RFR: 8290079: Reduce interaction with volatile in static initializer of BigInteger
Raffaello Giulietti
duke at openjdk.org
Wed Jul 13 07:41:52 UTC 2022
On Tue, 12 Jul 2022 21:16:23 GMT, Сергей Цыпанов <duke at 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
More information about the core-libs-dev
mailing list