René Schwietzke noticed an interesting behavior in how non-fluid pattern for StringBuilder is slower than using a fluid one.
The simplest reproducer is:
```
@Warmup(iterations = 3, time = 300, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 3, time = 300, timeUnit = TimeUnit.MILLISECONDS)
@Fork(value = 1, jvmArgsAppend = {"-XX:+UseParallelGC", "-Xmx1g", "-Xms1g"})
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class FluidSBBench {
static final String PREFIX = "a";
String foo = "aaaaa aaaaa aaaaa aaaaa aaaaa";
@Benchmark
public String fluid() {
return new StringBuilder().append(PREFIX).append(foo).toString();
}
@Benchmark
public String nonFluid() {
final StringBuilder sb = new StringBuilder();
sb.append(PREFIX);
sb.append(foo);
return sb.toString();
}
}
```
This yields:
```
Benchmark Mode Cnt Score Error Units
FluidSBBench.fluid avgt 3 5.788 ± 0.526 ns/op
FluidSBBench.fluid:gc.alloc.rate.norm avgt 3 72.000 ± 0.001 B/op
FluidSBBench.nonFluid avgt 3 19.159 ± 0.625 ns/op
FluidSBBench.nonFluid:gc.alloc.rate.norm avgt 3 160.000 ± 0.001 B/op
```
`-XX:+PrintOptimizeStringConcat` says this for nonFluid case:
```
considering toString call in FluidSBBench::nonFluid @ bci:25 (line 58) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
fusion would fail for
90 Allocate === 60 6 85 8 1 (88 87 51 1 1 10 49 1 1 1 15 1 1 67 29 1 29 1 15 67 1 ) [[ 91 92 93 100 101 102 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, top, bool ) FluidSBBench::nonFluid @ bci:0 (line 55) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:0 (line 55) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
164 CatchProj === 163 [[ 174 ]] #0@bci -1 !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
163 Catch === 157 158 [[ 164 165 ]] !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
157 Proj === 156 [[ 163 ]] #0 !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
156 CallStaticJava === 142 147 148 8 1 (107 155 10 49 1 1 1 15 1 1 67 29 1 29 1 15 1 107 ) [[ 157 158 159 170 169 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):exact * ( java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact *, java/lang/String (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):exact * ) FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
142 CatchProj === 141 [[ 156 ]] #0@bci -1 !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
141 Catch === 135 136 [[ 142 143 ]] !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
135 Proj === 134 [[ 141 ]] #0 !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
134 CallStaticJava === 117 122 123 8 1 (107 133 10 49 1 1 1 15 1 1 67 29 1 29 1 15 67 107 ) [[ 135 136 137 148 147 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):exact * ( java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact *, java/lang/String (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):exact * ) FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
```
The simplest reproducer is:
```
@Warmup(iterations = 3, time = 300, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 3, time = 300, timeUnit = TimeUnit.MILLISECONDS)
@Fork(value = 1, jvmArgsAppend = {"-XX:+UseParallelGC", "-Xmx1g", "-Xms1g"})
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class FluidSBBench {
static final String PREFIX = "a";
String foo = "aaaaa aaaaa aaaaa aaaaa aaaaa";
@Benchmark
public String fluid() {
return new StringBuilder().append(PREFIX).append(foo).toString();
}
@Benchmark
public String nonFluid() {
final StringBuilder sb = new StringBuilder();
sb.append(PREFIX);
sb.append(foo);
return sb.toString();
}
}
```
This yields:
```
Benchmark Mode Cnt Score Error Units
FluidSBBench.fluid avgt 3 5.788 ± 0.526 ns/op
FluidSBBench.fluid:gc.alloc.rate.norm avgt 3 72.000 ± 0.001 B/op
FluidSBBench.nonFluid avgt 3 19.159 ± 0.625 ns/op
FluidSBBench.nonFluid:gc.alloc.rate.norm avgt 3 160.000 ± 0.001 B/op
```
`-XX:+PrintOptimizeStringConcat` says this for nonFluid case:
```
considering toString call in FluidSBBench::nonFluid @ bci:25 (line 58) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
fusion would fail for
90 Allocate === 60 6 85 8 1 (88 87 51 1 1 10 49 1 1 1 15 1 1 67 29 1 29 1 15 67 1 ) [[ 91 92 93 100 101 102 ]] rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, top, bool ) FluidSBBench::nonFluid @ bci:0 (line 55) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:0 (line 55) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
164 CatchProj === 163 [[ 174 ]] #0@bci -1 !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
163 Catch === 157 158 [[ 164 165 ]] !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
157 Proj === 156 [[ 163 ]] #0 !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
156 CallStaticJava === 142 147 148 8 1 (107 155 10 49 1 1 1 15 1 1 67 29 1 29 1 15 1 107 ) [[ 157 158 159 170 169 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):exact * ( java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact *, java/lang/String (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):exact * ) FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:20 (line 57) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
142 CatchProj === 141 [[ 156 ]] #0@bci -1 !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
141 Catch === 135 136 [[ 142 143 ]] !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
135 Proj === 134 [[ 141 ]] #0 !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
134 CallStaticJava === 117 122 123 8 1 (107 133 10 49 1 1 1 15 1 1 67 29 1 29 1 15 67 107 ) [[ 135 136 137 148 147 ]] # Static java.lang.StringBuilder::append java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):exact * ( java/lang/StringBuilder (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact *, java/lang/String (java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/constant/Constable,java/lang/constant/ConstantDesc):exact * ) FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190) !jvms: FluidSBBench::nonFluid @ bci:11 (line 56) FluidSBBench_nonFluid_jmhTest::nonFluid_avgt_jmhStub @ bci:17 (line 190)
```
- is cloned by
-
JDK-8348969 [REDO] C2: Non-fluid StringBuilder pattern bails out in OptoStringConcat
- Open
- relates to
-
JDK-8348687 [BACKOUT] C2: Non-fluid StringBuilder pattern bails out in OptoStringConcat
- Resolved
-
JDK-8348622 Test AuctionItemRepository.java fails run with TEST_THREAD_FACTORY=Virtual and -Xcomp
- Open
- links to
-
Commit(master) openjdk/jdk/6032f6ea
-
Review(master) openjdk/jdk/22537