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.Value  -wmb "org.openjdk.bench.valhalla.acmp.array.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(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_val(ValueInt4[] objects1, ValueInt4[] 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_val(ValueInt4[] objects1, ValueInt4[] 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_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(Object[] arr1, Object[] arr2, int eq) {
259         if (eq <= 0) {
260             arr1[0] = null;
261             arr2[0] = new ValueInt4(1);
262             arr1[1] = new ValueInt4(2);
263             arr2[1] = null;
264             for (int i = 2; i < SIZE; i++) {
265                 arr1[i] = new ValueInt4(2 * i);
266                 arr2[i] = new ValueInt4(2 * i + 1);
267             }
268         } else if (eq >= 100) {
269             arr2[0] = arr1[0] = null;
270             for (int i = 1; i < SIZE; i++) {
271                 arr2[i] = arr1[i] = new ValueInt4(i);
272             }
273         } else {
274             BitSet eqset = new Random(42).ints(0, SIZE).distinct().limit(eq * SIZE / 100).collect(BitSet::new, BitSet::set, BitSet::or);
275             boolean samenulls = true;
276             int distinctnulls = 0;
277             for (int i = 0; i < SIZE; i++) {
278                 if (eqset.get(i)) {
279                     if(samenulls) {
280                         arr2[i] = arr1[i] = null;
281                         samenulls = false;
282                     } else {
283                         arr2[i] = arr1[i] = new ValueInt4(i);
284                     }
285                 } else {
286                     switch (distinctnulls) {
287                         case 0:
288                             arr1[i] = null;
289                             arr2[i] = new ValueInt4(2 * i + 1);
290                             distinctnulls = 1;
291                             break;
292                         case 1:
293                             arr1[i] = new ValueInt4(2 * i);
294                             arr2[i] = null;
295                             distinctnulls  = 2;
296                             break;
297                         default:
298                             arr1[i] = new ValueInt4(2 * i);
299                             arr2[i] = new ValueInt4(2 * i + 1);
300                             break;
301                     }
302                 }
303             }
304 
305         }
306     }
307 
308     @State(Scope.Thread)
309     public abstract static class ObjState {
310         Object[] arr1, arr2;
311 
312         public void setup(int eq) {
313             arr1 = new Object[SIZE];
314             arr2 = new Object[SIZE];
315             populate(arr1, arr2, eq);
316         }
317     }
318 
319     @State(Scope.Thread)
320     public abstract static class ValState {
321         ValueInt4[] arr1, arr2;
322 
323         public void setup(int eq) {
324             arr1 = new ValueInt4[SIZE];
325             arr2 = new ValueInt4[SIZE];
326             populate(arr1, arr2, eq);
327         }
328     }
329 
330     public static class ObjState00 extends ObjState {
331         @Setup
332         public void setup() {
333             setup(0);
334         }
335     }
336 
337     public static class ObjState25 extends ObjState {
338         @Setup
339         public void setup() {
340             setup(25);
341         }
342     }
343 
344     public static class ObjState50 extends ObjState {
345         @Setup
346         public void setup() {
347             setup(50);
348         }
349     }
350 
351     public static class ObjState75 extends ObjState {
352         @Setup
353         public void setup() {
354             setup(75);
355         }
356     }
357 
358     public static class ObjState100 extends ObjState {
359         @Setup
360         public void setup() {
361             setup(100);
362         }
363     }
364 
365     public static class ValState00 extends ValState {
366         @Setup
367         public void setup() {
368             setup(0);
369         }
370     }
371 
372     public static class ValState25 extends ValState {
373         @Setup
374         public void setup() {
375             setup(25);
376         }
377     }
378 
379     public static class ValState50 extends ValState {
380         @Setup
381         public void setup() {
382             setup(50);
383         }
384     }
385 
386     public static class ValState75 extends ValState {
387         @Setup
388         public void setup() {
389             setup(75);
390         }
391     }
392 
393     public static class ValState100 extends ValState {
394         @Setup
395         public void setup() {
396             setup(100);
397         }
398     }
399 
400 }