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.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 }