1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.rng.examples.jmh.simple;
19
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.core.source64.SplitMix64;
22 import org.apache.commons.rng.simple.RandomSource;
23 import org.apache.commons.rng.simple.internal.SeedFactory;
24 import org.openjdk.jmh.annotations.Benchmark;
25 import org.openjdk.jmh.annotations.BenchmarkMode;
26 import org.openjdk.jmh.annotations.Fork;
27 import org.openjdk.jmh.annotations.Measurement;
28 import org.openjdk.jmh.annotations.Mode;
29 import org.openjdk.jmh.annotations.OutputTimeUnit;
30 import org.openjdk.jmh.annotations.Scope;
31 import org.openjdk.jmh.annotations.State;
32 import org.openjdk.jmh.annotations.Threads;
33 import org.openjdk.jmh.annotations.Warmup;
34
35 import java.util.Random;
36 import java.util.concurrent.ThreadLocalRandom;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.atomic.AtomicInteger;
39 import java.util.concurrent.atomic.AtomicLong;
40 import java.util.concurrent.locks.Lock;
41 import java.util.concurrent.locks.ReentrantLock;
42
43
44
45
46
47 @BenchmarkMode(Mode.AverageTime)
48 @OutputTimeUnit(TimeUnit.NANOSECONDS)
49 @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
50 @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
51 @State(Scope.Benchmark)
52 @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"})
53 public class SeedGenerationPerformance {
54
55
56
57
58 static final long SEED_INCREMENT = 0xbb67ae8584caa73bL;
59
60
61
62
63
64
65
66 private static final ReentrantLock UNFAIR_LOCK = new ReentrantLock(false);
67
68
69
70
71
72
73
74 private static final ReentrantLock FAIR_LOCK = new ReentrantLock(true);
75
76
77
78
79
80 private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
81
82
83 private int intValue;
84
85
86 private long longValue;
87
88
89 private volatile int volatileIntValue;
90
91
92 private volatile long volatileLongValue;
93
94
95 private final AtomicInteger atomicInt = new AtomicInteger();
96
97
98 private final AtomicLong atomicLong = new AtomicLong();
99
100
101 private final AtomicLong state = new AtomicLong();
102
103
104 private final UniformRandomProvider xoRoShiRo128Plus = RandomSource.XO_RO_SHI_RO_128_PLUS.create();
105
106
107 private final UniformRandomProvider xorShift1024StarPhi = RandomSource.XOR_SHIFT_1024_S_PHI.create();
108
109
110 private final UniformRandomProvider well44497b = RandomSource.WELL_44497_B.create();
111
112
113 private final Random random = new Random();
114
115
116
117
118 private static final class ThreadLocalRNG extends ThreadLocal<UniformRandomProvider> {
119
120
121
122 private static final AtomicLong SEED = new AtomicLong(0);
123
124
125 private static final ThreadLocalRNG INSTANCE = new ThreadLocalRNG();
126
127
128 private ThreadLocalRNG() {
129
130 }
131
132 @Override
133 protected UniformRandomProvider initialValue() {
134 return new SplitMix64(SEED.getAndAdd(SEED_INCREMENT));
135 }
136
137
138
139
140
141
142 public static UniformRandomProvider current() {
143 return INSTANCE.get();
144 }
145 }
146
147
148
149
150 private static final class ThreadLocalSplitMix extends ThreadLocal<SplitMix64> {
151
152
153
154 private static final AtomicLong SEED = new AtomicLong(0);
155
156
157 private static final ThreadLocalSplitMix INSTANCE = new ThreadLocalSplitMix();
158
159
160 private ThreadLocalSplitMix() {
161
162 }
163
164 @Override
165 protected SplitMix64 initialValue() {
166 return new SplitMix64(SEED.getAndAdd(SEED_INCREMENT));
167 }
168
169
170
171
172
173
174 public static SplitMix64 current() {
175 return INSTANCE.get();
176 }
177 }
178
179
180
181
182 private static final class ThreadLocalSequence extends ThreadLocal<long[]> {
183
184
185
186 private static final AtomicLong SEED = new AtomicLong(0);
187
188
189 private static final ThreadLocalSequence INSTANCE = new ThreadLocalSequence();
190
191
192 private ThreadLocalSequence() {
193
194 }
195
196 @Override
197 protected long[] initialValue() {
198 return new long[] {SEED.getAndAdd(SEED_INCREMENT)};
199 }
200
201
202
203
204
205
206 public static long next() {
207 final long[] value = INSTANCE.get();
208 return value[0] += GOLDEN_GAMMA;
209 }
210 }
211
212
213
214
215
216
217
218 private static int nextInt(UniformRandomProvider rng) {
219 synchronized (rng) {
220 return rng.nextInt();
221 }
222 }
223
224
225
226
227
228
229
230 private static long nextLong(UniformRandomProvider rng) {
231 synchronized (rng) {
232 return rng.nextLong();
233 }
234 }
235
236
237
238
239
240
241
242
243 private static int nextInt(Lock lock, UniformRandomProvider rng) {
244 lock.lock();
245 try {
246 return rng.nextInt();
247 } finally {
248 lock.unlock();
249 }
250 }
251
252
253
254
255
256
257
258
259 private static long nextLong(Lock lock, UniformRandomProvider rng) {
260 lock.lock();
261 try {
262 return rng.nextLong();
263 } finally {
264 lock.unlock();
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277
278 private static long mixLong(long z) {
279 z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
280 z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
281 return z ^ (z >>> 31);
282 }
283
284
285
286
287
288
289
290
291
292
293
294 private static int mixInt(long z) {
295 z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
296 return (int) (((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
297 }
298
299
300
301
302 @Benchmark
303 public void baselineVoid() {
304
305 }
306
307
308
309
310
311
312 @Benchmark
313 public int baselineInt() {
314 return intValue;
315 }
316
317
318
319
320
321
322 @Benchmark
323 public long baselineLong() {
324 return longValue;
325 }
326
327
328
329
330
331
332
333
334 @Benchmark
335 public int XoRoShiRo128Plus_nextInt() {
336 return xoRoShiRo128Plus.nextInt();
337 }
338
339 @Benchmark
340 public int XorShift1024StarPhi_nextInt() {
341 return xorShift1024StarPhi.nextInt();
342 }
343
344 @Benchmark
345 public int Well44497b_nextInt() {
346 return well44497b.nextInt();
347 }
348
349 @Benchmark
350 public long XoRoShiRo128Plus_nextLong() {
351 return xoRoShiRo128Plus.nextLong();
352 }
353
354 @Benchmark
355 public long XorShift1024StarPhi_nextLong() {
356 return xorShift1024StarPhi.nextLong();
357 }
358
359 @Benchmark
360 public long Well44497b_nextLong() {
361 return well44497b.nextLong();
362 }
363
364 @Benchmark
365 public int Threads1_SeedFactory_createInt() {
366 return SeedFactory.createInt();
367 }
368
369 @Benchmark
370 public long Threads1_SeedFactory_createLong() {
371 return SeedFactory.createLong();
372 }
373
374 @Benchmark
375 public long Threads1_System_currentTimeMillis() {
376
377 return System.currentTimeMillis();
378 }
379
380 @Benchmark
381 public long Threads1_System_nanoTime() {
382
383 return System.nanoTime();
384 }
385
386 @Benchmark
387 public int Threads1_System_identityHashCode() {
388 return System.identityHashCode(new Object());
389 }
390
391 @Benchmark
392 public long Threads1_ThreadLocalRandom_nextLong() {
393 return ThreadLocalRandom.current().nextLong();
394 }
395
396 @Benchmark
397 public int Threads1_ThreadLocalRandom_nextInt() {
398 return ThreadLocalRandom.current().nextInt();
399 }
400
401 @Benchmark
402 public long Threads1_ThreadLocalRNG_nextLong() {
403 return ThreadLocalRNG.current().nextLong();
404 }
405
406 @Benchmark
407 public int Threads1_ThreadLocalRNG_nextInt() {
408 return ThreadLocalRNG.current().nextInt();
409 }
410
411 @Benchmark
412 public long Threads1_ThreadLocalSplitMix_nextLong() {
413 return ThreadLocalSplitMix.current().nextLong();
414 }
415
416 @Benchmark
417 public int Threads1_ThreadLocalSplitMix_nextInt() {
418 return ThreadLocalSplitMix.current().nextInt();
419 }
420
421 @Benchmark
422 public long Threads1_ThreadLocalSequenceMix_nextLong() {
423 return mixLong(ThreadLocalSequence.next());
424 }
425
426 @Benchmark
427 public int Threads1_ThreadLocalSequenceMix_nextInt() {
428 return mixInt(ThreadLocalSequence.next());
429 }
430
431 @Benchmark
432 public long Threads1_Random_nextLong() {
433 return random.nextLong();
434 }
435
436 @Benchmark
437 public int Threads1_Random_nextInt() {
438 return random.nextInt();
439 }
440
441 @Benchmark
442 public long Threads1_SyncSplitMix_nextLong() {
443 return mixLong(state.getAndAdd(GOLDEN_GAMMA));
444 }
445
446 @Benchmark
447 public int Threads1_SyncSplitMix_nextInt() {
448 return mixInt(state.getAndAdd(GOLDEN_GAMMA));
449 }
450
451 @Benchmark
452 public int Threads1_Sync_XoRoShiRo128Plus_nextInt() {
453 return nextInt(xoRoShiRo128Plus);
454 }
455
456 @Benchmark
457 public int Threads1_Sync_XorShift1024StarPhi_nextInt() {
458 return nextInt(xorShift1024StarPhi);
459 }
460
461 @Benchmark
462 public int Threads1_Sync_Well44497b_nextInt() {
463 return nextInt(well44497b);
464 }
465
466 @Benchmark
467 public long Threads1_Sync_XoRoShiRo128Plus_nextLong() {
468 return nextLong(xoRoShiRo128Plus);
469 }
470
471 @Benchmark
472 public long Threads1_Sync_XorShift1024StarPhi_nextLong() {
473 return nextLong(xorShift1024StarPhi);
474 }
475
476 @Benchmark
477 public long Threads1_Sync_Well44497b_nextLong() {
478 return nextLong(well44497b);
479 }
480
481 @Benchmark
482 public int Threads1_UnfairLock_XoRoShiRo128Plus_nextInt() {
483 return nextInt(UNFAIR_LOCK, xoRoShiRo128Plus);
484 }
485
486 @Benchmark
487 public int Threads1_UnfairLock_XorShift1024StarPhi_nextInt() {
488 return nextInt(UNFAIR_LOCK, xorShift1024StarPhi);
489 }
490
491 @Benchmark
492 public int Threads1_UnfairLock_Well44497b_nextInt() {
493 return nextInt(UNFAIR_LOCK, well44497b);
494 }
495
496 @Benchmark
497 public long Threads1_UnfairLock_XoRoShiRo128Plus_nextLong() {
498 return nextLong(UNFAIR_LOCK, xoRoShiRo128Plus);
499 }
500
501 @Benchmark
502 public long Threads1_UnfairLock_XorShift1024StarPhi_nextLong() {
503 return nextLong(UNFAIR_LOCK, xorShift1024StarPhi);
504 }
505
506 @Benchmark
507 public long Threads1_UnfairLock_Well44497b_nextLong() {
508 return nextLong(UNFAIR_LOCK, well44497b);
509 }
510
511 @Benchmark
512 public int Threads1_FairLock_XoRoShiRo128Plus_nextInt() {
513 return nextInt(FAIR_LOCK, xoRoShiRo128Plus);
514 }
515
516 @Benchmark
517 public int Threads1_FairLock_XorShift1024StarPhi_nextInt() {
518 return nextInt(FAIR_LOCK, xorShift1024StarPhi);
519 }
520
521 @Benchmark
522 public int Threads1_FairLock_Well44497b_nextInt() {
523 return nextInt(FAIR_LOCK, well44497b);
524 }
525
526 @Benchmark
527 public long Threads1_FairLock_XoRoShiRo128Plus_nextLong() {
528 return nextLong(FAIR_LOCK, xoRoShiRo128Plus);
529 }
530
531 @Benchmark
532 public long Threads1_FairLock_XorShift1024StarPhi_nextLong() {
533 return nextLong(FAIR_LOCK, xorShift1024StarPhi);
534 }
535
536 @Benchmark
537 public long Threads1_FairLock_Well44497b_nextLong() {
538 return nextLong(FAIR_LOCK, well44497b);
539 }
540
541 @Benchmark
542 public int Threads1_volatileInt_increment() {
543 return ++volatileIntValue;
544 }
545
546 @Benchmark
547 public long Threads1_volatileLong_increment() {
548 return ++volatileLongValue;
549 }
550
551 @Benchmark
552 public int Threads1_AtomicInt_getAndIncrement() {
553 return atomicInt.getAndIncrement();
554 }
555
556 @Benchmark
557 public long Threads1_AtomicLong_getAndIncrement() {
558 return atomicLong.getAndIncrement();
559 }
560
561 @Benchmark
562 @Threads(4)
563 public int Threads4_SeedFactory_createInt() {
564 return SeedFactory.createInt();
565 }
566
567 @Benchmark
568 @Threads(4)
569 public long Threads4_SeedFactory_createLong() {
570 return SeedFactory.createLong();
571 }
572
573 @Benchmark
574 @Threads(4)
575 public long Threads4_System_currentTimeMillis() {
576
577 return System.currentTimeMillis();
578 }
579
580 @Benchmark
581 @Threads(4)
582 public long Threads4_System_nanoTime() {
583
584 return System.nanoTime();
585 }
586
587 @Benchmark
588 @Threads(4)
589 public int Threads4_System_identityHashCode() {
590 return System.identityHashCode(new Object());
591 }
592
593 @Benchmark
594 @Threads(4)
595 public long Threads4_ThreadLocalRandom_nextLong() {
596 return ThreadLocalRandom.current().nextLong();
597 }
598
599 @Benchmark
600 @Threads(4)
601 public int Threads4_ThreadLocalRandom_nextInt() {
602 return ThreadLocalRandom.current().nextInt();
603 }
604
605 @Benchmark
606 @Threads(4)
607 public long Threads4_ThreadLocalRNG_nextLong() {
608 return ThreadLocalRNG.current().nextLong();
609 }
610
611 @Benchmark
612 @Threads(4)
613 public int Threads4_ThreadLocalRNG_nextInt() {
614 return ThreadLocalRNG.current().nextInt();
615 }
616
617 @Benchmark
618 @Threads(4)
619 public long Threads4_ThreadLocalSplitMix_nextLong() {
620 return ThreadLocalSplitMix.current().nextLong();
621 }
622
623 @Benchmark
624 @Threads(4)
625 public int Threads4_ThreadLocalSplitMix_nextInt() {
626 return ThreadLocalSplitMix.current().nextInt();
627 }
628
629 @Benchmark
630 @Threads(4)
631 public long Threads4_ThreadLocalSequenceMix_nextLong() {
632 return mixLong(ThreadLocalSequence.next());
633 }
634
635 @Benchmark
636 @Threads(4)
637 public int Threads4_ThreadLocalSequenceMix_nextInt() {
638 return mixInt(ThreadLocalSequence.next());
639 }
640
641 @Benchmark
642 @Threads(4)
643 public long Threads4_Random_nextLong() {
644 return random.nextLong();
645 }
646
647 @Benchmark
648 @Threads(4)
649 public int Threads4_Random_nextInt() {
650 return random.nextInt();
651 }
652
653 @Benchmark
654 @Threads(4)
655 public long Threads4_SyncSplitMix_nextLong() {
656 return mixLong(state.getAndAdd(GOLDEN_GAMMA));
657 }
658
659 @Benchmark
660 @Threads(4)
661 public int Threads4_SyncSplitMix_nextInt() {
662 return mixInt(state.getAndAdd(GOLDEN_GAMMA));
663 }
664
665 @Benchmark
666 @Threads(4)
667 public int Threads4_Sync_XoRoShiRo128Plus_nextInt() {
668 return nextInt(xoRoShiRo128Plus);
669 }
670
671 @Benchmark
672 @Threads(4)
673 public int Threads4_Sync_XorShift1024StarPhi_nextInt() {
674 return nextInt(xorShift1024StarPhi);
675 }
676
677 @Benchmark
678 @Threads(4)
679 public int Threads4_Sync_Well44497b_nextInt() {
680 return nextInt(well44497b);
681 }
682
683 @Benchmark
684 @Threads(4)
685 public long Threads4_Sync_XoRoShiRo128Plus_nextLong() {
686 return nextLong(xoRoShiRo128Plus);
687 }
688
689 @Benchmark
690 @Threads(4)
691 public long Threads4_Sync_XorShift1024StarPhi_nextLong() {
692 return nextLong(xorShift1024StarPhi);
693 }
694
695 @Benchmark
696 @Threads(4)
697 public long Threads4_Sync_Well44497b_nextLong() {
698 return nextLong(well44497b);
699 }
700
701 @Benchmark
702 @Threads(4)
703 public int Threads4_UnfairLock_XoRoShiRo128Plus_nextInt() {
704 return nextInt(UNFAIR_LOCK, xoRoShiRo128Plus);
705 }
706
707 @Benchmark
708 @Threads(4)
709 public int Threads4_UnfairLock_XorShift1024StarPhi_nextInt() {
710 return nextInt(UNFAIR_LOCK, xorShift1024StarPhi);
711 }
712
713 @Benchmark
714 @Threads(4)
715 public int Threads4_UnfairLock_Well44497b_nextInt() {
716 return nextInt(UNFAIR_LOCK, well44497b);
717 }
718
719 @Benchmark
720 @Threads(4)
721 public long Threads4_UnfairLock_XoRoShiRo128Plus_nextLong() {
722 return nextLong(UNFAIR_LOCK, xoRoShiRo128Plus);
723 }
724
725 @Benchmark
726 @Threads(4)
727 public long Threads4_UnfairLock_XorShift1024StarPhi_nextLong() {
728 return nextLong(UNFAIR_LOCK, xorShift1024StarPhi);
729 }
730
731 @Benchmark
732 @Threads(4)
733 public long Threads4_UnfairLock_Well44497b_nextLong() {
734 return nextLong(UNFAIR_LOCK, well44497b);
735 }
736
737 @Benchmark
738 @Threads(4)
739 public int Threads4_FairLock_XoRoShiRo128Plus_nextInt() {
740 return nextInt(FAIR_LOCK, xoRoShiRo128Plus);
741 }
742
743 @Benchmark
744 @Threads(4)
745 public int Threads4_FairLock_XorShift1024StarPhi_nextInt() {
746 return nextInt(FAIR_LOCK, xorShift1024StarPhi);
747 }
748
749 @Benchmark
750 @Threads(4)
751 public int Threads4_FairLock_Well44497b_nextInt() {
752 return nextInt(FAIR_LOCK, well44497b);
753 }
754
755 @Benchmark
756 @Threads(4)
757 public long Threads4_FairLock_XoRoShiRo128Plus_nextLong() {
758 return nextLong(FAIR_LOCK, xoRoShiRo128Plus);
759 }
760
761 @Benchmark
762 @Threads(4)
763 public long Threads4_FairLock_XorShift1024StarPhi_nextLong() {
764 return nextLong(FAIR_LOCK, xorShift1024StarPhi);
765 }
766
767 @Benchmark
768 @Threads(4)
769 public long Threads4_FairLock_Well44497b_nextLong() {
770 return nextLong(FAIR_LOCK, well44497b);
771 }
772
773 @Benchmark
774 @Threads(4)
775 public int Threads4_volatileInt_increment() {
776 return ++volatileIntValue;
777 }
778
779 @Benchmark
780 @Threads(4)
781 public long Threads4_volatileLong_increment() {
782 return ++volatileLongValue;
783 }
784
785 @Benchmark
786 @Threads(4)
787 public int Threads4_AtomicInt_getAndIncrement() {
788 return atomicInt.getAndIncrement();
789 }
790
791 @Benchmark
792 @Threads(4)
793 public long Threads4_AtomicLong_getAndIncrement() {
794 return atomicLong.getAndIncrement();
795 }
796 }