openj9 icon indicating copy to clipboard operation
openj9 copied to clipboard

Regression: Unicode Smiley text measuring extremely slow in 25.0.1

Open patric42 opened this issue 1 month ago • 4 comments

Calling TextMeasurer::getLayout on "😊🙂😀"

in 21: SmileyRegression.breakSmilies avgt 3 0,006 ± 0,001 ms/op in 25: SmileyRegression.breakSmilies avgt 3 1,116 ± 3,488 ms/op

The performance in 21 is almost identical to Temurin's.

This hurts really hard, as this call is done usually directly on the EDT, so your UI is going to freeze to halt.

Following is the code to reproduce: (I used jbang to ease running the benchmark):

SmileyRegression.java :

///usr/bin/env jbang "$0" "$@" ; exit
//DEPS org.openjdk.jmh:jmh-core:1.19 org.openjdk.jmh:jmh-generator-annprocess:1.19
//COMPILE_OPTIONS -processor org.openjdk.jmh.generators.BenchmarkProcessor
package smiley;

// benchmark imports
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.RunnerException;
import java.util.concurrent.TimeUnit;
import java.io.IOException;

// actual imports
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.font.TextMeasurer;
import java.awt.geom.Rectangle2D;
import java.text.AttributedString;

// configure jmh
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 3)
@Measurement(iterations = 3)
@Fork(value = 1, warmups = 1)
public class SmileyRegression {

   String rawText = "\uD83D\uDE0A\uD83D\uDE42\uD83D\uDE00";
   AttributedString smiles = new AttributedString(rawText);
   FontRenderContext frc = new FontRenderContext(null, true, false);

   @Benchmark
   public void breakSmilies() {
      TextMeasurer tm = new TextMeasurer(smiles.getIterator(), frc);
      TextLayout tl = tm.getLayout(0, rawText.length());
      if (tl.getBounds().getWidth() < 0) throw new IllegalStateException();
   }
   
   public static void main(String[] args) throws IOException, RunnerException {
      org.openjdk.jmh.Main.main(args);
   }
}

jbang --verbose SmileyRegression.java

patric42 avatar Dec 01 '25 16:12 patric42

I got the following results on xlinux.

Benchmark                      Mode  Cnt  Score   Error  Units
SmileyRegression.breakSmilies  avgt    3  0.007 ± 0.002  ms/op Semeru 21.0.9
SmileyRegression.breakSmilies  avgt    3  0.364 ± 0.769  ms/op Semeru 25.0.1
SmileyRegression.breakSmilies  avgt    3  0.004 ±  0.001  ms/op Temurin 25.0.1

pshipton avatar Dec 01 '25 18:12 pshipton

@hzongaro @vijaysun-omr fyi

pshipton avatar Dec 01 '25 18:12 pshipton

@0xdaryl

0xdaryl avatar Dec 01 '25 18:12 0xdaryl

The performance difference is observed between Semeru JDK 21.0.9 and JDK 25.0.1 (both from the Semeru downloads page that use the 0.56 OpenJ9 release).

However, the performance is significantly improved with the latest JDK 25 build from master (Dec 3).

Benchmark                      Mode  Cnt  Score   Error  Units
SmileyRegression.breakSmilies  avgt    3  0.024 ± 0.021  ms/op  Semeru JDK 21.0.9 (0.56 OpenJ9 release)
SmileyRegression.breakSmilies  avgt    3  0.025 ± 0.039  ms/op  Semeru JDK 21.0.10 (master, Dec 3)

SmileyRegression.breakSmilies  avgt    3  0.554 ± 2.031  ms/op  Semeru JDK 25.0.1 (0.56 OpenJ9 release)
SmileyRegression.breakSmilies  avgt    3  0.055 ± 0.054  ms/op  Semeru JDK 25.0.1 (master, Dec 3)

SmileyRegression.breakSmilies  avgt    3  0.019 ± 0.050  ms/op  Temurin JDK 25.0.1

I'm pretty sure I know why it improved, but I would like to look into it deeper to confirm before commenting. There is still a performance gap with JDK 21 and Temurin to look into, suggesting some other performance opportunities to find.

0xdaryl avatar Dec 04 '25 03:12 0xdaryl