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.field;
 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.field.Value  -wmb "org.openjdk.bench.valhalla.acmp.field.Value.*050"
 45  */
 46 
 47 @Fork(value = 3, jvmArgsAppend = {"--enable-preview"})
 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 Value128 {
 54 
 55     public static final int SIZE = 100;
 56 
 57     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 58     private static int cmp_branch_obj(ObjWrapper[] objects1, ObjWrapper[] objects2) {
 59         int s = 0;
 60         for (int i = 0; i < SIZE; i++) {
 61             if (objects1[i].f == objects2[i].f) {
 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_val(ValWrapper[] objects1, ValWrapper[] objects2) {
 72         int s = 0;
 73         for (int i = 0; i < SIZE; i++) {
 74             if (objects1[i].f == objects2[i].f) {
 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_val(ValWrapper[] objects1, ValWrapper[] objects2) {
 85         boolean s = false;
 86         for (int i = 0; i < SIZE; i++) {
 87             s ^= objects1[i].f == objects2[i].f;
 88         }
 89         return s;
 90     }
 91 
 92     @CompilerControl(CompilerControl.Mode.DONT_INLINE)
 93     private static boolean cmp_result_obj(ObjWrapper[] objects1, ObjWrapper[] objects2) {
 94         boolean s = false;
 95         for (int i = 0; i < SIZE; i++) {
 96             s ^= objects1[i].f == objects2[i].f;
 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_val_equals000(ValState00 st) {
140         return cmp_branch_val(st.arr1, st.arr2);
141     }
142 
143     @Benchmark
144     @OperationsPerInvocation(SIZE)
145     @CompilerControl(CompilerControl.Mode.INLINE)
146     public int branch_val_equals025(ValState25 st) {
147         return cmp_branch_val(st.arr1, st.arr2);
148     }
149 
150     @Benchmark
151     @OperationsPerInvocation(SIZE)
152     @CompilerControl(CompilerControl.Mode.INLINE)
153     public int branch_val_equals050(ValState50 st) {
154         return cmp_branch_val(st.arr1, st.arr2);
155     }
156 
157     @Benchmark
158     @OperationsPerInvocation(SIZE)
159     @CompilerControl(CompilerControl.Mode.INLINE)
160     public int branch_val_equals075(ValState75 st) {
161         return cmp_branch_val(st.arr1, st.arr2);
162     }
163 
164     @Benchmark
165     @OperationsPerInvocation(SIZE)
166     @CompilerControl(CompilerControl.Mode.INLINE)
167     public int branch_val_equals100(ValState100 st) {
168         return cmp_branch_val(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_val_equals000(ValState00 st) {
211         return cmp_result_val(st.arr1, st.arr2);
212     }
213 
214     @Benchmark
215     @OperationsPerInvocation(SIZE)
216     @CompilerControl(CompilerControl.Mode.INLINE)
217     public boolean result_val_equals025(ValState25 st) {
218         return cmp_result_val(st.arr1, st.arr2);
219     }
220 
221     @Benchmark
222     @OperationsPerInvocation(SIZE)
223     @CompilerControl(CompilerControl.Mode.INLINE)
224     public boolean result_val_equals050(ValState50 st) {
225         return cmp_result_val(st.arr1, st.arr2);
226     }
227 
228     @Benchmark
229     @OperationsPerInvocation(SIZE)
230     @CompilerControl(CompilerControl.Mode.INLINE)
231     public boolean result_val_equals075(ValState75 st) {
232         return cmp_result_val(st.arr1, st.arr2);
233     }
234 
235     @Benchmark
236     @OperationsPerInvocation(SIZE)
237     @CompilerControl(CompilerControl.Mode.INLINE)
238     public boolean result_val_equals100(ValState100 st) {
239         return cmp_result_val(st.arr1, st.arr2);
240     }
241 
242     public static value class ValueInt4 {
243 
244         public final int v0;
245         public final int v1;
246         public final int v2;
247         public final int v3;
248 
249         public ValueInt4(int v) {
250             this.v0 = v;
251             this.v1 = v + 1;
252             this.v2 = v + 2;
253             this.v3 = v + 3;
254         }
255 
256     }
257 
258     private static void populate(ObjWrapper[] arr1, ObjWrapper[] arr2, int eq) {
259         if (eq <= 0) {
260             arr1[0] = new ObjWrapper(null);
261             arr2[0] = new ObjWrapper(new ValueInt4(1));
262             arr1[1] = new ObjWrapper(new ValueInt4(2));
263             arr2[1] = new ObjWrapper(null);
264             for (int i = 2; i < SIZE; i++) {
265                 arr1[i] = new ObjWrapper(new ValueInt4(2 * i));
266                 arr2[i] = new ObjWrapper(new ValueInt4(2 * i + 1));
267             }
268         } else if (eq >= 100) {
269             arr2[0] = arr1[0] = new ObjWrapper(null);
270             for (int i = 1; i < SIZE; i++) {
271                 ValueInt4 x = new ValueInt4(i);
272                 arr2[i] = new ObjWrapper(x);
273                 arr1[i] = new ObjWrapper(x);
274             }
275         } else {
276             BitSet eqset = new Random(42).ints(0, SIZE).distinct().limit(eq * SIZE / 100).collect(BitSet::new, BitSet::set, BitSet::or);
277             boolean samenulls = true;
278             int distinctnulls = 0;
279             for (int i = 0; i < SIZE; i++) {
280                 if (eqset.get(i)) {
281                     if(samenulls) {
282                         arr2[i] = new ObjWrapper(null);
283                         arr1[i] = new ObjWrapper(null);
284                         samenulls = false;
285                     } else {
286                         ValueInt4 x = new ValueInt4(i);
287                         arr2[i] = new ObjWrapper(x);
288                         arr1[i] = new ObjWrapper(x);
289                     }
290                 } else {
291                     switch (distinctnulls) {
292                         case 0:
293                             arr1[i] = new ObjWrapper(null);
294                             arr2[i] = new ObjWrapper(new ValueInt4(2 * i + 1));
295                             distinctnulls = 1;
296                             break;
297                         case 1:
298                             arr1[i] = new ObjWrapper(new ValueInt4(2 * i));
299                             arr2[i] = new ObjWrapper(null);
300                             distinctnulls  = 2;
301                             break;
302                         default:
303                             arr1[i] = new ObjWrapper(new ValueInt4(2 * i));
304                             arr2[i] = new ObjWrapper(new ValueInt4(2 * i + 1));
305                             break;
306                     }
307                 }
308             }
309         }
310     }
311 
312 
313     private static void populate(ValWrapper[] arr1, ValWrapper[] arr2, int eq) {
314         if (eq <= 0) {
315             arr1[0] = new ValWrapper(null);
316             arr2[0] = new ValWrapper(new ValueInt4(1));
317             arr1[1] = new ValWrapper(new ValueInt4(2));
318             arr2[1] = new ValWrapper(null);
319             for (int i = 2; i < SIZE; i++) {
320                 arr1[i] = new ValWrapper(new ValueInt4(2 * i));
321                 arr2[i] = new ValWrapper(new ValueInt4(2 * i + 1));
322             }
323         } else if (eq >= 100) {
324             arr2[0] = arr1[0] = new ValWrapper(null);
325             for (int i = 1; i < SIZE; i++) {
326                 ValueInt4 x = new ValueInt4(i);
327                 arr2[i] = new ValWrapper(x);
328                 arr1[i] = new ValWrapper(x);
329             }
330         } else {
331             BitSet eqset = new Random(42).ints(0, SIZE).distinct().limit(eq * SIZE / 100).collect(BitSet::new, BitSet::set, BitSet::or);
332             boolean samenulls = true;
333             int distinctnulls = 0;
334             for (int i = 0; i < SIZE; i++) {
335                 if (eqset.get(i)) {
336                     if(samenulls) {
337                         arr2[i] = new ValWrapper(null);
338                         arr1[i] = new ValWrapper(null);
339                         samenulls = false;
340                     } else {
341                         ValueInt4 x = new ValueInt4(i);
342                         arr2[i] = new ValWrapper(x);
343                         arr1[i] = new ValWrapper(x);
344                     }
345                 } else {
346                     switch (distinctnulls) {
347                         case 0:
348                             arr1[i] = new ValWrapper(null);
349                             arr2[i] = new ValWrapper(new ValueInt4(2 * i + 1));
350                             distinctnulls = 1;
351                             break;
352                         case 1:
353                             arr1[i] = new ValWrapper(new ValueInt4(2 * i));
354                             arr2[i] = new ValWrapper(null);
355                             distinctnulls  = 2;
356                             break;
357                         default:
358                             arr1[i] = new ValWrapper(new ValueInt4(2 * i));
359                             arr2[i] = new ValWrapper(new ValueInt4(2 * i + 1));
360                             break;
361                     }
362                 }
363             }
364         }
365     }
366 
367     public static class ObjWrapper {
368         public Object f;
369 
370         public ObjWrapper(Object f) {
371             this.f = f;
372         }
373     }
374 
375     public static class ValWrapper {
376         public ValueInt4 f;
377 
378         public ValWrapper(ValueInt4 f) {
379             this.f = f;
380         }
381     }
382 
383     @State(Scope.Thread)
384     public abstract static class ObjState {
385         ObjWrapper[] arr1, arr2;
386 
387         public void setup(int eq) {
388             arr1 = new ObjWrapper[SIZE];
389             arr2 = new ObjWrapper[SIZE];
390             populate(arr1, arr2, eq);
391         }
392     }
393 
394     @State(Scope.Thread)
395     public abstract static class ValState {
396         ValWrapper[] arr1, arr2;
397 
398         public void setup(int eq) {
399             arr1 = new ValWrapper[SIZE];
400             arr2 = new ValWrapper[SIZE];
401             populate(arr1, arr2, eq);
402         }
403     }
404 
405     public static class ObjState00 extends ObjState {
406         @Setup
407         public void setup() {
408             setup(0);
409         }
410     }
411 
412     public static class ObjState25 extends ObjState {
413         @Setup
414         public void setup() {
415             setup(25);
416         }
417     }
418 
419     public static class ObjState50 extends ObjState {
420         @Setup
421         public void setup() {
422             setup(50);
423         }
424     }
425 
426     public static class ObjState75 extends ObjState {
427         @Setup
428         public void setup() {
429             setup(75);
430         }
431     }
432 
433     public static class ObjState100 extends ObjState {
434         @Setup
435         public void setup() {
436             setup(100);
437         }
438     }
439 
440     public static class ValState00 extends ValState {
441         @Setup
442         public void setup() {
443             setup(0);
444         }
445     }
446 
447     public static class ValState25 extends ValState {
448         @Setup
449         public void setup() {
450             setup(25);
451         }
452     }
453 
454     public static class ValState50 extends ValState {
455         @Setup
456         public void setup() {
457             setup(50);
458         }
459     }
460 
461     public static class ValState75 extends ValState {
462         @Setup
463         public void setup() {
464             setup(75);
465         }
466     }
467 
468     public static class ValState100 extends ValState {
469         @Setup
470         public void setup() {
471             setup(100);
472         }
473     }
474 
475 }