JDK-8196666 : Significant performance regression in "Font.layoutGlyphVector()"
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 9.0.4,10
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: other
  • CPU: x86
  • Submitted: 2018-01-26
  • Updated: 2018-02-12
  • Resolved: 2018-02-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11
11Resolved
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "9.0.4" Java(TM)   SE Runtime Environment (build 9.0.4+11)   Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)   [same in 9.0.1]

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.16299.192]   (also reproducible on Mac and Linux, but less pronounced)

EXTRA RELEVANT SYSTEM CONFIGURATION :
None (reproducible on different OSs and types of hardware)

A DESCRIPTION OF THE PROBLEM :
For most (not all) fonts java.awt.Font.layoutGlyphVector() has become significantly slower in Java 9 (compared to Java 8), up to a factor of 20.
After some quick profiling and looking through source code the apparent main cause is additional disc I/O,
i.e. Java 9 reads from actual font file for every call to "layoutGlyphVector" while Java 8 does not.
It seems that unlike previous versions Java 9 no longer caches all required data from TTF/OTF tables and instead rereads it every time (maybe due to more tables being used now and still only caching the old subset).
As there are a few fonts that are faster on Java 9, solving this issue could result not only in equal, but even better performance in Java 9,
which (especially when combined with the visual improvements in Java 9) could make GlyphVectors a viable component for performance sensitive text layout engines.

REGRESSION.  Last worked in version 8u162

ADDITIONAL REGRESSION INFORMATION: 
java version "1.8.0_162"   Java(TM) SE Runtime Environment (build 1.8.0_162-b12)   Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)   [same in previous Java 8 and similar in Java 7]

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the source code below, ideally using "arial" and "arial unicode ms". For these Java 9 should be about 5 and 15-20 (fifteen to twenty) times slower, respectively, than Java 8.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Java 9 should not be significantly slower. (As some fonts are faster it could even be generally faster when caching is fixed (if that is the cause))
ACTUAL -
Java 9 is significantly slower for most fonts.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
None (performance issue)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.io.File;
import java.util.Collections;
public class GVT {
    //Adapt FONT_DIRECTORY for other OSs or specific folders with a selected sets of fonts ("Arial" and "Arial Unicode MS" highly recommended)
    private static final String FONT_DIRECTORY = "c:\\windows\\fonts\\"; 
    private static final int REPETITIONS = 5_000;
    private static final char[] TEXT = "X sosofts 0,0 Steffieie Y".toCharArray();
    private static final FontRenderContext FRC = new FontRenderContext(null, true, true);
    
    public static void main(String[] args) throws Throwable {
        System.out.println("Java " + System.getProperty("java.version") + " on " + System.getProperty("os.name") + "\n");
        for (File fontFile : new File(FONT_DIRECTORY).listFiles()) {
            if (fontFile.toString().toLowerCase().endsWith(".ttf")) {
                Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(123f)
                        .deriveFont(Collections.singletonMap(TextAttribute.KERNING, TextAttribute.KERNING_ON))
                        .deriveFont(Collections.singletonMap(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON));
                System.out.print(fontFile.toString() + ";" + font.getName() + ";");
                long start = System.nanoTime();
                for (int i = 0; i < REPETITIONS; i++) {
                    font.layoutGlyphVector(FRC, TEXT, 0, TEXT.length, 0);
                }
                System.out.println((System.nanoTime() - start) / REPETITIONS / 1000);
            }
        }
    }
}
---------- END SOURCE ----------


Comments
This is a duplicate of JDK-8186317: Cache font layout tables for use by harfbuzz. Fixed in JDK 10.
12-02-2018

Reported with: JDK 9.0.4 Windows 10 Generic issue Significant performance regression in "Font.layoutGlyphVector()" with JDk 9.0.4 when compared to JDK 8u. Checked with: JDK 8u161, 9.0.4 and 10 ea b41 Windows 10 To verify, run the attached test case. It took more then double the time with JDk 9 and 10 when compared to JDk 8u to populate the fonts. Results: ======== 8u161: 1:30 sec 9.0.4: 3:20 sec 10 ea b41: 2:50 sec ======== This seems a performance regression with JDK 9.0.4 and 10. JDK 9 reads from actual font file for every call to "layoutGlyphVector" while JDK 8u does not.
02-02-2018