Skip to content

Instantly share code, notes, and snippets.

@eirikbakke
Created September 8, 2018 19:53
Show Gist options
  • Save eirikbakke/81eec72221c9d7d8fc0b4afa9c54a163 to your computer and use it in GitHub Desktop.
Save eirikbakke/81eec72221c9d7d8fc0b4afa9c54a163 to your computer and use it in GitHub Desktop.
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
/**
* Measure the performance on both LineBreakMeasurer and Font.layoutGlyphVector for short strings.
* An order-of-magnitude performance regression was observed for both when switching from
* Java 1.8.0_172 to Java 10.0.2 (presumably related to adoption of the new HarfBuzz font engine).
*/
public final class FontLayoutPerfTest {
private static final int MEASURED_ITERATIONS = 6000;
private final Font font = new Font("Arial", Font.PLAIN, 12);
private final FontRenderContext frc = new FontRenderContext(new AffineTransform(), true, false);
private int counter = 0;
private void runOneIteration(boolean useLineBreakMeasurer) {
// For testing purposes, make sure each string is different, but always 7 characters wide.
String s = String.format("%07d", counter++);
if (useLineBreakMeasurer) {
AttributedString as = new AttributedString(s);
AttributedCharacterIterator aci = as.getIterator();
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
TextLayout line = lbm.nextLayout(Float.POSITIVE_INFINITY);
if (line == null)
throw new AssertionError();
} else {
font.layoutGlyphVector(frc, s.toCharArray(), 0, s.length(), 0);
}
}
public void runTest(boolean useLineBreakMeasurer) {
// Warm-up first.
for (int i = 0; i < MEASURED_ITERATIONS / 4; i++)
runOneIteration(useLineBreakMeasurer);
long startTime = System.nanoTime();
for (int i = 0; i < MEASURED_ITERATIONS; i++)
runOneIteration(useLineBreakMeasurer);
long endTime = System.nanoTime();
double nanosPerLayout = (endTime - startTime) / (double) MEASURED_ITERATIONS;
String method = useLineBreakMeasurer ? "LineBreakMeasurer" : "layoutGlyphVector";
System.out.printf("%s took %.2f microseconds per layout (%d iterations)\n",
new Object[] { method, nanosPerLayout / 1000.0, MEASURED_ITERATIONS });
}
public static final void main(String args[]) {
FontLayoutPerfTest tester = new FontLayoutPerfTest();
System.out.println("Java " + System.getProperty("java.version") +
" on " + System.getProperty("os.name"));
tester.runTest(false);
tester.runTest(true);
}
}
/* Some outputs gathered from this test on a ThinkPad X1 Carbon 6th Gen laptop:
Java 1.8.0_172 on Windows 10
layoutGlyphVector took 45.59 microseconds per layout (300 iterations)
LineBreakMeasurer took 132.51 microseconds per layout (300 iterations)
Java 10.0.2 on Windows 10
layoutGlyphVector took 433.80 microseconds per layout (300 iterations)
LineBreakMeasurer took 892.86 microseconds per layout (300 iterations)
Java 1.8.0_172 on Windows 10
layoutGlyphVector took 10.32 microseconds per layout (6000 iterations)
LineBreakMeasurer took 33.84 microseconds per layout (6000 iterations)
Java 10.0.2 on Windows 10
layoutGlyphVector took 404.16 microseconds per layout (6000 iterations)
LineBreakMeasurer took 785.34 microseconds per layout (6000 iterations)
Java 1.8.0_172 on Windows 10
layoutGlyphVector took 6.07 microseconds per layout (60000 iterations)
LineBreakMeasurer took 11.37 microseconds per layout (60000 iterations)
Java 10.0.2 on Windows 10
layoutGlyphVector took 394.30 microseconds per layout (60000 iterations)
LineBreakMeasurer took 800.26 microseconds per layout (60000 iterations)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment