On Tue, 12 Jul 2022 21:16:23 GMT, Сергей Цыпанов <d...@openjdk.org> wrote:

>> Usually yes, but since a static initializer is executed by at most one 
>> thread by using a locking protocol before any other static code is ever 
>> executed, the runtime _could_ (but I'm not sure it it really does) treat the 
>> volatile in the for loop as a local.
>> But I would approve your change because it makes this more explicit.
>
> @rgiulietti I've copy-pasted class-loading benchmark from JMH samples
> 
> @State(Scope.Thread)
> @Warmup(iterations = 10, time = 1)
> @Measurement(iterations = 10, time = 5)
> @Fork(value = 5, jvmArgsAppend = {"-Xms1g", "-Xmx1g"})
> @BenchmarkMode(Mode.AverageTime)
> @OutputTimeUnit(TimeUnit.NANOSECONDS)
> public class Classy {
> 
>     @Benchmark
>     public Class<?> load() throws ClassNotFoundException {
>         return Class.forName("com.tsypanov.slp.Sample", true, new XLoader());
>     }
> 
>     public static class XLoader extends URLClassLoader {
> 
>         private static final byte[] X_BYTECODE = new byte[]{ /*..*/};
> 
>         public XLoader() {
>             super(new URL[0], ClassLoader.getSystemClassLoader());
>         }
> 
>         @Override
>         protected Class<?> findClass(final String name) {
>             return defineClass(name, X_BYTECODE, 0, X_BYTECODE.length);
>         }
>     }
> }
> 
> and used it to measure loading a class from `byte[]` copied from the 
> following class compiled:
> 
> class Sample {
>   static volatile int[] items = new int[100];
>   static {
>     for (int i = 0; i < items.length; i++) {
>       items[i] = ThreadLocalRandom.current().nextInt();
>     }
>   }
> }
> 
> I ran the benchmark with `java -jar target/sleep-benchmarks.jar Classy -prof 
> cl` and for the version above got these results (Java 17):
> 
> Benchmark                       Mode  Cnt       Score      Error        Units
> Classy.load                     avgt   50   96247.202 ±  548.137        ns/op
> Classy.load:·class.load         avgt   50  259912.089 ± 1485.314  classes/sec
> Classy.load:·class.load.norm    avgt   50       1.000 ±    0.001   classes/op
> Classy.load:·class.unload       avgt   50  260243.318 ± 3673.515  classes/sec
> Classy.load:·class.unload.norm  avgt   50       1.001 ±    0.014   classes/op
> 
> Then I've modified the class in the same way I did in this PR:
> 
> class Sample {
>   static volatile int[] items;
>   static {
>     int[] items = new int[100];
>     for (int i = 0; i < items.length; i++) {
>       items[i] = ThreadLocalRandom.current().nextInt();
>     }
>     Sample.items = items;
>   }
> }
> 
> and for modified code got
> 
> 
> Benchmark                       Mode  Cnt       Score      Error        Units
> Classy.load                     avgt   50   63955.673 ±  147.470        ns/op
> Classy.load:·class.load         avgt   50  391101.854 ±  925.013  classes/sec
> Classy.load:·class.load.norm    avgt   50       1.000 ±    0.001   classes/op
> Classy.load:·class.unload       avgt   50  390800.851 ± 2307.589  classes/sec
> Classy.load:·class.unload.norm  avgt   50       0.999 ±    0.006   classes/op
> 
> From this I conclude that volatile costs are still there no matter whether we 
> deal with static or non-static initializers.

@stsypanov Hi Сергей, thanks for the convincing measurements!

-------------

PR: https://git.openjdk.org/jdk/pull/9451

Reply via email to