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.openjdk.jmh.annotations.Benchmark;
21  import org.openjdk.jmh.annotations.BenchmarkMode;
22  import org.openjdk.jmh.annotations.Mode;
23  import org.openjdk.jmh.annotations.Warmup;
24  import org.openjdk.jmh.annotations.Measurement;
25  import org.openjdk.jmh.annotations.State;
26  import org.openjdk.jmh.annotations.Threads;
27  import org.openjdk.jmh.annotations.Fork;
28  import org.openjdk.jmh.annotations.Scope;
29  import org.openjdk.jmh.annotations.Param;
30  import org.openjdk.jmh.annotations.Setup;
31  import org.openjdk.jmh.annotations.OutputTimeUnit;
32  
33  import java.util.concurrent.ThreadLocalRandom;
34  import java.util.concurrent.TimeUnit;
35  
36  import org.apache.commons.rng.UniformRandomProvider;
37  import org.apache.commons.rng.simple.RandomSource;
38  import org.apache.commons.rng.simple.ThreadLocalRandomSource;
39  
40  /**
41   * Executes benchmark to compare the speed of generation of low frequency
42   * random numbers on multiple-threads.
43   */
44  @BenchmarkMode(Mode.AverageTime)
45  @OutputTimeUnit(TimeUnit.NANOSECONDS)
46  @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
47  @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
48  @State(Scope.Benchmark)
49  @Fork(value = 1, jvmArgs = {"-server", "-Xms128M", "-Xmx128M"})
50  public class ThreadLocalPerformance {
51      /**
52       * Number of random values to generate.
53       */
54      @Param({"0", "1", "10", "100"})
55      private int numValues;
56  
57      /**
58       * The benchmark state (to retrieve the various "RandomSource"s).
59       */
60      @State(Scope.Benchmark)
61      public static class Sources {
62          /** The random source. */
63          protected RandomSource randomSource;
64  
65          /**
66           * RNG providers.
67           */
68          @Param({"SPLIT_MIX_64"})
69          private String randomSourceName;
70  
71          /**
72           * @return the random source
73           */
74          public RandomSource getRandomSource() {
75              return randomSource;
76          }
77  
78          /** Instantiates the random source. */
79          @Setup
80          public void setup() {
81              randomSource = RandomSource.valueOf(randomSourceName);
82          }
83      }
84  
85      /**
86       * The benchmark state (to retrieve the various "RandomSource"s thread locally).
87       */
88      @State(Scope.Benchmark)
89      public static class LocalSources extends Sources {
90          /** The thread-local random provider. */
91          private ThreadLocal<UniformRandomProvider> rng;
92  
93          /**
94           * @return the random number generator
95           */
96          public UniformRandomProvider getRNG() {
97              return rng.get();
98          }
99  
100         /** Instantiates the ThreadLocal holding the random source. */
101         @Override
102         @Setup
103         public void setup() {
104             super.setup();
105 
106             rng = new ThreadLocal<UniformRandomProvider>() {
107                 @Override
108                 protected UniformRandomProvider initialValue() {
109                     return RandomSource.create(randomSource);
110                 }
111             };
112         }
113     }
114 
115     /**
116      * @return the result
117      */
118     @Benchmark
119     @Threads(4)
120     public long threadLocalRandom() {
121         final ThreadLocalRandom rng = ThreadLocalRandom.current();
122         long result = 0;
123         for (int i = 0; i < numValues; i++) {
124             result = result ^ rng.nextLong();
125         }
126         return result;
127     }
128 
129     /**
130      * @return the result
131      */
132     @Benchmark
133     @Threads(4)
134     public long threadLocalRandomWrapped() {
135         final ThreadLocalRandom rand = ThreadLocalRandom.current();
136         final UniformRandomProvider rng = new UniformRandomProvider() {
137             // CHECKSTYLE: stop all
138             @Override
139             public void nextBytes(byte[] bytes) { /* Ignore this. */ }
140             @Override
141             public void nextBytes(byte[] bytes, int start, int len) { /* Ignore this. */ }
142             @Override
143             public int nextInt() { return rand.nextInt(); }
144             @Override
145             public int nextInt(int n) { return rand.nextInt(n); }
146             @Override
147             public long nextLong() { return rand.nextLong(); }
148             @Override
149             public long nextLong(long n) { return rand.nextLong(n); }
150             @Override
151             public boolean nextBoolean() { return rand.nextBoolean(); }
152             @Override
153             public float nextFloat() { return rand.nextFloat(); }
154             @Override
155             public double nextDouble() { return rand.nextDouble(); }
156             // CHECKSTYLE: resume all
157         };
158         long result = 0;
159         for (int i = 0; i < numValues; i++) {
160             result = result ^ rng.nextLong();
161         }
162         return result;
163     }
164 
165     /**
166      * @param sources Source of randomness.
167      * @return the result
168      */
169     @Benchmark
170     @Threads(4)
171     public long randomSourceCreate(Sources sources) {
172         final UniformRandomProvider rng = RandomSource.create(sources.getRandomSource());
173         long result = 0;
174         for (int i = 0; i < numValues; i++) {
175             result = result ^ rng.nextLong();
176         }
177         return result;
178     }
179 
180     /**
181      * @param sources Source of randomness.
182      * @return the result
183      */
184     @Benchmark
185     @Threads(4)
186     public long threadLocalRandomSourceCurrent(Sources sources) {
187         final UniformRandomProvider rng = ThreadLocalRandomSource.current(sources.getRandomSource());
188         long result = 0;
189         for (int i = 0; i < numValues; i++) {
190             result = result ^ rng.nextLong();
191         }
192         return result;
193     }
194 
195     /**
196      * @param localSources Local source of randomness.
197      * @return the result
198      */
199     @Benchmark
200     @Threads(4)
201     public long threadLocalUniformRandomProvider(LocalSources localSources) {
202         final UniformRandomProvider rng = localSources.getRNG();
203         long result = 0;
204         for (int i = 0; i < numValues; i++) {
205             result = result ^ rng.nextLong();
206         }
207         return result;
208     }
209 }