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.sampling.distribution;
19
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.sampling.distribution.AliasMethodDiscreteSampler;
22 import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
23 import org.apache.commons.rng.simple.RandomSource;
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.Param;
31 import org.openjdk.jmh.annotations.Scope;
32 import org.openjdk.jmh.annotations.Setup;
33 import org.openjdk.jmh.annotations.State;
34 import org.openjdk.jmh.annotations.Warmup;
35
36 import java.util.concurrent.TimeUnit;
37
38 /**
39 * Executes benchmark to test the {@link AliasMethodDiscreteSampler} using different
40 * zero padding on the input probability distribution.
41 */
42 @BenchmarkMode(Mode.AverageTime)
43 @OutputTimeUnit(TimeUnit.NANOSECONDS)
44 @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
45 @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
46 @State(Scope.Benchmark)
47 @Fork(value = 1, jvmArgs = {"-server", "-Xms128M", "-Xmx128M"})
48 public class AliasMethodDiscreteSamplerPerformance {
49 /**
50 * The value.
51 *
52 * <p>This must NOT be final!</p>
53 */
54 private int value;
55
56 /**
57 * The discrete probability distribution and a sampler. Used to test the sample speed and
58 * construction speed of different sized distributions.
59 */
60 @State(Scope.Benchmark)
61 public static class DistributionData {
62 /**
63 * The distribution size.
64 */
65 @Param({"7", "8", "9", "15", "16", "17", "31", "32", "33", "63", "64", "65"})
66 private int size;
67
68 /**
69 * The sampler alpha parameter.
70 */
71 @Param({"-1", "0", "1", "2"})
72 private int alpha;
73
74 /** The probabilities. */
75 private double[] probabilities;
76
77 /** The sampler. */
78 private DiscreteSampler sampler;
79
80 /**
81 * @return the alpha.
82 */
83 public int getAlpha() {
84 return alpha;
85 }
86
87 /**
88 * @return the probabilities.
89 */
90 public double[] getProbabilities() {
91 return probabilities;
92 }
93
94 /**
95 * @return the sampler.
96 */
97 public DiscreteSampler getSampler() {
98 return sampler;
99 }
100
101 /** Create the distribution and sampler. */
102 @Setup
103 public void setup() {
104 probabilities = createProbabilities(size);
105 final UniformRandomProvider rng = RandomSource.SPLIT_MIX_64.create();
106 sampler = AliasMethodDiscreteSampler.of(rng, probabilities, alpha);
107 }
108
109 /**
110 * Creates the probabilities for a discrete distribution of the given size.
111 *
112 * <p>This is not normalised to sum to 1. The sampler should handle this.</p>
113 *
114 * @param size Size of the distribution.
115 * @return the probabilities
116 */
117 private static double[] createProbabilities(int size) {
118 final double[] probabilities = new double[size];
119 for (int i = 0; i < size; i++) {
120 probabilities[i] = (i + 1.0) / size;
121 }
122 return probabilities;
123 }
124 }
125
126 // Benchmarks methods below.
127
128 /**
129 * Baseline for the JMH timing overhead for production of an {@code int} value.
130 *
131 * @return the {@code int} value
132 */
133 @Benchmark
134 public int baseline() {
135 return value;
136 }
137
138 /**
139 * Run the sampler.
140 *
141 * @param data Contains the distribution sampler.
142 * @return the sample value
143 */
144 @Benchmark
145 public int sample(DistributionData data) {
146 return data.getSampler().sample();
147 }
148
149 /**
150 * Create the sampler.
151 *
152 * @param dist Contains the sampler constructor parameters.
153 * @return the sampler
154 */
155 @Benchmark
156 public Object createSampler(DistributionData dist) {
157 // For the construction the RNG can be null
158 return AliasMethodDiscreteSampler.of(null, dist.getProbabilities(), dist.getAlpha());
159 }
160 }