<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">If you are using JMH, a read of this section may be helpful:<div><br></div><div><div style="display: block;"><div style="-webkit-user-select: all; -webkit-user-drag: element; display: inline-block;" class="apple-rich-link" draggable="true" role="link" data-url="https://jenkov.com/tutorials/java-performance/jmh.html#writing-good-benchmarks"><a style="border-radius:10px;font-family:-apple-system, Helvetica, Arial, sans-serif;display:block;-webkit-user-select:none;width:300px;user-select:none;-webkit-user-modify:read-only;user-modify:read-only;overflow:hidden;text-decoration:none;" class="lp-rich-link" rel="nofollow" href="https://jenkov.com/tutorials/java-performance/jmh.html#writing-good-benchmarks" dir="ltr" role="button" draggable="false" width="300"><table style="table-layout:fixed;border-collapse:collapse;width:300px;background-color:#BCBCBC;font-family:-apple-system, Helvetica, Arial, sans-serif;" class="lp-rich-link-emailBaseTable" cellpadding="0" cellspacing="0" border="0" width="300"><tbody><tr><td vertical-align="center" align="center"><img style="width:300px;filter:brightness(0.97);height:180px;" width="300" height="180" draggable="false" class="lp-rich-link-mediaImage" alt="java-performance-teaser-500-300.png" src="cid:4AA3D9D0-D652-40F8-B819-475CEA35C7F0"></td></tr><tr><td vertical-align="center"><table bgcolor="#BCBCBC" cellpadding="0" cellspacing="0" width="300" style="table-layout:fixed;font-family:-apple-system, Helvetica, Arial, sans-serif;background-color:rgba(188, 188, 188, 1);-apple-color-filter:initial;" class="lp-rich-link-captionBar"><tbody><tr><td style="padding:8px 0px 8px 0px;" class="lp-rich-link-captionBar-textStackItem"><div style="max-width:100%;margin:0px 16px 0px 16px;overflow:hidden;" class="lp-rich-link-captionBar-textStack"><div style="word-wrap:break-word;font-weight:500;font-size:12px;overflow:hidden;text-overflow:ellipsis;text-align:left;" class="lp-rich-link-captionBar-textStack-topCaption-leading"><a rel="nofollow" href="https://jenkov.com/tutorials/java-performance/jmh.html#writing-good-benchmarks" style="text-decoration: none" draggable="false"><font color="#FFFFFF" style="color: rgba(255, 255, 255, 0.847059);">JMH - Java Microbenchmark Harness</font></a></div><div style="word-wrap:break-word;font-weight:400;font-size:11px;overflow:hidden;text-overflow:ellipsis;text-align:left;" class="lp-rich-link-captionBar-textStack-bottomCaption-leading"><a rel="nofollow" href="https://jenkov.com/tutorials/java-performance/jmh.html#writing-good-benchmarks" style="text-decoration: none" draggable="false"><font color="#FFFFFF" style="color: rgba(255, 255, 255, 0.54902);">jenkov.com</font></a></div></div></td></tr></tbody></table></td></tr></tbody></table></a></div></div><br id="lineBreakAtBeginningOfMessage"><div><br><blockquote type="cite"><div>On Jun 24, 2025, at 11:54 AM, Johan Sjolen <johan.sjolen@oracle.com> wrote:</div><br class="Apple-interchange-newline"><div><div><br>One last benchmark for today: I added a benchmark that binds the MISSING ScopedValue at the end, so it's like the slow benchmark but we don't need to traverse anything to find the binding.<br>That turns out to be even faster:<br><br># Benchmark: org.openjdk.bench.java.lang.ScopedValues.ScopedValuesAreSlow2<br><br># Run progress: 15.79% complete, ETA 00:03:51<br># Fork: 1 of 1<br>WARNING: A terminally deprecated method in sun.misc.Unsafe has been called<br>WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/home/opc/views/master/build/linux-aarch64/images/test/micro/benchmarks.jar)<br>WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils<br>WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release<br># Warmup Iteration 1: 196769.758 ns/op<br># Warmup Iteration 2: 59395.092 ns/op<br># Warmup Iteration 3: 29831.474 ns/op<br># Warmup Iteration 4: 30670.259 ns/op<br>Iteration 1: 29522.851 ns/op<br>Iteration 2: 29220.998 ns/op<br>Iteration 3: 30017.858 ns/op<br>Iteration 4: 30409.883 ns/op<br>Iteration 5: 30392.041 ns/op<br>Iteration 6: 30876.052 ns/op<br>Iteration 7: 31950.619 ns/op<br>Iteration 8: 30711.009 ns/op<br>Iteration 9: 30412.429 ns/op<br>Iteration 10: 30890.572 ns/op<br><br><br>Result "org.openjdk.bench.java.lang.ScopedValues.ScopedValuesAreSlow2":<br> 30440.431 ±(99.9%) 1155.565 ns/op [Average]<br> (min, avg, max) = (29220.998, 30440.431, 31950.619), stdev = 764.335<br> CI (99.9%): [29284.866, 31595.997] (assumes normal distribution)<br><br>I'm logging off for today,<br>Cheers and thanks Robert and Aleksey for looking at this.<br><br>/ Johan<br><br>________________________________________<br>From: loom-dev <loom-dev-retn@openjdk.org> on behalf of Johan Sjolen <johan.sjolen@oracle.com><br>Sent: Tuesday, June 24, 2025 18:44<br>To: Aleksey Shipilev<br>Cc: loom-dev@openjdk.org<br>Subject: Re: ScopedValue performance declines as number of dynamic bindings increases<br><br>Hi Aleksey,<br><br>I re-wrote my benchmarks to use JMH and I used Blackhole::consume instead of the S.o.println. The entire point of the println was to signal to the compiler 'this has to happen'. I kept the 100k iterations, as I didn't want the setup of the 100 dynamic bindings to dominate (or perhaps they are? Not sure).<br><br>I ended up with the following results:<br><br><br>(This is the test of just doing MISSING.orElse)<br>Result "org.openjdk.bench.java.lang.ScopedValues.ScopedValuesAreFasT":<br> 815142.530 ±(99.9%) 17764.324 ns/op [Average]<br> (min, avg, max) = (790345.594, 815142.530, 835566.013), stdev = 11750.000<br> CI (99.9%): [797378.206, 832906.854] (assumes normal distribution)<br><br>(This is the test with MISSING.orElse within the 100 dynamic bindings)<br>Result "org.openjdk.bench.java.lang.ScopedValues.ScopedValuesAreSlow":<br> 18847997.203 ±(99.9%) 587930.099 ns/op [Average]<br> (min, avg, max) = (18176298.357, 18847997.203, 19523500.462), stdev = 388879.358<br> CI (99.9%): [18260067.104, 19435927.301] (assumes normal distribution)<br><br><br>That's 815142 ns/op vs 18847997ns/op, a pretty large diff still ('contested' case takes 23x longer).<br><br>Am I messing up my benchmarks once again, but in some different way?<br><br>Here's the branch and source: https://github.com/openjdk/jdk/compare/master...jdksjolen:jdk:scopedvaluejmhs<br><br>I just put the benchmark into the pre-existing ScopedValues.java, should just be a copy and paste and be done if you've got a JDK build set up.<br>The tests are run on linux-aarch64.<br><br>________________________________________<br>From: Aleksey Shipilev <shipilev@amazon.de><br>Sent: Tuesday, June 24, 2025 18:08<br>To: Johan Sjolen; Robert Engels<br>Cc: loom-dev@openjdk.org<br>Subject: Re: ScopedValue performance declines as number of dynamic bindings increases<br><br>On 24.06.25 18:01, Johan Sjolen wrote:<br><blockquote type="cite">Oooh, that could explain the issue completely. I didn't think about that at all.<br>The issue basically disappears when compiling first, let me see what happens with a JMH benchmark as well.<br></blockquote><br>I predict JMH would show the same thing.<br><br>javac is not very fast when cold; this is also why we use it as go-to example in AOT cache studies.<br>I would also expect compiling deeply nested lambdas (like in ScopedTest.java) makes the javac code<br>fairly recursive, which again plays interestingly with JIT compilation. It is still<br>actionable/interesting to figure out what can be improved there. Looks fairly weird we spend >3<br>seconds compiling a seemingly "easy" source. Submit a tools/javac RFE, let compiler folks have fun<br>with it?<br><br>-Aleksey<br><br><br><br>Amazon Web Services Development Center Germany GmbH<br>Tamara-Danz-Str. 13<br>10243 Berlin<br>Geschaeftsfuehrung: Christian Schlaeger, Jonathan Weiss<br>Eingetragen am Amtsgericht Charlottenburg unter HRB 257764 B<br>Sitz: Berlin<br>Ust-ID: DE 365 538 597<br></div></div></blockquote></div><br></div></body></html>