JDK-8216049 : stringTable::intern creates redundant String when looking up existing one
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 11,12
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2019-01-03
  • Updated: 2019-09-09
  • Resolved: 2019-02-16
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 JDK 12 JDK 13
11.0.3Fixed 12.0.2Fixed 13 b09Fixed
Related Reports
Relates :  
Relates :  
Description
After JDK-8195097 in stringTable::intern the pre-insert lookup is done using a new String oop rather than the jchar* + len, which adds overhead in places like java_lang_StackTraceElement::fill_in - see https://stackoverflow.com/a/54015664/2397895

The following naive patch speeds up microbenchmarks throwing and consuming stack traces by 1.33x on my machine:

diff -r d3e199e30cfb src/hotspot/share/classfile/stringTable.cpp
--- a/src/hotspot/share/classfile/stringTable.cpp	Thu Jan 03 02:26:42 2019 +0100
+++ b/src/hotspot/share/classfile/stringTable.cpp	Thu Jan 03 10:29:24 2019 +0100
@@ -334,6 +334,10 @@
   if (StringTable::_alt_hash) {
     hash = hash_string(name, len, true);
   }
+  found_string = StringTable::the_table()->do_lookup(name, len, hash);
+  if (found_string != NULL) {
+    return found_string;
+  }
   return StringTable::the_table()->do_intern(string_or_null_h, name, len,
                                              hash, CHECK_NULL);
 }

Comments
Fix Request Backporting this patch resolves the performance regression introduced in 11, as demonstrated by the performance tests above. Patch applies cleanly to 11u and 12u, and passes tier1 tests. The risk is low, because patch is simple, non-intrusive, and does what pre-11 JDKs used to do.
20-02-2019

Post-integration testing on other platforms shows this fix is need to recuperate from 8 -> 11 regression. x86_32: # 8u181 StackTraceBench.test 1 avgt 5 88.887 �� 3.273 us/op StackTraceBench.test 10 avgt 5 122.042 �� 3.338 us/op StackTraceBench.test 100 avgt 5 475.721 �� 5.700 us/op StackTraceBench.test 1000 avgt 5 4071.670 �� 156.898 us/op # jdk/jdk StackTraceBench.test 1 avgt 5 121.319 �� 1.807 us/op StackTraceBench.test 10 avgt 5 159.781 �� 4.162 us/op StackTraceBench.test 100 avgt 5 450.427 �� 40.854 us/op StackTraceBench.test 1000 avgt 5 3478.950 �� 358.002 us/op # jdk/jdk + JDK-8216049 StackTraceBench.test 1 avgt 5 75.581 �� 1.542 us/op StackTraceBench.test 10 avgt 5 97.783 �� 4.902 us/op StackTraceBench.test 100 avgt 5 287.913 �� 12.209 us/op StackTraceBench.test 1000 avgt 5 2187.656 �� 161.485 us/op AArch64: Benchmark (depth) Mode Cnt Score Error Units # 8u151 StackTraceBench.test 1 avgt 5 216.302 �� 1.277 us/op StackTraceBench.test 10 avgt 5 273.065 �� 1.753 us/op StackTraceBench.test 100 avgt 5 839.889 �� 5.672 us/op StackTraceBench.test 1000 avgt 5 6793.779 �� 146.191 us/op # jdk/jdk StackTraceBench.test 1 avgt 5 165.792 �� 0.700 us/op StackTraceBench.test 10 avgt 5 234.875 �� 0.792 us/op StackTraceBench.test 100 avgt 5 946.452 �� 3.029 us/op StackTraceBench.test 1000 avgt 5 8224.362 �� 23.767 us/op # jdk/jdk + JDK-8216049 StackTraceBench.test 1 avgt 5 124.672 �� 3.165 us/op StackTraceBench.test 10 avgt 5 161.022 �� 0.945 us/op StackTraceBench.test 100 avgt 5 524.245 �� 1.864 us/op StackTraceBench.test 1000 avgt 5 4109.673 �� 27.176 us/op
19-02-2019

RFR: https://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2019-February/032645.html
15-02-2019

Any unexpected blockers for this issue? If time is a problem, I can invest some time in it too.
12-02-2019

JDK-8151751 is finished, and this fix would be a nice addition on top. I shall look into backporting JDK-8151751 fixes to 12 and 11, please consider doing the same for this one!
15-01-2019

I am seeing a very substantial improvement even after JDK-8216302 (well, especially after it?), using the test from JDK-8151751: Benchmark (depth) Mode Cnt Score Error Units # baseline StackTraceBench.test 1 avgt 15 15.094 �� 0.056 us/op StackTraceBench.test 10 avgt 15 21.053 �� 0.070 us/op StackTraceBench.test 100 avgt 15 80.455 �� 0.511 us/op StackTraceBench.test 1000 avgt 15 673.652 �� 4.299 us/op # patched StackTraceBench.test 1 avgt 15 9.835 �� 0.105 us/op StackTraceBench.test 10 avgt 15 13.088 �� 0.113 us/op StackTraceBench.test 100 avgt 15 45.608 �� 0.298 us/op StackTraceBench.test 1000 avgt 15 373.225 �� 6.225 us/op
10-01-2019

The specific case of StackTrace::fill_in where this would manifest has likely been handled by JDK-8216302, and I'm not sure how to write a micro that triggers the create_from_unicode branch in do_intern without that defect. Still, with my naive patch in the bug description above I see a 1.1-1.2x speedup in the below microbenchmark. Smaller speedup, but still noticeable. Apply the following patch to jdk/jdk to add a trivial microbenchmark to org.openjdk.bench.java.lang.StringOther: diff -r c0a3821ee5cf test/micro/org/openjdk/bench/java/lang/StringOther.java --- a/test/micro/org/openjdk/bench/java/lang/StringOther.java Wed Jan 09 18:34:55 2019 +0100 +++ b/test/micro/org/openjdk/bench/java/lang/StringOther.java Wed Jan 09 21:44:11 2019 +0100 @@ -85,4 +85,12 @@ return String.valueOf(rnd.nextInt()).intern(); } + /** + * Benchmarks the speed at which the VM can take an already interned string and attempt to intern it again. + */ + @Benchmark + public boolean internRepeat() { + return str1.intern() == str1.intern() && str4.intern() == str4.intern(); + } + } make build-microbenchmark (should work if you've configured with jib, otherwise refer to test documentation on how to configure with --with-jmh) java -jar build/$YOUR_PLATFORM/images/test/micro/benchmarks.jar StringOther.internRepeat -f 1 -wi 5 -i 5 -w 2 -r 2 -jvmArgs="-Xshare:off"
09-01-2019

[~redestad] Can you please post me to the benchmark, and tell me if there is anything special I need to do to run it myself?
09-01-2019