Skip to content

Instantly share code, notes, and snippets.

@eirikbakke
Created June 7, 2019 02:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eirikbakke/6519b3e623c0f4703ee82388d1587f08 to your computer and use it in GitHub Desktop.
Save eirikbakke/6519b3e623c0f4703ee82388d1587f08 to your computer and use it in GitHub Desktop.
SVG vs. PNG loading benchmark
import com.google.common.collect.ImmutableSet;
import com.google.common.math.StatsAccumulator;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Set;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.Icon;
import javax.swing.ImageIcon;
// Note: Before running this benchmark, be sure to disable Intel SpeedStep in the BIOS.
public class SVGBenchmark {
private static final Set<String> ICON_NAMES = ImmutableSet.of(
"warning", "arrow_down", "arrow_up", "cursoredit_data", "cursoredit_formula",
"cursoredit_label", "cursoredit_none", "database", "field_collapsed_join",
"field_new_primitive_data", "field_new_primitive_formula", "field_new_relation",
"field_primitive_data", "field_primitive_formula", "field_relation_noinst", "field_relation",
"fields_relation_only", "filter_range", "folder_closed", "folder_open", "general_minus",
"general_plus", "project_perspective", "project_table", "project_logo", "toolbar_edit",
"toolbar_redo", "toolbar_refresh", "toolbar_stop", "toolbar_undo", "toolbar_zoom_in",
"toolbar_zoom_original", "toolbar_zoom_out");
private static final ImageReader PNG_READER;
static {
ImageIO.setUseCache(false);
PNG_READER = ImageIO.getImageReadersByMIMEType("image/png").next();
}
private static URL getResourceURL(String iconName, boolean svg) {
String path = "com/somepackage/project/icons/" + iconName + "." + (svg ? "svg" : "png");
URL ret = SVGBenchmark.class.getClassLoader().getResource(path);
if (ret == null)
throw new RuntimeException("Resource not found");
return ret;
}
private static void loadAndPaintOneIcon(String iconName, boolean svg) {
final URL url = getResourceURL(iconName, svg);
final Icon icon;
if (svg) {
try {
icon = SVGIcon.load(url);
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
Image image;
// Load in the same way as ImageUtilities opens PNG files.
try (ImageInputStream stream = ImageIO.createImageInputStream(url.openStream())) {
ImageReadParam param = PNG_READER.getDefaultReadParam();
PNG_READER.setInput(stream, true, true);
image = PNG_READER.read(0, param);
} catch (IOException e) {
throw new RuntimeException(e);
}
icon = new ImageIcon(image);
}
BufferedImage img = new BufferedImage(
icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g = img.createGraphics();
// Assume the Component parameter isn't used by the underlying implementation.
icon.paintIcon(null, g, 0, 0);
g.dispose();
}
private static void measureOneSample(StatsAccumulator svgStats, StatsAccumulator pngStats) {
boolean order[] = Math.random() < 0.5
? new boolean[] {false, true}
: new boolean[] {true, false};
//boolean order[] = new boolean[] {true};
for (boolean svg : order) {
long bef = System.nanoTime();
for (String iconName : ICON_NAMES)
loadAndPaintOneIcon(iconName, svg);
long aft = System.nanoTime();
(svg ? svgStats : pngStats).add(aft - bef);
}
}
private static void printStats(StatsAccumulator stats, boolean svg) {
double mean = (stats.count() == 0) ? Double.NaN : stats.mean();
double standardError = stats.count() < 2 ? Double.NaN :
(stats.sampleStandardDeviation() / Math.sqrt(stats.count()));
double standardErrorPercentage = 100 * (standardError / mean);
double meanPerIcon = mean / ICON_NAMES.size();
System.out.printf("Loading and painting %s took %.2f microseconds per icon +/- %.02f%%\n",
svg ? "SVG" : "PNG", (meanPerIcon / 1000.0), standardErrorPercentage);
}
private static void measure() {
StatsAccumulator svgStats = new StatsAccumulator();
StatsAccumulator pngStats = new StatsAccumulator();
// Warmup.
for (int i = 0; i < 300; i++)
measureOneSample(svgStats, pngStats);
// Throw away the warmup stats and start fresh.
svgStats = new StatsAccumulator();
pngStats = new StatsAccumulator();
// Now do the actual measurements.
for (int i = 0; i < 500; i++)
measureOneSample(svgStats, pngStats);
printStats(svgStats, true);
printStats(pngStats, false);
}
private static final void printFileSizeStats(boolean svg) {
StatsAccumulator sizeStats = new StatsAccumulator();
for (String iconName : ICON_NAMES) {
URL url = getResourceURL(iconName, svg);
try (InputStream is = url.openStream()) {
sizeStats.add(is.readAllBytes().length);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
System.out.println("Average size of " + (svg ? "SVG" : "PNG") + " icon file is " +
Math.round(sizeStats.mean()) + " bytes (max was " + (int) sizeStats.max() + " bytes)");
}
public static final void main(String args[]) {
printFileSizeStats(true);
printFileSizeStats(false);
measure();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment