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 }