View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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.simple.RandomSource;
22  import org.openjdk.jmh.annotations.Benchmark;
23  import org.openjdk.jmh.annotations.BenchmarkMode;
24  import org.openjdk.jmh.annotations.Fork;
25  import org.openjdk.jmh.annotations.Measurement;
26  import org.openjdk.jmh.annotations.Mode;
27  import org.openjdk.jmh.annotations.OutputTimeUnit;
28  import org.openjdk.jmh.annotations.Param;
29  import org.openjdk.jmh.annotations.Scope;
30  import org.openjdk.jmh.annotations.Setup;
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.concurrent.TimeUnit;
36  import java.util.concurrent.locks.Lock;
37  import java.util.concurrent.locks.ReentrantLock;
38  
39  /**
40   * Executes a benchmark to compare the speed of generating an array of {@code int/long} values
41   * in a thread-safe way.
42   *
43   * <p>Uses an upper limit of 128 for the size of an array seed.</p>
44   */
45  @BenchmarkMode(Mode.AverageTime)
46  @OutputTimeUnit(TimeUnit.NANOSECONDS)
47  @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
48  @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
49  @State(Scope.Benchmark)
50  @Fork(value = 1, jvmArgs = { "-server", "-Xms512M", "-Xmx512M" })
51  public class SeedArrayGenerationPerformance {
52      /**
53       * The lock to own when using the generator. This lock is unfair and there is no
54       * particular access order for waiting threads.
55       *
56       * <p>This is used as an alternative to {@code synchronized} statements.</p>
57       */
58      private static final ReentrantLock UNFAIR_LOCK = new ReentrantLock(false);
59  
60      /**
61       * The lock to own when using the generator. This lock is fair and the longest waiting
62       * thread will be favoured.
63       *
64       * <p>This is used as an alternative to {@code synchronized} statements.</p>
65       */
66      private static final ReentrantLock FAIR_LOCK = new ReentrantLock(true);
67  
68      /** The int[] value. Must NOT be final to prevent JVM optimisation! */
69      private int[] intValue;
70  
71      /** The long[] value. Must NOT be final to prevent JVM optimisation! */
72      private long[] longValue;
73  
74      /**
75       * The RandomSource to test.
76       */
77      @State(Scope.Benchmark)
78      public static class SeedRandomSources {
79          /**
80           * RNG providers to test.
81           * For seed generation only long period generators should be considered.
82           */
83          @Param({"WELL_44497_B",
84                  "XOR_SHIFT_1024_S_PHI"})
85          private String randomSourceName;
86  
87          /** RNG. */
88          private UniformRandomProvider generator;
89  
90          /**
91           * Gets the generator.
92           *
93           * @return the RNG.
94           */
95          public UniformRandomProvider getGenerator() {
96              return generator;
97          }
98  
99          /**
100          * Look-up the {@link RandomSource} from the name and instantiates the generator.
101          */
102         @Setup
103         public void setup() {
104             generator = RandomSource.valueOf(randomSourceName).create();
105         }
106     }
107 
108     /**
109      * The number of values that are required to seed a generator.
110      */
111     @State(Scope.Benchmark)
112     public static class SeedSizes {
113         /** The number of values. */
114         @Param({"2", "4", "8", "16", "32", "64", "128"})
115         private int size;
116 
117         /**
118          * Gets the number of {@code int} values required.
119          *
120          * @return the size
121          */
122         public int getSize() {
123             return size;
124         }
125     }
126 
127     /**
128      * Define the number of seed values to create and the number to compute per synchronisation on
129      * the generator.
130      */
131     @State(Scope.Benchmark)
132     public static class TestSizes {
133         /** The number of values. */
134         @Param({"2", "4", "8", "16", "32", "64", "128"})
135         private int size;
136 
137         /** The block size is the number of values to compute per synchronisation on the generator. */
138         @Param({"2", "4", "8", "16", "32", "64", "128"})
139         private int blockSize;
140 
141         /**
142          * Gets the number of {@code int} values required.
143          *
144          * @return the size
145          */
146         public int getSize() {
147             return size;
148         }
149 
150         /**
151          * @return the block size
152          */
153         public int getBlockSize() {
154             return blockSize;
155         }
156 
157         /**
158          * Verify the size parameters. This throws an exception if the block size exceeds the seed
159          * size as the test is redundant. JMH will catch the exception and run the next benchmark.
160          */
161         @Setup
162         public void setup() {
163             if (getBlockSize() > getSize()) {
164                 throw new AssertionError("Skipping benchmark: Block size is above seed size");
165             }
166         }
167     }
168 
169     /**
170      * Get the next {@code int} from the RNG. This is synchronized on the generator.
171      *
172      * @param rng Random generator.
173      * @return the int
174      */
175     private static int nextInt(UniformRandomProvider rng) {
176         synchronized (rng) {
177             return rng.nextInt();
178         }
179     }
180 
181     /**
182      * Get the next {@code long} from the RNG. This is synchronized on the generator.
183      *
184      * @param rng Random generator.
185      * @return the long
186      */
187     private static long nextLong(UniformRandomProvider rng) {
188         synchronized (rng) {
189             return rng.nextLong();
190         }
191     }
192 
193     /**
194      * Fill the array between {@code start} inclusive and {@code end} exclusive from the RNG.
195      * This is synchronized on the generator.
196      *
197      * @param rng Random generator.
198      * @param array Array data.
199      * @param start Start (inclusive).
200      * @param end End (exclusive).
201      */
202     private static void nextInt(UniformRandomProvider rng, int[] array, int start, int end) {
203         synchronized (rng) {
204             for (int i = start; i < end; i++) {
205                 array[i] = rng.nextInt();
206             }
207         }
208     }
209 
210     /**
211      * Fill the array between {@code start} inclusive and {@code end} exclusive from the
212      * RNG. This is synchronized on the generator.
213      *
214      * @param rng Random generator.
215      * @param array Array data.
216      * @param start Start (inclusive).
217      * @param end End (exclusive).
218      */
219     private static void nextLong(UniformRandomProvider rng, long[] array, int start, int end) {
220         synchronized (rng) {
221             for (int i = start; i < end; i++) {
222                 array[i] = rng.nextLong();
223             }
224         }
225     }
226 
227     /**
228      * Get the next {@code int} from the RNG. The lock is used to guard access to the generator.
229      *
230      * @param lock Lock guarding access to the generator.
231      * @param rng Random generator.
232      * @return the int
233      */
234     private static int nextInt(Lock lock, UniformRandomProvider rng) {
235         lock.lock();
236         try {
237             return rng.nextInt();
238         } finally {
239             lock.unlock();
240         }
241     }
242 
243     /**
244      * Get the next {@code long} from the RNG. The lock is used to guard access to the generator.
245      *
246      * @param lock Lock guarding access to the generator.
247      * @param rng Random generator.
248      * @return the long
249      */
250     private static long nextLong(Lock lock, UniformRandomProvider rng) {
251         lock.lock();
252         try {
253             return rng.nextLong();
254         } finally {
255             lock.unlock();
256         }
257     }
258 
259     /**
260      * Fill the array between {@code start} inclusive and {@code end} exclusive from the RNG.
261      * The lock is used to guard access to the generator.
262      *
263      * @param lock Lock guarding access to the generator.
264      * @param rng Random generator.
265      * @param array Array data.
266      * @param start Start (inclusive).
267      * @param end End (exclusive).
268      */
269     private static void nextInt(Lock lock, UniformRandomProvider rng, int[] array, int start, int end) {
270         lock.lock();
271         try {
272             for (int i = start; i < end; i++) {
273                 array[i] = rng.nextInt();
274             }
275         } finally {
276             lock.unlock();
277         }
278     }
279 
280     /**
281      * Fill the array between {@code start} inclusive and {@code end} exclusive from the RNG.
282      * The lock is used to guard access to the generator.
283      *
284      * @param lock Lock guarding access to the generator.
285      * @param rng Random generator.
286      * @param array Array data.
287      * @param start Start (inclusive).
288      * @param end End (exclusive).
289      */
290     private static void nextLong(Lock lock, UniformRandomProvider rng, long[] array, int start, int end) {
291         lock.lock();
292         try {
293             for (int i = start; i < end; i++) {
294                 array[i] = rng.nextLong();
295             }
296         } finally {
297             lock.unlock();
298         }
299     }
300 
301     /**
302      * Baseline for a JMH method call with no return value.
303      */
304     @Benchmark
305     public void baselineVoid() {
306         // Do nothing, this is a baseline
307     }
308 
309     /**
310      * Baseline for a JMH method call returning an {@code int[]}.
311      *
312      * @return the value
313      */
314     @Benchmark
315     public int[] baselineIntArray() {
316         return intValue;
317     }
318 
319     /**
320      * Baseline for a JMH method call returning an {@code long[]}.
321      *
322      * @return the value
323      */
324     @Benchmark
325     public long[] baselineLongArray() {
326         return longValue;
327     }
328 
329     // The following methods use underscores to make parsing the results output easier.
330     // They are not documented as the names are self-documenting.
331 
332     // CHECKSTYLE: stop MethodName
333 
334     /**
335      * @param sources Source of randomness.
336      * @param sizes Size of the seed.
337      * @return the seed
338      */
339     @Benchmark
340     public int[] createIntArraySeed(SeedRandomSources sources, SeedSizes sizes) {
341         final UniformRandomProvider rng = sources.getGenerator();
342         final int[] seed = new int[sizes.getSize()];
343         for (int i = 0; i < seed.length; i++) {
344             seed[i] = rng.nextInt();
345         }
346         return seed;
347     }
348 
349     /**
350      * @param sources Source of randomness.
351      * @param sizes Size of the seed.
352      * @return the seed
353      */
354     @Benchmark
355     public long[] createLongArraySeed(SeedRandomSources sources, SeedSizes sizes) {
356         final UniformRandomProvider rng = sources.getGenerator();
357         final long[] seed = new long[sizes.getSize()];
358         for (int i = 0; i < seed.length; i++) {
359             seed[i] = rng.nextLong();
360         }
361         return seed;
362     }
363 
364     /**
365      * @param sources Source of randomness.
366      * @param sizes Size of the seed.
367      * @return the seed
368      */
369     @Benchmark
370     public int[] Threads1_createIntArraySeed_Sync(SeedRandomSources sources, SeedSizes sizes) {
371         final UniformRandomProvider rng = sources.getGenerator();
372         final int[] seed = new int[sizes.getSize()];
373         for (int i = 0; i < seed.length; i++) {
374             seed[i] = nextInt(rng);
375         }
376         return seed;
377     }
378 
379     /**
380      * @param sources Source of randomness.
381      * @param sizes Size of the seed.
382      * @return the seed
383      */
384     @Benchmark
385     public long[] Threads1_createLongArraySeed_Sync(SeedRandomSources sources, SeedSizes sizes) {
386         final UniformRandomProvider rng = sources.getGenerator();
387         final long[] seed = new long[sizes.getSize()];
388         for (int i = 0; i < seed.length; i++) {
389             seed[i] = nextLong(rng);
390         }
391         return seed;
392     }
393 
394     /**
395      * @param sources Source of randomness.
396      * @param sizes Size of the seed.
397      * @return the seed
398      */
399     @Benchmark
400     public int[] Threads1_createIntArraySeed_UnfairLock(SeedRandomSources sources, SeedSizes sizes) {
401         final UniformRandomProvider rng = sources.getGenerator();
402         final int[] seed = new int[sizes.getSize()];
403         for (int i = 0; i < seed.length; i++) {
404             seed[i] = nextInt(UNFAIR_LOCK, rng);
405         }
406         return seed;
407     }
408 
409     /**
410      * @param sources Source of randomness.
411      * @param sizes Size of the seed.
412      * @return the seed
413      */
414     @Benchmark
415     public long[] Threads1_createLongArraySeed_UnfairLock(SeedRandomSources sources, SeedSizes sizes) {
416         final UniformRandomProvider rng = sources.getGenerator();
417         final long[] seed = new long[sizes.getSize()];
418         for (int i = 0; i < seed.length; i++) {
419             seed[i] = nextLong(UNFAIR_LOCK, rng);
420         }
421         return seed;
422     }
423 
424     /**
425      * @param sources Source of randomness.
426      * @param sizes Size of the seed.
427      * @return the seed
428      */
429     @Benchmark
430     public int[] Threads1_createIntArraySeed_FairLock(SeedRandomSources sources, SeedSizes sizes) {
431         final UniformRandomProvider rng = sources.getGenerator();
432         final int[] seed = new int[sizes.getSize()];
433         for (int i = 0; i < seed.length; i++) {
434             seed[i] = nextInt(FAIR_LOCK, rng);
435         }
436         return seed;
437     }
438 
439     /**
440      * @param sources Source of randomness.
441      * @param sizes Size of the seed.
442      * @return the seed
443      */
444     @Benchmark
445     public long[] Threads1_createLongArraySeed_FairLock(SeedRandomSources sources, SeedSizes sizes) {
446         final UniformRandomProvider rng = sources.getGenerator();
447         final long[] seed = new long[sizes.getSize()];
448         for (int i = 0; i < seed.length; i++) {
449             seed[i] = nextLong(FAIR_LOCK, rng);
450         }
451         return seed;
452     }
453 
454     /**
455      * @param sources Source of randomness.
456      * @param sizes Size of the seed and compute blocks.
457      * @return the seed
458      */
459     @Benchmark
460     public int[] Threads1_createIntArraySeedBlocks_Sync(SeedRandomSources sources, TestSizes sizes) {
461         final UniformRandomProvider rng = sources.getGenerator();
462         final int[] seed = new int[sizes.getSize()];
463         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
464             nextInt(rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
465         }
466         return seed;
467     }
468 
469     /**
470      * @param sources Source of randomness.
471      * @param sizes Size of the seed and compute blocks.
472      * @return the seed
473      */
474     @Benchmark
475     public long[] Threads1_createLongArraySeedBlocks_Sync(SeedRandomSources sources, TestSizes sizes) {
476         final UniformRandomProvider rng = sources.getGenerator();
477         final long[] seed = new long[sizes.getSize()];
478         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
479             nextLong(rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
480         }
481         return seed;
482     }
483 
484     /**
485      * @param sources Source of randomness.
486      * @param sizes Size of the seed and compute blocks.
487      * @return the seed
488      */
489     @Benchmark
490     public int[] Threads1_createIntArraySeedBlocks_UnfairLock(SeedRandomSources sources, TestSizes sizes) {
491         final UniformRandomProvider rng = sources.getGenerator();
492         final int[] seed = new int[sizes.getSize()];
493         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
494             nextInt(UNFAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
495         }
496         return seed;
497     }
498 
499     /**
500      * @param sources Source of randomness.
501      * @param sizes Size of the seed and compute blocks.
502      * @return the seed
503      */
504     @Benchmark
505     public long[] Threads1_createLongArraySeedBlocks_UnfairLock(SeedRandomSources sources, TestSizes sizes) {
506         final UniformRandomProvider rng = sources.getGenerator();
507         final long[] seed = new long[sizes.getSize()];
508         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
509             nextLong(UNFAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
510         }
511         return seed;
512     }
513 
514     /**
515      * @param sources Source of randomness.
516      * @param sizes Size of the seed and compute blocks.
517      * @return the seed
518      */
519     @Benchmark
520     public int[] Threads1_createIntArraySeedBlocks_FairLock(SeedRandomSources sources, TestSizes sizes) {
521         final UniformRandomProvider rng = sources.getGenerator();
522         final int[] seed = new int[sizes.getSize()];
523         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
524             nextInt(FAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
525         }
526         return seed;
527     }
528 
529     /**
530      * @param sources Source of randomness.
531      * @param sizes Size of the seed and compute blocks.
532      * @return the seed
533      */
534     @Benchmark
535     public long[] Threads1_createLongArraySeedBlocks_FairLock(SeedRandomSources sources, TestSizes sizes) {
536         final UniformRandomProvider rng = sources.getGenerator();
537         final long[] seed = new long[sizes.getSize()];
538         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
539             nextLong(FAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
540         }
541         return seed;
542     }
543 
544     /**
545      * @param sources Source of randomness.
546      * @param sizes Size of the seed.
547      * @return the seed
548      */
549     @Benchmark
550     @Threads(4)
551     public int[] Threads4_createIntArraySeed_Sync(SeedRandomSources sources, SeedSizes sizes) {
552         final UniformRandomProvider rng = sources.getGenerator();
553         final int[] seed = new int[sizes.getSize()];
554         for (int i = 0; i < seed.length; i++) {
555             seed[i] = nextInt(rng);
556         }
557         return seed;
558     }
559 
560     /**
561      * @param sources Source of randomness.
562      * @param sizes Size of the seed.
563      * @return the seed
564      */
565     @Benchmark
566     @Threads(4)
567     public long[] Threads4_createLongArraySeed_Sync(SeedRandomSources sources, SeedSizes sizes) {
568         final UniformRandomProvider rng = sources.getGenerator();
569         final long[] seed = new long[sizes.getSize()];
570         for (int i = 0; i < seed.length; i++) {
571             seed[i] = nextLong(rng);
572         }
573         return seed;
574     }
575 
576     /**
577      * @param sources Source of randomness.
578      * @param sizes Size of the seed.
579      * @return the seed
580      */
581     @Benchmark
582     @Threads(4)
583     public int[] Threads4_createIntArraySeed_UnfairLock(SeedRandomSources sources, SeedSizes sizes) {
584         final UniformRandomProvider rng = sources.getGenerator();
585         final int[] seed = new int[sizes.getSize()];
586         for (int i = 0; i < seed.length; i++) {
587             seed[i] = nextInt(UNFAIR_LOCK, rng);
588         }
589         return seed;
590     }
591 
592     /**
593      * @param sources Source of randomness.
594      * @param sizes Size of the seed.
595      * @return the seed
596      */
597     @Benchmark
598     @Threads(4)
599     public long[] Threads4_createLongArraySeed_UnfairLock(SeedRandomSources sources, SeedSizes sizes) {
600         final UniformRandomProvider rng = sources.getGenerator();
601         final long[] seed = new long[sizes.getSize()];
602         for (int i = 0; i < seed.length; i++) {
603             seed[i] = nextLong(UNFAIR_LOCK, rng);
604         }
605         return seed;
606     }
607 
608     /**
609      * @param sources Source of randomness.
610      * @param sizes Size of the seed.
611      * @return the seed
612      */
613     @Benchmark
614     @Threads(4)
615     public int[] Threads4_createIntArraySeed_FairLock(SeedRandomSources sources, SeedSizes sizes) {
616         final UniformRandomProvider rng = sources.getGenerator();
617         final int[] seed = new int[sizes.getSize()];
618         for (int i = 0; i < seed.length; i++) {
619             seed[i] = nextInt(FAIR_LOCK, rng);
620         }
621         return seed;
622     }
623 
624     /**
625      * @param sources Source of randomness.
626      * @param sizes Size of the seed.
627      * @return the seed
628      */
629     @Benchmark
630     @Threads(4)
631     public long[] Threads4_createLongArraySeed_FairLock(SeedRandomSources sources, SeedSizes sizes) {
632         final UniformRandomProvider rng = sources.getGenerator();
633         final long[] seed = new long[sizes.getSize()];
634         for (int i = 0; i < seed.length; i++) {
635             seed[i] = nextLong(FAIR_LOCK, rng);
636         }
637         return seed;
638     }
639 
640     /**
641      * @param sources Source of randomness.
642      * @param sizes Size of the seed and compute blocks.
643      * @return the seed
644      */
645     @Benchmark
646     @Threads(4)
647     public int[] Threads4_createIntArraySeedBlocks_Sync(SeedRandomSources sources, TestSizes sizes) {
648         final UniformRandomProvider rng = sources.getGenerator();
649         final int[] seed = new int[sizes.getSize()];
650         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
651             nextInt(rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
652         }
653         return seed;
654     }
655 
656     /**
657      * @param sources Source of randomness.
658      * @param sizes Size of the seed and compute blocks.
659      * @return the seed
660      */
661     @Benchmark
662     @Threads(4)
663     public long[] Threads4_createLongArraySeedBlocks_Sync(SeedRandomSources sources, TestSizes sizes) {
664         final UniformRandomProvider rng = sources.getGenerator();
665         final long[] seed = new long[sizes.getSize()];
666         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
667             nextLong(rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
668         }
669         return seed;
670     }
671 
672     /**
673      * @param sources Source of randomness.
674      * @param sizes Size of the seed and compute blocks.
675      * @return the seed
676      */
677     @Benchmark
678     @Threads(4)
679     public int[] Threads4_createIntArraySeedBlocks_UnfairLock(SeedRandomSources sources, TestSizes sizes) {
680         final UniformRandomProvider rng = sources.getGenerator();
681         final int[] seed = new int[sizes.getSize()];
682         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
683             nextInt(UNFAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
684         }
685         return seed;
686     }
687 
688     /**
689      * @param sources Source of randomness.
690      * @param sizes Size of the seed and compute blocks.
691      * @return the seed
692      */
693     @Benchmark
694     @Threads(4)
695     public long[] Threads4_createLongArraySeedBlocks_UnfairLock(SeedRandomSources sources, TestSizes sizes) {
696         final UniformRandomProvider rng = sources.getGenerator();
697         final long[] seed = new long[sizes.getSize()];
698         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
699             nextLong(UNFAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
700         }
701         return seed;
702     }
703 
704     /**
705      * @param sources Source of randomness.
706      * @param sizes Size of the seed and compute blocks.
707      * @return the seed
708      */
709     @Benchmark
710     @Threads(4)
711     public int[] Threads4_createIntArraySeedBlocks_FairLock(SeedRandomSources sources, TestSizes sizes) {
712         final UniformRandomProvider rng = sources.getGenerator();
713         final int[] seed = new int[sizes.getSize()];
714         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
715             nextInt(FAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
716         }
717         return seed;
718     }
719 
720     /**
721      * @param sources Source of randomness.
722      * @param sizes Size of the seed and compute blocks.
723      * @return the seed
724      */
725     @Benchmark
726     @Threads(4)
727     public long[] Threads4_createLongArraySeedBlocks_FairLock(SeedRandomSources sources, TestSizes sizes) {
728         final UniformRandomProvider rng = sources.getGenerator();
729         final long[] seed = new long[sizes.getSize()];
730         for (int i = 0; i < seed.length; i += sizes.getBlockSize()) {
731             nextLong(FAIR_LOCK, rng, seed, i, Math.min(i + sizes.getBlockSize(), seed.length));
732         }
733         return seed;
734     }
735 }