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.core; 19 20 import org.apache.commons.rng.UniformRandomProvider; 21 import org.openjdk.jmh.annotations.Benchmark; 22 import org.openjdk.jmh.annotations.BenchmarkMode; 23 import org.openjdk.jmh.annotations.Fork; 24 import org.openjdk.jmh.annotations.Measurement; 25 import org.openjdk.jmh.annotations.Mode; 26 import org.openjdk.jmh.annotations.OutputTimeUnit; 27 import org.openjdk.jmh.annotations.Param; 28 import org.openjdk.jmh.annotations.Scope; 29 import org.openjdk.jmh.annotations.State; 30 import org.openjdk.jmh.annotations.Warmup; 31 import org.openjdk.jmh.infra.Blackhole; 32 33 import java.util.concurrent.TimeUnit; 34 35 /** 36 * Benchmarks to check linearity in the baseline implementations of {@link UniformRandomProvider}. 37 * 38 * <p>These ordinarily do not need to be run. The benchmarks can be used to determine 39 * if the baseline scales linearly with workload. If not then the JVM has removed the 40 * baseline from the testing loop given that its result is predictable. The ideal 41 * baseline will:</p> 42 * 43 * <ul> 44 * <li>Run as fast as possible 45 * <li>Not be removed from the execution path 46 * </ul> 47 * 48 * <p>The results of this benchmark should be plotted for each method using [numValues] vs [run time] 49 * to check linearity.</p> 50 */ 51 @BenchmarkMode(Mode.AverageTime) 52 @OutputTimeUnit(TimeUnit.NANOSECONDS) 53 @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) 54 @Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) 55 @State(Scope.Benchmark) 56 @Fork(value = 1, jvmArgs = { "-server", "-Xms128M", "-Xmx128M" }) 57 public class BaselineGenerationPerformance { 58 /** 59 * The size of the array for testing {@link UniformRandomProvider#nextBytes(byte[])}. 60 * 61 * <p>This is a small prime number (127). This satisfies the following requirements:</p> 62 * 63 * <ul> 64 * <li>The number of bytes will be allocated when testing so the allocation overhead 65 * should be small. 66 * <li>The number must be set so that filling the bytes from an {@code int} or {@code long} 67 * source has no advantage for the 32-bit source, e.g. the same number of underlying bits have 68 * to be generated. Note: 127 / 4 ~ 32 ints or 127 / 8 ~ 16 longs. 69 * <li>The number should not be a factor of 4 to prevent filling completely using a 32-bit 70 * source. This tests the edge case of partial fill. 71 * </ul> 72 */ 73 static final int NEXT_BYTES_SIZE = 127; 74 75 /** 76 * The upper limit for testing {@link UniformRandomProvider#nextInt(int)}. 77 * 78 * <p>This is the biggest prime number for an {@code int} (2147483629) to give a worst case 79 * run-time for the method.</p> 80 */ 81 static final int NEXT_INT_LIMIT = 2_147_483_629; 82 83 /** 84 * The upper limit for testing {@link UniformRandomProvider#nextLong(long)}. 85 * 86 * <p>This is the biggest prime number for a {@code long} (9223372036854775783L) to 87 * give a worst case run-time for the method.</p> 88 */ 89 static final long NEXT_LONG_LIMIT = 9_223_372_036_854_775_783L; 90 91 /** 92 * The provider for testing {@link UniformRandomProvider#nextByte()} and 93 * {@link UniformRandomProvider#nextByte(int)}. 94 */ 95 private UniformRandomProvider nextBytesProvider = BaselineUtils.getNextBytes(); 96 97 /** 98 * The provider for testing {@link UniformRandomProvider#nextInt()} and 99 * {@link UniformRandomProvider#nextInt(int)}. 100 */ 101 private UniformRandomProvider nextIntProvider = BaselineUtils.getNextInt(); 102 103 /** 104 * The provider for testing {@link UniformRandomProvider#nextLong()} and 105 * {@link UniformRandomProvider#nextLong(long)}. 106 */ 107 private UniformRandomProvider nextLongProvider = BaselineUtils.getNextLong(); 108 109 /** 110 * The provider for testing {@link UniformRandomProvider#nextBoolean()}. 111 */ 112 private UniformRandomProvider nextBooleanProvider = BaselineUtils.getNextBoolean(); 113 114 /** 115 * The provider for testing {@link UniformRandomProvider#nextFloat()}. 116 */ 117 private UniformRandomProvider nextFloatProvider = BaselineUtils.getNextFloat(); 118 119 /** 120 * The provider for testing {@link UniformRandomProvider#nextDouble()}. 121 */ 122 private UniformRandomProvider nextDoubleProvider = BaselineUtils.getNextDouble(); 123 124 /** 125 * Number of random values to generate when testing linearity. This must be high to avoid 126 * JIT optimisation of small loop constructs. 127 * 128 * <p>Note: Following the convention in the JMH Blackhole::consumCPU(long) method 129 * the loops are constructed to count down (although since there is no consumption 130 * of the loop counter the loop construct may be rewritten anyway).</p> 131 */ 132 @Param({"50000", "100000", "150000", "200000", "250000"}) 133 private int numValues; 134 135 /** 136 * Exercise the {@link UniformRandomProvider#nextBytes(byte[])} method. 137 * 138 * <p>Note: Currently there is not a test for 139 * {@link UniformRandomProvider#nextBytes(byte[], int, int)} since the two methods are 140 * implemented by the base Int/LongProvider class using the same code.</p> 141 * 142 * @param bh Data sink. 143 */ 144 @Benchmark 145 public void nextBytes(Blackhole bh) { 146 // The array allocation is not part of the benchmark. 147 final byte[] result = new byte[NEXT_BYTES_SIZE]; 148 for (int i = numValues; i > 0; i--) { 149 nextBytesProvider.nextBytes(result); 150 bh.consume(result); 151 } 152 } 153 154 /** 155 * Exercise the {@link UniformRandomProvider#nextInt()} method. 156 * 157 * @param bh Data sink. 158 */ 159 @Benchmark 160 public void nextInt(Blackhole bh) { 161 for (int i = numValues; i > 0; i--) { 162 bh.consume(nextIntProvider.nextInt()); 163 } 164 } 165 166 /** 167 * Exercise the {@link UniformRandomProvider#nextInt(int)} method. 168 * 169 * @param bh Data sink. 170 */ 171 @Benchmark 172 public void nextIntN(Blackhole bh) { 173 for (int i = numValues; i > 0; i--) { 174 bh.consume(nextIntProvider.nextInt(NEXT_INT_LIMIT)); 175 } 176 } 177 178 /** 179 * Exercise the {@link UniformRandomProvider#nextLong()} method. 180 * 181 * @param bh Data sink. 182 */ 183 @Benchmark 184 public void nextLong(Blackhole bh) { 185 for (int i = numValues; i > 0; i--) { 186 bh.consume(nextLongProvider.nextLong()); 187 } 188 } 189 190 /** 191 * Exercise the {@link UniformRandomProvider#nextLong(long)} method. 192 * 193 * @param bh Data sink. 194 */ 195 @Benchmark 196 public void nextLongN(Blackhole bh) { 197 for (int i = numValues; i > 0; i--) { 198 bh.consume(nextLongProvider.nextLong(NEXT_LONG_LIMIT)); 199 } 200 } 201 202 /** 203 * Exercise the {@link UniformRandomProvider#nextBoolean()} method. 204 * 205 * @param bh Data sink. 206 */ 207 @Benchmark 208 public void nextBoolean(Blackhole bh) { 209 for (int i = numValues; i > 0; i--) { 210 bh.consume(nextBooleanProvider.nextBoolean()); 211 } 212 } 213 214 /** 215 * Exercise the {@link UniformRandomProvider#nextFloat()} method. 216 * 217 * @param bh Data sink. 218 */ 219 @Benchmark 220 public void nextFloat(Blackhole bh) { 221 for (int i = numValues; i > 0; i--) { 222 bh.consume(nextFloatProvider.nextFloat()); 223 } 224 } 225 226 /** 227 * Exercise the {@link UniformRandomProvider#nextDouble()} method. 228 * 229 * @param bh Data sink. 230 */ 231 @Benchmark 232 public void nextDouble(Blackhole bh) { 233 for (int i = numValues; i > 0; i--) { 234 bh.consume(nextDoubleProvider.nextDouble()); 235 } 236 } 237 }