<div>+ core-libs-dev@</div><div> </div><div>I meant relation between in-loop and hoisted access.</div><div> </div><div>In Java 19 when we take count = 100 for volatile array and hoist it from the loop then the average time decreases from 146 to 33 ns.</div><div> </div><div>And if we take the same count for "plain" field and hoist it from the loop then the average time decreases from 98 to 7 ns.</div><div> </div><div> </div><div>16.08.2023, 15:44, "Raffaello Giulietti" <raffaello.giulietti@oracle.com>:</div><blockquote><p>If I read the data correctly, for the count=100 case in jdk 20 it takes<br />109 ns/op for the array and 74 ns/op for the field.<br /><br />To me this looks like a field access is _less_ expensive.<br /><br />Am I missing something?<br /><br /><br /><br />On 2023-08-16 13:37, Сергей Цыпанов wrote:</p><blockquote> Hello,<br /> <br /> I was measuring costs of hoisting volatile access out of the loop and found out, that there's a difference in numbers for arrays and "plain" references.<br /> <br /> Here's the benchmark for array:<br /> <br /> @BenchmarkMode(Mode.AverageTime)<br /> @OutputTimeUnit(TimeUnit.NANOSECONDS)<br /> @Warmup(time = 2, iterations = 5)<br /> @Measurement(time = 2, iterations = 5)<br /> @Fork(value = 4, jvmArgs = "-Xmx1g")<br /> public class VolatileArrayInLoopBenchmark {<!-- --><br /> <br /> @Benchmark<br /> public int accessVolatileInLoop(Data data) {<!-- --><br /> int sum = 0;<br /> for (int i = 0; i < data.count; i++) {<!-- --><br /> sum += data.ints[i];<br /> }<br /> return sum;<br /> }<br /> <br /> @Benchmark<br /> public int hoistVolatileFromLoop(Data data) {<!-- --><br /> int sum = 0;<br /> int[] ints = data.ints;<br /> for (int i = 0; i < data.count; i++) {<!-- --><br /> sum += ints[i];<br /> }<br /> return sum;<br /> }<br /> <br /> @State(Scope.Benchmark)<br /> public static class Data {<!-- --><br /> @Param({"1", "10", "100"})<br /> private int count;<br /> private volatile int[] ints;<br /> <br /> @Setup<br /> public void setUp() {<!-- --><br /> int[] ints = new int[count];<br /> for (int i = 0; i < ints.length; i++) {<!-- --><br /> ints[i] = ThreadLocalRandom.current().nextInt();<br /> }<br /> this.ints = ints;<br /> }<br /> }<br /> }<br /> <br /> and this one is for reference:<br /> <br /> @BenchmarkMode(Mode.AverageTime)<br /> @OutputTimeUnit(TimeUnit.NANOSECONDS)<br /> @Warmup(time = 2, iterations = 5)<br /> @Measurement(time = 2, iterations = 5)<br /> @Fork(value = 4, jvmArgs = "-Xmx1g")<br /> public class VolatileFieldInLoopBenchmark {<!-- --><br /> <br /> @Benchmark<br /> public int accessVolatileInLoop(Data data) {<!-- --><br /> int sum = 0;<br /> for (int i = 0; i < data.count; i++) {<!-- --><br /> sum += data.value;<br /> }<br /> return sum;<br /> }<br /> <br /> @Benchmark<br /> public int hoistVolatileFromLoop(Data data) {<!-- --><br /> int sum = 0;<br /> int value = data.value;<br /> for (int i = 0; i < data.count; i++) {<!-- --><br /> sum += value;<br /> }<br /> return sum;<br /> }<br /> <br /> @State(Scope.Benchmark)<br /> public static class Data {<!-- --><br /> private final ThreadLocalRandom random = ThreadLocalRandom.current();<br /> <br /> private volatile int value = random.nextInt();<br /> <br /> @Param({"1", "10", "100"})<br /> private int count;<br /> }<br /> }<br /> <br />  From measurement results it looks like volatile array access is cheaper than "plain" reference access:<br /> <br /> Java 19<br /> <br /> Benchmark (count) Mode Cnt Score Error Units<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 1 avgt 20 2.110 ± 0.404 ns/op<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 10 avgt 20 14.836 ± 2.825 ns/op<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 100 avgt 20 146.497 ± 25.786 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 1 avgt 20 3.006 ± 0.686 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 10 avgt 20 6.222 ± 1.215 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 100 avgt 20 33.262 ± 6.579 ns/op<br /> <br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 1 avgt 20 1.823 ± 0.382 ns/op<br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 10 avgt 20 10.259 ± 2.874 ns/op<br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 100 avgt 20 98.648 ± 18.500 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 1 avgt 20 2.189 ± 0.412 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 10 avgt 20 4.734 ± 0.891 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 100 avgt 20 7.126 ± 1.309 ns/op<br /> <br /> Java 20<br /> <br /> Benchmark (count) Mode Cnt Score Error Units<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 1 avgt 20 1.714 ± 0.066 ns/op<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 10 avgt 20 10.703 ± 0.148 ns/op<br /> VolatileArrayInLoopBenchmark.accessVolatileInLoop 100 avgt 20 109.001 ± 1.866 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 1 avgt 20 2.408 ± 0.224 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 10 avgt 20 4.678 ± 0.060 ns/op<br /> VolatileArrayInLoopBenchmark.hoistVolatileFromLoop 100 avgt 20 24.711 ± 1.091 ns/op<br /> <br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 1 avgt 20 1.366 ± 0.105 ns/op<br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 10 avgt 20 7.388 ± 0.119 ns/op<br /> VolatileFieldInLoopBenchmark.accessVolatileInLoop 100 avgt 20 74.630 ± 1.163 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 1 avgt 20 1.653 ± 0.035 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 10 avgt 20 3.138 ± 0.040 ns/op<br /> VolatileFieldInLoopBenchmark.hoistVolatileFromLoop 100 avgt 20 4.945 ± 0.177 ns/op<br /> <br /> So my question is why is volatile reference access is relatively more expensive than volatile array access?</blockquote></blockquote>