11/*
2- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2424
2525import org .openjdk .jmh .annotations .Benchmark ;
2626import org .openjdk .jmh .annotations .BenchmarkMode ;
27+ import org .openjdk .jmh .annotations .CompilerControl ;
2728import org .openjdk .jmh .annotations .Fork ;
2829import org .openjdk .jmh .annotations .Measurement ;
2930import org .openjdk .jmh .annotations .Mode ;
4243@ Warmup (iterations = 4 , time = 2 , timeUnit = TimeUnit .SECONDS )
4344@ Measurement (iterations = 4 , time = 2 , timeUnit = TimeUnit .SECONDS )
4445@ Fork (value = 3 )
45- public class WriteBarrier {
46+ public abstract class WriteBarrier {
4647
4748 // For array references
4849 public static final int NUM_REFERENCES_SMALL = 32 ;
4950 public static final int NUM_REFERENCES_LARGE = 2048 ;
5051
5152 // For array update tests
5253 private Object [] theArraySmall ;
53- private Object [] realReferencesSmall ;
54- private Object [] nullReferencesSmall ;
5554 private int [] indicesSmall ;
5655
5756 private Object [] theArrayLarge ;
58- private Object [] realReferencesLarge ;
59- private Object [] nullReferencesLarge ;
6057 private int [] indicesLarge ;
6158
59+ private Object nullRef ;
60+ private Object realRef ;
61+
6262 // For field update tests
6363 public Referencer head = null ;
6464 public Referencer tail = null ;
@@ -84,13 +84,9 @@ void clear() {
8484 @ Setup
8585 public void setup () {
8686 theArraySmall = new Object [NUM_REFERENCES_SMALL ];
87- realReferencesSmall = new Object [NUM_REFERENCES_SMALL ];
88- nullReferencesSmall = new Object [NUM_REFERENCES_SMALL ];
8987 indicesSmall = new int [NUM_REFERENCES_SMALL ];
9088
9189 theArrayLarge = new Object [NUM_REFERENCES_LARGE ];
92- realReferencesLarge = new Object [NUM_REFERENCES_LARGE ];
93- nullReferencesLarge = new Object [NUM_REFERENCES_LARGE ];
9490 indicesLarge = new int [NUM_REFERENCES_LARGE ];
9591
9692 m_w = (int ) System .currentTimeMillis ();
@@ -99,14 +95,14 @@ public void setup() {
9995
10096 for (int i = 0 ; i < NUM_REFERENCES_SMALL ; i ++) {
10197 indicesSmall [i ] = get_random () % (NUM_REFERENCES_SMALL - 1 );
102- realReferencesSmall [i ] = new Object ();
10398 }
10499
105100 for (int i = 0 ; i < NUM_REFERENCES_LARGE ; i ++) {
106101 indicesLarge [i ] = get_random () % (NUM_REFERENCES_LARGE - 1 );
107- realReferencesLarge [i ] = new Object ();
108102 }
109103
104+ realRef = new Object ();
105+
110106 // Build a small linked structure
111107 this .head = new Referencer ();
112108 this .tail = new Referencer ();
@@ -124,31 +120,40 @@ private int get_random() {
124120 return Math .abs ((m_z << 16 ) + m_w ); /* 32-bit result */
125121 }
126122
123+ // This and the other testArrayWriteBarrierFast benchmarks below should not
124+ // be inlined into the JMH-generated harness method. If the methods were
125+ // inlined, we might spill in the main loop (on x64) depending on very
126+ // subtle conditions (such as whether LinuxPerfAsmProfiler is enabled!),
127+ // which could distort the results.
127128 @ Benchmark
129+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
128130 public void testArrayWriteBarrierFastPathRealSmall () {
129131 for (int i = 0 ; i < NUM_REFERENCES_SMALL ; i ++) {
130- theArraySmall [indicesSmall [NUM_REFERENCES_SMALL - i - 1 ]] = realReferencesSmall [ indicesSmall [ i ]] ;
132+ theArraySmall [indicesSmall [NUM_REFERENCES_SMALL - i - 1 ]] = realRef ;
131133 }
132134 }
133135
134136 @ Benchmark
137+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
135138 public void testArrayWriteBarrierFastPathNullSmall () {
136139 for (int i = 0 ; i < NUM_REFERENCES_SMALL ; i ++) {
137- theArraySmall [indicesSmall [NUM_REFERENCES_SMALL - i - 1 ]] = nullReferencesSmall [ indicesSmall [ i ]] ;
140+ theArraySmall [indicesSmall [NUM_REFERENCES_SMALL - i - 1 ]] = nullRef ;
138141 }
139142 }
140143
141144 @ Benchmark
145+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
142146 public void testArrayWriteBarrierFastPathRealLarge () {
143147 for (int i = 0 ; i < NUM_REFERENCES_LARGE ; i ++) {
144- theArrayLarge [indicesLarge [NUM_REFERENCES_LARGE - i - 1 ]] = realReferencesLarge [ indicesLarge [ i ]] ;
148+ theArrayLarge [indicesLarge [NUM_REFERENCES_LARGE - i - 1 ]] = realRef ;
145149 }
146150 }
147151
148152 @ Benchmark
153+ @ CompilerControl (CompilerControl .Mode .DONT_INLINE )
149154 public void testArrayWriteBarrierFastPathNullLarge () {
150155 for (int i = 0 ; i < NUM_REFERENCES_LARGE ; i ++) {
151- theArrayLarge [indicesLarge [NUM_REFERENCES_LARGE - i - 1 ]] = nullReferencesLarge [ indicesLarge [ i ]] ;
156+ theArrayLarge [indicesLarge [NUM_REFERENCES_LARGE - i - 1 ]] = nullRef ;
152157 }
153158 }
154159
@@ -160,4 +165,15 @@ public void testFieldWriteBarrierFastPath() {
160165 this .head .append (this .tail );
161166 this .tail .clear ();
162167 }
168+
169+ // This run is useful to compare different GC barrier models without being
170+ // affected by C2 unrolling the main loop differently for each model.
171+ @ Fork (value = 3 , jvmArgs = {"-XX:LoopUnrollLimit=1" })
172+ public static class WithoutUnrolling extends WriteBarrier {}
173+
174+ // This run is useful to study the interaction of GC barriers and loop
175+ // unrolling. Check that the main loop in the testArray benchmarks is
176+ // unrolled (or not) as expected for the studied GC barrier model.
177+ @ Fork (value = 3 )
178+ public static class WithDefaultUnrolling extends WriteBarrier {}
163179}
0 commit comments