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 }