/*
* $Id$
*
* Copyright 2011 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.io.nio;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import loci.common.services.ServiceFactory;
import loci.formats.codec.JPEG2000CodecOptions;
import loci.formats.services.JAIIIOService;
import ome.conditions.MissingPyramidException;
import ome.model.core.Pixels;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.perf4j.StopWatch;
import org.perf4j.slf4j.Slf4JStopWatch;
/**
* Basic {@link BackOff} implementation which attempts several writes of the
* default block size on startup, and uses that as a scaling factor for all
* subsequent calculations.
*
* @author Josh Moore, josh at glencoesoftware.com
* @since Beta4.3.1
* @see <a href="https://trac.openmicroscopy.org/ome/ticket/5910">ticket 5910</a>
*/
public class SimpleBackOff implements BackOff {
private static final int[] CODE_BLOCK = new int[] { 4, 4 };
private static final int IMAGE_TYPE = BufferedImage.TYPE_INT_ARGB;
private final static Logger log = LoggerFactory.getLogger(SimpleBackOff.class);
private final JAIIIOService service;
protected final double scalingFactor;
protected final double warmUpFactor;
protected final int count;
protected final TileSizes sizes;
public SimpleBackOff() {
this(new ConfiguredTileSizes());
}
public SimpleBackOff(TileSizes sizes) {
this.sizes = sizes;
this.count = 10;
try {
ServiceFactory sf = new ServiceFactory();
service = sf.getInstance(JAIIIOService.class);
warmUpFactor = calculate(); // WARM-UP
scalingFactor = calculate();
} catch (Exception e) {
log.error("Failed to create simpleBackOff", e);
throw new RuntimeException(e);
}
}
public int getCount() {
return count;
}
public double getScalingFactor() {
return scalingFactor;
}
public double getWarmUpFactor() {
return warmUpFactor;
}
public void throwMissingPyramidException(String msg, Pixels pixels) {
throw new MissingPyramidException(msg, calculate(pixels),
pixels.getId());
}
protected long calculate(Pixels pixels) {
return (long) (scalingFactor * countTiles(pixels));
}
protected int countTiles(Pixels pixels) {
final int[] count = new int[] { 0 };
ome.io.nio.Utils.forEachTile(new TileLoopIteration() {
public void run(int z, int c, int t, int x, int y, int tileWidth,
int tileHeight, int tileCount) {
count[0]++;
}
}, pixels.getSizeX(), pixels.getSizeY(), pixels.getSizeZ(),
pixels.getSizeC(), pixels.getSizeT(),
sizes.getTileWidth(), sizes.getTileHeight());
return count[0];
}
protected double calculate() throws Exception {
final String key = String.format("%s.%sX%s", getClass().getName(),
sizes.getTileWidth(), sizes.getTileHeight());
StopWatch sw;
BufferedImage image;
ByteArrayOutputStream stream;
long elapsed = 0;
for (int i = 0; i < count; i++) {
sw = new Slf4JStopWatch(key);
JPEG2000CodecOptions options = JPEG2000CodecOptions.getDefaultOptions();
options.lossless = false;
options.codeBlockSize = CODE_BLOCK;
options.quality = 1.0f;
image = new BufferedImage(sizes.getTileWidth(), sizes.getTileHeight(), IMAGE_TYPE);
stream = new ByteArrayOutputStream();
service.writeImage(stream, image, options);
sw.stop();
elapsed += sw.getElapsedTime();
}
return ((double) elapsed) / count;
}
@Override
public String toString() {
return String.format("%s(factor=%s)",
getClass().getName(), scalingFactor);
}
}