1 /*
  2  * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.bench.valhalla.acmp.array;
 24 
 25 import org.openjdk.jmh.annotations.Benchmark;
 26 import org.openjdk.jmh.annotations.BenchmarkMode;
 27 import org.openjdk.jmh.annotations.CompilerControl;
 28 import org.openjdk.jmh.annotations.Fork;
 29 import org.openjdk.jmh.annotations.Measurement;
 30 import org.openjdk.jmh.annotations.Mode;
 31 import org.openjdk.jmh.annotations.OperationsPerInvocation;
 32 import org.openjdk.jmh.annotations.OutputTimeUnit;
 33 import org.openjdk.jmh.annotations.Scope;
 34 import org.openjdk.jmh.annotations.Setup;
 35 import org.openjdk.jmh.annotations.State;
 36 import org.openjdk.jmh.annotations.Warmup;
 37 
 38 import java.util.BitSet;
 39 import java.util.Random;
 40 import java.util.concurrent.TimeUnit;
 41 
 42 /*
 43  *  For proper results it should be executed:
 44  *  java -jar target/benchmarks.jar org.openjdk.bench.valhalla.acmp.array.Identity  -wmb "org.openjdk.bench.valhalla.acmp.array.Identity.*050"
 45  */
 46 
 47 @Fork(3)
 48 @Warmup(iterations = 3, time = 1)
 49 @Measurement(iterations = 5, time = 1)
 50 @OutputTimeUnit(TimeUnit.NANOSECONDS)
 51 @BenchmarkMode(Mode.AverageTime)
 52 @State(Scope.Thread)
 53 public class Identity {
 54 
 55     public static final int SIZE = 100;
 56 
 57     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 58     private static int cmp_branch_obj(Object[] objects1, Object[] objects2) {
 59         int s = 0;
 60         for (int i = 0; i < SIZE; i++) {
 61             if (objects1[i] == objects2[i]) {
 62                 s += 1;
 63             } else {
 64                 s -= 1;
 65             }
 66         }
 67         return s;
 68     }
 69 
 70     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 71     private static int cmp_branch_ref(IdentityInt[] objects1, IdentityInt[] objects2) {
 72         int s = 0;
 73         for (int i = 0; i < SIZE; i++) {
 74             if (objects1[i] == objects2[i]) {
 75                 s += 1;
 76             } else {
 77                 s -= 1;
 78             }
 79         }
 80         return s;
 81     }
 82 
 83     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 84     private static boolean cmp_result_ref(IdentityInt[] objects1, IdentityInt[] objects2) {
 85         boolean s = false;
 86         for (int i = 0; i < SIZE; i++) {
 87             s ^= objects1[i] == objects2[i];
 88         }
 89         return s;
 90     }
 91 
 92     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 93     private static boolean cmp_result_obj(Object[] objects1, Object[] objects2) {
 94         boolean s = false;
 95         for (int i = 0; i < SIZE; i++) {
 96             s ^= objects1[i] == objects2[i];
 97         }
 98         return s;
 99     }
100 
101     @Benchmark
102     @OperationsPerInvocation(SIZE)
103     @CompilerControl(CompilerControl.Mode.INLINE)
104     public int branch_obj_equals000(ObjState00 st) {
105         return cmp_branch_obj(st.arr1, st.arr2);
106     }
107 
108     @Benchmark
109     @OperationsPerInvocation(SIZE)
110     @CompilerControl(CompilerControl.Mode.INLINE)
111     public int branch_obj_equals025(ObjState25 st) {
112         return cmp_branch_obj(st.arr1, st.arr2);
113     }
114 
115     @Benchmark
116     @OperationsPerInvocation(SIZE)
117     @CompilerControl(CompilerControl.Mode.INLINE)
118     public int branch_obj_equals050(ObjState50 st) {
119         return cmp_branch_obj(st.arr1, st.arr2);
120     }
121 
122     @Benchmark
123     @OperationsPerInvocation(SIZE)
124     @CompilerControl(CompilerControl.Mode.INLINE)
125     public int branch_obj_equals075(ObjState75 st) {
126         return cmp_branch_obj(st.arr1, st.arr2);
127     }
128 
129     @Benchmark
130     @OperationsPerInvocation(SIZE)
131     @CompilerControl(CompilerControl.Mode.INLINE)
132     public int branch_obj_equals100(ObjState100 st) {
133         return cmp_branch_obj(st.arr1, st.arr2);
134     }
135 
136     @Benchmark
137     @OperationsPerInvocation(SIZE)
138     @CompilerControl(CompilerControl.Mode.INLINE)
139     public int branch_ref_equals000(RefState00 st) {
140         return cmp_branch_ref(st.arr1, st.arr2);
141     }
142 
143     @Benchmark
144     @OperationsPerInvocation(SIZE)
145     @CompilerControl(CompilerControl.Mode.INLINE)
146     public int branch_ref_equals025(RefState25 st) {
147         return cmp_branch_ref(st.arr1, st.arr2);
148     }
149 
150     @Benchmark
151     @OperationsPerInvocation(SIZE)
152     @CompilerControl(CompilerControl.Mode.INLINE)
153     public int branch_ref_equals050(RefState50 st) {
154         return cmp_branch_ref(st.arr1, st.arr2);
155     }
156 
157     @Benchmark
158     @OperationsPerInvocation(SIZE)
159     @CompilerControl(CompilerControl.Mode.INLINE)
160     public int branch_ref_equals075(RefState75 st) {
161         return cmp_branch_ref(st.arr1, st.arr2);
162     }
163 
164     @Benchmark
165     @OperationsPerInvocation(SIZE)
166     @CompilerControl(CompilerControl.Mode.INLINE)
167     public int branch_ref_equals100(RefState100 st) {
168         return cmp_branch_ref(st.arr1, st.arr2);
169     }
170 
171 
172     @Benchmark
173     @OperationsPerInvocation(SIZE)
174     @CompilerControl(CompilerControl.Mode.INLINE)
175     public boolean result_obj_equals000(ObjState00 st) {
176         return cmp_result_obj(st.arr1, st.arr2);
177     }
178 
179     @Benchmark
180     @OperationsPerInvocation(SIZE)
181     @CompilerControl(CompilerControl.Mode.INLINE)
182     public boolean result_obj_equals025(ObjState25 st) {
183         return cmp_result_obj(st.arr1, st.arr2);
184     }
185 
186     @Benchmark
187     @OperationsPerInvocation(SIZE)
188     @CompilerControl(CompilerControl.Mode.INLINE)
189     public boolean result_obj_equals050(ObjState50 st) {
190         return cmp_result_obj(st.arr1, st.arr2);
191     }
192 
193     @Benchmark
194     @OperationsPerInvocation(SIZE)
195     @CompilerControl(CompilerControl.Mode.INLINE)
196     public boolean result_obj_equals075(ObjState75 st) {
197         return cmp_result_obj(st.arr1, st.arr2);
198     }
199 
200     @Benchmark
201     @OperationsPerInvocation(SIZE)
202     @CompilerControl(CompilerControl.Mode.INLINE)
203     public boolean result_obj_equals100(ObjState100 st) {
204         return cmp_result_obj(st.arr1, st.arr2);
205     }
206 
207     @Benchmark
208     @OperationsPerInvocation(SIZE)
209     @CompilerControl(CompilerControl.Mode.INLINE)
210     public boolean result_ref_equals000(RefState00 st) {
211         return cmp_result_ref(st.arr1, st.arr2);
212     }
213 
214     @Benchmark
215     @OperationsPerInvocation(SIZE)
216     @CompilerControl(CompilerControl.Mode.INLINE)
217     public boolean result_ref_equals025(RefState25 st) {
218         return cmp_result_ref(st.arr1, st.arr2);
219     }
220 
221     @Benchmark
222     @OperationsPerInvocation(SIZE)
223     @CompilerControl(CompilerControl.Mode.INLINE)
224     public boolean result_ref_equals050(RefState50 st) {
225         return cmp_result_ref(st.arr1, st.arr2);
226     }
227 
228     @Benchmark
229     @OperationsPerInvocation(SIZE)
230     @CompilerControl(CompilerControl.Mode.INLINE)
231     public boolean result_ref_equals075(RefState75 st) {
232         return cmp_result_ref(st.arr1, st.arr2);
233     }
234 
235     @Benchmark
236     @OperationsPerInvocation(SIZE)
237     @CompilerControl(CompilerControl.Mode.INLINE)
238     public boolean result_ref_equals100(RefState100 st) {
239         return cmp_result_ref(st.arr1, st.arr2);
240     }
241 
242     public static class IdentityInt {
243 
244         public final int v0;
245 
246         public IdentityInt(int v0) {
247             this.v0 = v0;
248         }
249 
250         public int value() {
251             return v0;
252         }
253 
254     }
255 
256     private static void populate(Object[] arr1, Object[] arr2, int eq) {
257         if (eq <= 0) {
258             arr1[0] = null;
259             arr2[0] = new IdentityInt(1);
260             arr1[1] = new IdentityInt(2);
261             arr2[1] = null;
262             for (int i = 2; i < SIZE; i++) {
263                 arr1[i] = new IdentityInt(2 * i);
264                 arr2[i] = new IdentityInt(2 * i + 1);
265             }
266         } else if (eq >= 100) {
267             arr2[0] = arr1[0] = null;
268             for (int i = 1; i < SIZE; i++) {
269                 arr2[i] = arr1[i] = new IdentityInt(i);
270             }
271         } else {
272             BitSet eqset = new Random(42).ints(0, SIZE).distinct().limit(eq * SIZE / 100).collect(BitSet::new, BitSet::set, BitSet::or);
273             boolean samenulls = true;
274             int distinctnulls = 0;
275             for (int i = 0; i < SIZE; i++) {
276                 if (eqset.get(i)) {
277                     if(samenulls) {
278                         arr2[i] = arr1[i] = null;
279                         samenulls = false;
280                     } else {
281                         arr2[i] = arr1[i] = new IdentityInt(i);
282                     }
283                 } else {
284                     switch (distinctnulls) {
285                         case 0:
286                             arr1[i] = null;
287                             arr2[i] = new IdentityInt(2 * i + 1);
288                             distinctnulls = 1;
289                             break;
290                         case 1:
291                             arr1[i] = new IdentityInt(2 * i);
292                             arr2[i] = null;
293                             distinctnulls  = 2;
294                             break;
295                         default:
296                             arr1[i] = new IdentityInt(2 * i);
297                             arr2[i] = new IdentityInt(2 * i + 1);
298                             break;
299                     }
300                 }
301             }
302 
303         }
304     }
305 
306     @State(Scope.Thread)
307     public abstract static class ObjState {
308         Object[] arr1, arr2;
309 
310         public void setup(int eq) {
311             arr1 = new Object[SIZE];
312             arr2 = new Object[SIZE];
313             populate(arr1, arr2, eq);
314         }
315     }
316 
317     @State(Scope.Thread)
318     public abstract static class RefState {
319         IdentityInt[] arr1, arr2;
320 
321         public void setup(int eq) {
322             arr1 = new IdentityInt[SIZE];
323             arr2 = new IdentityInt[SIZE];
324             populate(arr1, arr2, eq);
325         }
326     }
327 
328     public static class ObjState00 extends ObjState {
329         @Setup
330         public void setup() {
331             setup(0);
332         }
333     }
334 
335     public static class ObjState25 extends ObjState {
336         @Setup
337         public void setup() {
338             setup(25);
339         }
340     }
341 
342     public static class ObjState50 extends ObjState {
343         @Setup
344         public void setup() {
345             setup(50);
346         }
347     }
348 
349     public static class ObjState75 extends ObjState {
350         @Setup
351         public void setup() {
352             setup(75);
353         }
354     }
355 
356     public static class ObjState100 extends ObjState {
357         @Setup
358         public void setup() {
359             setup(100);
360         }
361     }
362 
363     public static class RefState00 extends RefState {
364         @Setup
365         public void setup() {
366             setup(0);
367         }
368     }
369 
370     public static class RefState25 extends RefState {
371         @Setup
372         public void setup() {
373             setup(25);
374         }
375     }
376 
377     public static class RefState50 extends RefState {
378         @Setup
379         public void setup() {
380             setup(50);
381         }
382     }
383 
384     public static class RefState75 extends RefState {
385         @Setup
386         public void setup() {
387             setup(75);
388         }
389     }
390 
391     public static class RefState100 extends RefState {
392         @Setup
393         public void setup() {
394             setup(100);
395         }
396     }
397 
398 }