I am running Windows x64. Windows 11 Pro 24H2

Intel(R) Core(TM) i7-1370P

On Mon, Jul 21, 2025 at 4:59 PM Chen Liang <chen.l.li...@oracle.com> wrote:

> I finally came around and ran the benchmark on my linux-x64 device;
> however, I could not produce your results where String is significantly
> slower than StringBuilder.
>
> This is the results I've got:
>
> Benchmark                                         (data)  Mode  Cnt
>  Score    Error  Units
> CharSequenceCharAtBenchmark.testString             ascii  avgt    5
>  668.649 ± 13.895  ns/op
> CharSequenceCharAtBenchmark.testString         non-ascii  avgt    5
>  651.903 ±  7.240  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder      ascii  avgt    5
>  673.802 ± 26.260  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder  non-ascii  avgt    5
>  657.374 ± 35.785  ns/op
>
> I think we might have more clue - are you testing on a macosx-aarch64
> machine or some other platform? It might be that on some platforms, there
> are some problems in the hand-written assemblies for the intrinsics which
> contribute to this slowdown, instead of a problem with the C2 IR.
>
> Chen
> ------------------------------
> *From:* core-libs-dev <core-libs-dev-r...@openjdk.org> on behalf of Brett
> Okken <brett.okken...@gmail.com>
> *Sent:* Monday, July 21, 2025 4:01 PM
> *To:* Roger Riggs <roger.ri...@oracle.com>
> *Cc:* core-libs-dev@openjdk.org <core-libs-dev@openjdk.org>
> *Subject:* Re: String.charAt vs StringBuilder.charAt performance
>
> Updating to have different test methods for each representation did remove
> the difference for the non-ascii String case for the jdk 21+ releases.
> However, the ascii (latin) strings are still slower with String than
> StringBuilder.
>
> How does C2 then handle something like StringCharBuffer wrapping a
> CharSequence for all of it's get operations:
>
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/nio/StringCharBuffer.java#L88-L97
>
> Which is then used by CharBufferSpliterator
>
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/nio/CharBufferSpliterator.java
>
> And by many CharsetEncoder impls when either source or destination is not
> backed by array (which would be the case if StringCharBuffer used):
>
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/nio/cs/UTF_8.java#L517
>
> https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/nio/cs/UnicodeEncoder.java#L81
>
>
>
> jdk 17
> Benchmark                                         (data)  Mode  Cnt
> Score     Error  Units
> CharSequenceCharAtBenchmark.testString             ascii  avgt    3
>  1429.358 ± 623.424  ns/op
> CharSequenceCharAtBenchmark.testString         non-ascii  avgt    3
> 705.282 ± 233.453  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder      ascii  avgt    3
> 724.138 ± 267.346  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder  non-ascii  avgt    3
> 718.357 ± 864.066  ns/op
>
> jdk 21
> Benchmark                                         (data)  Mode  Cnt
> Score     Error  Units
> CharSequenceCharAtBenchmark.testString             ascii  avgt    3
>  1087.024 ┬▒ 235.082  ns/op
> CharSequenceCharAtBenchmark.testString         non-ascii  avgt    3
> 687.520 ┬▒ 747.532  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder      ascii  avgt    3
> 672.802 ┬▒  29.740  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder  non-ascii  avgt    3
> 689.964 ┬▒ 791.175  ns/op
>
> jdk 25
> Benchmark                                         (data)  Mode  Cnt
> Score      Error  Units
> CharSequenceCharAtBenchmark.testString             ascii  avgt    3
>  1176.057 ┬▒ 1157.979  ns/op
> CharSequenceCharAtBenchmark.testString         non-ascii  avgt    3
> 697.382 ┬▒  231.144  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder      ascii  avgt    3
> 692.970 ┬▒  105.112  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder  non-ascii  avgt    3
> 703.178 ┬▒  446.019  ns/op
>
> jdk 26
> Benchmark                                         (data)  Mode  Cnt
> Score     Error  Units
> CharSequenceCharAtBenchmark.testString             ascii  avgt    3
>  1132.971 ┬▒ 350.786  ns/op
> CharSequenceCharAtBenchmark.testString         non-ascii  avgt    3
> 688.201 ┬▒ 175.797  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder      ascii  avgt    3
> 704.380 ┬▒ 101.763  ns/op
> CharSequenceCharAtBenchmark.testStringBuilder  non-ascii  avgt    3
> 673.622 ┬▒  51.462  ns/op
>
>
> @Warmup(iterations = 2, time = 7, timeUnit = TimeUnit.SECONDS)
> @BenchmarkMode(Mode.AverageTime)
> @OutputTimeUnit(TimeUnit.NANOSECONDS)
> @State(Scope.Benchmark)
> @Fork(value = 1, jvmArgsPrepend = {"-Xms512M", "-Xmx512M"})
> public class CharSequenceCharAtBenchmark {
>
>     @Param(value = {"ascii", "non-ascii"})
>     public String data;
>
>     private String string;
>
>     private StringBuilder stringBuilder;
>
>     @Setup(Level.Trial)
>     public void setup() throws Exception {
>         StringBuilder sb = new StringBuilder(3152);
>         for (int i=0; i<3152; ++i) {
>             char c = (char) i;
>             if ("ascii".equals(data)) {
>                 c = (char) (i & 0x7f);
>             }
>             sb.append(c);
>         }
>
>         string = sb.toString();
>         stringBuilder = sb;
>     }
>
>     @Benchmark
>     public int testString() {
>         String sequence = this.string;
>         int sum = 0;
>         for (int i=0, j=sequence.length(); i<j; ++i) {
>             sum += sequence.charAt(i);
>         }
>         return sum;
>     }
>
>     @Benchmark
>     public int testStringBuilder() {
>         StringBuilder sequence = this.stringBuilder;
>         int sum = 0;
>         for (int i=0, j=sequence.length(); i<j; ++i) {
>             sum += sequence.charAt(i);
>         }
>         return sum;
>     }
> }
>
>

Reply via email to