Skip to content

Commit 8009462

Browse files
committed
RNG-189: Add arbitrary jump JMH benchmark
1 parent 6299f15 commit 8009462

1 file changed

Lines changed: 86 additions & 3 deletions

File tree

  • commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core

commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919

2020
import java.util.concurrent.TimeUnit;
2121
import java.util.function.Supplier;
22+
import java.util.function.ToLongFunction;
23+
import org.apache.commons.rng.ArbitrarilyJumpableUniformRandomProvider;
2224
import org.apache.commons.rng.JumpableUniformRandomProvider;
2325
import org.apache.commons.rng.LongJumpableUniformRandomProvider;
2426
import org.apache.commons.rng.UniformRandomProvider;
27+
import org.apache.commons.rng.core.source32.IntProvider;
2528
import org.apache.commons.rng.simple.RandomSource;
2629
import org.openjdk.jmh.annotations.Benchmark;
2730
import org.openjdk.jmh.annotations.BenchmarkMode;
@@ -50,6 +53,13 @@ public class JumpBenchmark {
5053
*/
5154
@State(Scope.Benchmark)
5255
public abstract static class BaseJumpableSource {
56+
/**
57+
* Distance to skip before jumping.
58+
* Used to advance the state of a generator before repeat jumps.
59+
*/
60+
@Param({"0"})
61+
private int skip;
62+
5363
/** The generator of the next RNG copy from a jump. */
5464
private Supplier<UniformRandomProvider> gen;
5565

@@ -70,6 +80,27 @@ public void setup() {
7080
gen = createJumpFunction();
7181
}
7282

83+
/**
84+
* Creates the RNG.
85+
*
86+
* @param randomSourceName the random source name
87+
* @return the RNG
88+
*/
89+
UniformRandomProvider createRNG(String randomSourceName) {
90+
final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create();
91+
if (skip > 0) {
92+
// Skip the primary output of the generator.
93+
// Assumes either 32-bit or 64-bit output.
94+
final ToLongFunction<UniformRandomProvider> fun = rng instanceof IntProvider ?
95+
UniformRandomProvider::nextInt :
96+
UniformRandomProvider::nextLong;
97+
for (int i = skip; --i >= 0;) {
98+
fun.applyAsLong(rng);
99+
}
100+
}
101+
return rng;
102+
}
103+
73104
/**
74105
* Creates the jump function.
75106
* The jump will copy the RNG and then move forward the state of the source
@@ -124,7 +155,7 @@ public static class JumpableSource extends BaseJumpableSource {
124155
/** {@inheritDoc} */
125156
@Override
126157
protected Supplier<UniformRandomProvider> createJumpFunction() {
127-
final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create();
158+
final UniformRandomProvider rng = createRNG(randomSourceName);
128159
if (rng instanceof JumpableUniformRandomProvider) {
129160
return ((JumpableUniformRandomProvider) rng)::jump;
130161
}
@@ -172,14 +203,55 @@ public static class LongJumpableSource extends BaseJumpableSource {
172203
/** {@inheritDoc} */
173204
@Override
174205
protected Supplier<UniformRandomProvider> createJumpFunction() {
175-
final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create();
206+
final UniformRandomProvider rng = createRNG(randomSourceName);
176207
if (rng instanceof LongJumpableUniformRandomProvider) {
177208
return ((LongJumpableUniformRandomProvider) rng)::longJump;
178209
}
179210
throw new IllegalStateException("Invalid long jump source: " + randomSourceName);
180211
}
181212
}
182213

214+
/**
215+
* Exercise the {@link ArbitrarilyJumpableUniformRandomProvider#jump(double)} function,
216+
* or the {@link ArbitrarilyJumpableUniformRandomProvider#jumpPowerOfTwo(int)} function.
217+
*
218+
* <p>The power-of-two jump function is called if the distance is an exact {@code int} value.
219+
*
220+
* <p>To jump a small arbitrary amount specify the distance with a fractional component,
221+
* e.g. jump 123 using 123.5, otherwise a power-of-2 jump of 123 will be called.
222+
*/
223+
public static class ArbitrarilyJumpableSource extends BaseJumpableSource {
224+
/**
225+
* Select RNG providers.
226+
*/
227+
@Param({
228+
"PHILOX_4X32",
229+
"PHILOX_4X64"})
230+
private String randomSourceName;
231+
232+
/** Distance to jump.
233+
* Default: 2^99 + 2^49; 2^99 */
234+
@Param({"6.338253001141153E29", "99"})
235+
private double distance;
236+
237+
/** {@inheritDoc} */
238+
@Override
239+
protected Supplier<UniformRandomProvider> createJumpFunction() {
240+
final UniformRandomProvider rng = createRNG(randomSourceName);
241+
if (rng instanceof ArbitrarilyJumpableUniformRandomProvider) {
242+
final ArbitrarilyJumpableUniformRandomProvider gen = (ArbitrarilyJumpableUniformRandomProvider) rng;
243+
// Switch to a power-of-2 jump if an int
244+
final int logDistance = (int) distance;
245+
if ((double) logDistance == distance) {
246+
return () -> gen.jumpPowerOfTwo(logDistance);
247+
}
248+
final double jumpDistance = Math.floor(distance);
249+
return () -> gen.jump(jumpDistance);
250+
}
251+
throw new IllegalStateException("Invalid arbitrary jump source: " + randomSourceName);
252+
}
253+
}
254+
183255
/**
184256
* Jump benchmark.
185257
*
@@ -194,11 +266,22 @@ public UniformRandomProvider jump(JumpableSource data) {
194266
/**
195267
* Long jump benchmark.
196268
*
197-
* @param data Source of the long jump
269+
* @param data Source of the jump
198270
* @return the copy
199271
*/
200272
@Benchmark
201273
public UniformRandomProvider longJump(LongJumpableSource data) {
202274
return data.jump();
203275
}
276+
277+
/**
278+
* Arbitrary jump benchmark.
279+
*
280+
* @param data Source of the jump
281+
* @return the copy
282+
*/
283+
@Benchmark
284+
public UniformRandomProvider arbitraryJump(ArbitrarilyJumpableSource data) {
285+
return data.jump();
286+
}
204287
}

0 commit comments

Comments
 (0)