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.distribution;
19
20 import java.util.concurrent.TimeUnit;
21
22 import org.apache.commons.rng.RandomProviderState;
23 import org.apache.commons.rng.RestorableUniformRandomProvider;
24 import org.apache.commons.rng.UniformRandomProvider;
25 import org.apache.commons.rng.sampling.PermutationSampler;
26 import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
27 import org.apache.commons.rng.sampling.distribution.PoissonSampler;
28 import org.apache.commons.rng.sampling.distribution.PoissonSamplerCache;
29 import org.apache.commons.rng.simple.RandomSource;
30 import org.openjdk.jmh.annotations.Benchmark;
31 import org.openjdk.jmh.annotations.BenchmarkMode;
32 import org.openjdk.jmh.annotations.Fork;
33 import org.openjdk.jmh.annotations.Measurement;
34 import org.openjdk.jmh.annotations.Mode;
35 import org.openjdk.jmh.annotations.OutputTimeUnit;
36 import org.openjdk.jmh.annotations.Param;
37 import org.openjdk.jmh.annotations.Scope;
38 import org.openjdk.jmh.annotations.Setup;
39 import org.openjdk.jmh.annotations.State;
40 import org.openjdk.jmh.annotations.Warmup;
41 import org.openjdk.jmh.infra.Blackhole;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 @BenchmarkMode(Mode.AverageTime)
112 @OutputTimeUnit(TimeUnit.MICROSECONDS)
113 @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
114 @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
115 @State(Scope.Benchmark)
116 @Fork(value = 1, jvmArgs = { "-server", "-Xms128M", "-Xmx128M" })
117 public class PoissonSamplerCachePerformance {
118
119 private static final int NUM_SAMPLES = 100000;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 private static final int RANGE_SAMPLE_SIZE = 4099;
136
137 private static final int SEED_SIZE = 128;
138
139
140
141
142
143 private static final int[] SEED;
144
145
146
147
148
149
150
151
152
153
154 private static final double[] RANGE_SAMPLE;
155
156 static {
157
158 SEED = new int[SEED_SIZE];
159 final UniformRandomProvider rng = RandomSource.create(RandomSource.MWC_256);
160 for (int i = 0; i < SEED.length; i++) {
161 SEED[i] = rng.nextInt();
162 }
163
164 final int size = RANGE_SAMPLE_SIZE;
165 final int[] sample = PermutationSampler.natural(size);
166 PermutationSampler.shuffle(rng, sample);
167
168 RANGE_SAMPLE = new double[size];
169 for (int i = 0; i < size; i++) {
170
171
172
173
174 RANGE_SAMPLE[i] = (double) sample[i] / size;
175 }
176 }
177
178
179
180
181 @State(Scope.Benchmark)
182 public static class Sources {
183
184
185
186
187
188
189
190
191 @Param({ "SPLIT_MIX_64",
192
193
194 })
195 private String randomSourceName;
196
197
198 private RestorableUniformRandomProvider generator;
199
200
201
202
203
204 private RandomProviderState state;
205
206
207
208
209 public UniformRandomProvider getGenerator() {
210 generator.restoreState(state);
211 return generator;
212 }
213
214
215 @Setup
216 public void setup() {
217 final RandomSource randomSource = RandomSource
218 .valueOf(randomSourceName);
219
220 generator = RandomSource.create(randomSource, SEED.clone());
221 state = generator.saveState();
222 }
223 }
224
225
226
227
228 @State(Scope.Benchmark)
229 public static class MeanRange {
230
231
232
233
234
235
236 @Param({ "1", "4", "16", "64", "256", "1024", "4096"})
237 private double range;
238
239
240
241
242
243
244
245 public double getMean(int i) {
246 return getMin() + RANGE_SAMPLE[i % RANGE_SAMPLE.length] * range;
247 }
248
249
250
251
252
253
254 public double getMin() {
255 return PoissonSamplerCache.getMinimumCachedMean();
256 }
257
258
259
260
261
262
263 public double getMax() {
264 return getMin() + range;
265 }
266 }
267
268
269
270
271 private interface PoissonSamplerFactory {
272
273
274
275
276
277
278 DiscreteSampler createPoissonSampler(double mean);
279 }
280
281
282
283
284
285
286
287
288 private static void runSample(PoissonSamplerFactory factory,
289 MeanRange range,
290 Blackhole bh) {
291 for (int i = 0; i < NUM_SAMPLES; i++) {
292 bh.consume(factory.createPoissonSampler(range.getMean(i)).sample());
293 }
294 }
295
296
297
298
299
300
301
302
303 @Benchmark
304 public void runPoissonSampler(Sources sources,
305 MeanRange range,
306 Blackhole bh) {
307 final UniformRandomProvider r = sources.getGenerator();
308 final PoissonSamplerFactory factory = new PoissonSamplerFactory() {
309 @Override
310 public DiscreteSampler createPoissonSampler(double mean) {
311 return new PoissonSampler(r, mean);
312 }
313 };
314 runSample(factory, range, bh);
315 }
316
317
318
319
320
321
322 @Benchmark
323 public void runPoissonSamplerCacheWhenEmpty(Sources sources,
324 MeanRange range,
325 Blackhole bh) {
326 final UniformRandomProvider r = sources.getGenerator();
327 final PoissonSamplerCache cache = new PoissonSamplerCache(0, 0);
328 final PoissonSamplerFactory factory = new PoissonSamplerFactory() {
329 @Override
330 public DiscreteSampler createPoissonSampler(double mean) {
331 return cache.createPoissonSampler(r, mean);
332 }
333 };
334 runSample(factory, range, bh);
335 }
336
337
338
339
340
341
342 @Benchmark
343 public void runPoissonSamplerCache(Sources sources,
344 MeanRange range,
345 Blackhole bh) {
346 final UniformRandomProvider r = sources.getGenerator();
347 final PoissonSamplerCache cache = new PoissonSamplerCache(
348 range.getMin(), range.getMax());
349 final PoissonSamplerFactory factory = new PoissonSamplerFactory() {
350 @Override
351 public DiscreteSampler createPoissonSampler(double mean) {
352 return cache.createPoissonSampler(r, mean);
353 }
354 };
355 runSample(factory, range, bh);
356 }
357 }