1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.numbers.examples.jmh.core;
19
20 import java.math.MathContext;
21 import java.util.Arrays;
22 import java.util.concurrent.TimeUnit;
23 import java.util.function.IntFunction;
24
25 import org.apache.commons.numbers.core.Sum;
26 import org.apache.commons.numbers.examples.jmh.core.LinearCombination.FourD;
27 import org.apache.commons.numbers.examples.jmh.core.LinearCombination.ND;
28 import org.apache.commons.numbers.examples.jmh.core.LinearCombination.ThreeD;
29 import org.apache.commons.numbers.examples.jmh.core.LinearCombination.TwoD;
30 import org.apache.commons.rng.UniformRandomProvider;
31 import org.apache.commons.rng.simple.RandomSource;
32 import org.openjdk.jmh.annotations.Benchmark;
33 import org.openjdk.jmh.annotations.BenchmarkMode;
34 import org.openjdk.jmh.annotations.Fork;
35 import org.openjdk.jmh.annotations.Measurement;
36 import org.openjdk.jmh.annotations.Mode;
37 import org.openjdk.jmh.annotations.OutputTimeUnit;
38 import org.openjdk.jmh.annotations.Param;
39 import org.openjdk.jmh.annotations.Scope;
40 import org.openjdk.jmh.annotations.Setup;
41 import org.openjdk.jmh.annotations.State;
42 import org.openjdk.jmh.annotations.Warmup;
43 import org.openjdk.jmh.infra.Blackhole;
44
45
46
47
48 @BenchmarkMode(Mode.AverageTime)
49 @OutputTimeUnit(TimeUnit.NANOSECONDS)
50 @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
51 @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
52 @State(Scope.Benchmark)
53 @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"})
54 public class LinearCombinationPerformance {
55
56
57
58
59
60 private static final long SEED = System.currentTimeMillis();
61
62
63
64
65 @State(Scope.Benchmark)
66 public static class Factors {
67
68
69
70 @Param({"1e20"})
71 private double c;
72
73
74
75
76 @Param({"1000"})
77 private int size;
78
79
80 private double[][] a;
81
82
83 private double[][] b;
84
85
86
87
88
89
90
91
92
93 public int getLength() {
94 return 4;
95 }
96
97
98
99
100
101
102 public int getSize() {
103 return size;
104 }
105
106
107
108
109
110
111
112 public double[] getA(int index) {
113 return a[index];
114 }
115
116
117
118
119
120
121
122 public double[] getB(int index) {
123 return b[index];
124 }
125
126
127
128
129 @Setup
130 public void setup() {
131 final UniformRandomProvider rng =
132 RandomSource.XO_RO_SHI_RO_1024_PP.create(SEED);
133
134
135 final int n = Math.max(6, getLength());
136 final double[] x = new double[n];
137 final double[] y = new double[n];
138 a = new double[size][];
139 b = new double[size][];
140
141 final MathContext mathContext = new MathContext(100);
142 for (int i = 0; i < size; i++) {
143 LinearCombinationUtils.genDot(c, rng, x, y, null, mathContext);
144 a[i] = Arrays.copyOf(x, getLength());
145 b[i] = Arrays.copyOf(y, getLength());
146 }
147 }
148 }
149
150
151
152
153 @State(Scope.Benchmark)
154 public static class LengthFactors extends Factors {
155
156
157
158 @Param({"2", "3", "4", "8", "16", "32", "64"})
159 private int length;
160
161
162 @Override
163 public int getLength() {
164 return length;
165 }
166 }
167
168
169
170
171 @State(Scope.Benchmark)
172 public static class Calculator {
173
174
175
176 @Param({"standard",
177 "current",
178 "dekker",
179 "dot2s",
180 "dot2", "dot3", "dot4", "dot5", "dot6", "dot7",
181 "exact",
182 "extended", "extended2", "extended_exact", "extended_exact2",
183
184
185
186
187 "dot3c", "extendedc"})
188 private String name;
189
190
191 private TwoD twod;
192
193 private ThreeD threed;
194
195 private FourD fourd;
196
197 private ND nd;
198
199
200
201
202 public TwoD getTwoD() {
203 return twod;
204 }
205
206
207
208
209 public ThreeD getThreeD() {
210 return threed;
211 }
212
213
214
215
216 public FourD getFourD() {
217 return fourd;
218 }
219
220
221
222
223 public ND getND() {
224 return nd;
225 }
226
227
228
229
230 @Setup
231 public void setup() {
232 if ("current".endsWith(name)) {
233 twod = (a1, b1, a2, b2) ->
234 Sum.create()
235 .addProduct(a1, b1)
236 .addProduct(a2, b2).getAsDouble();
237 threed = (a1, b1, a2, b2, a3, b3) ->
238 Sum.create()
239 .addProduct(a1, b1)
240 .addProduct(a2, b2)
241 .addProduct(a3, b3).getAsDouble();
242 fourd = (a1, b1, a2, b2, a3, b3, a4, b4) ->
243 Sum.create()
244 .addProduct(a1, b1)
245 .addProduct(a2, b2)
246 .addProduct(a3, b3)
247 .addProduct(a4, b4).getAsDouble();
248 nd = (a, b) -> Sum.ofProducts(a, b).getAsDouble();
249 return;
250 }
251
252 if ("standard".endsWith(name)) {
253 nd = LinearCombinations.StandardPrecision.INSTANCE;
254 } else if ("dekker".equals(name)) {
255 nd = LinearCombinations.Dekker.INSTANCE;
256 } else if ("dot2s".equals(name)) {
257 nd = LinearCombinations.Dot2s.INSTANCE;
258 } else if ("dot2".equals(name)) {
259 nd = new LinearCombinations.DotK(2);
260 } else if ("dot3".equals(name)) {
261 nd = LinearCombinations.DotK.DOT_3;
262 } else if ("dot4".equals(name)) {
263 nd = LinearCombinations.DotK.DOT_4;
264 } else if ("dot5".equals(name)) {
265 nd = LinearCombinations.DotK.DOT_5;
266 } else if ("dot6".equals(name)) {
267 nd = LinearCombinations.DotK.DOT_6;
268 } else if ("dot7".equals(name)) {
269 nd = LinearCombinations.DotK.DOT_7;
270 } else if ("exact".equals(name)) {
271 nd = LinearCombinations.Exact.INSTANCE;
272 } else if ("extended".equals(name)) {
273 nd = LinearCombinations.ExtendedPrecision.INSTANCE;
274 } else if ("extended2".equals(name)) {
275 nd = LinearCombinations.ExtendedPrecision.DOUBLE;
276 } else if ("extended_exact".equals(name)) {
277 nd = LinearCombinations.ExtendedPrecision.EXACT;
278 } else if ("extended_exact2".equals(name)) {
279 nd = LinearCombinations.ExtendedPrecision.EXACT2;
280 } else if ("dot3c".equals(name)) {
281 nd = new LinearCombinations.DotK(3, new CachedArrayFactory());
282 } else if ("extendedc".equals(name)) {
283 nd = LinearCombinations.ExtendedPrecision.of(
284 LinearCombinations.ExtendedPrecision.Summation.STANDARD, new CachedArrayFactory());
285 } else {
286 throw new IllegalStateException("Unknown implementation: " + name);
287 }
288
289 twod = (TwoD) nd;
290 threed = (ThreeD) nd;
291 fourd = (FourD) nd;
292 }
293 }
294
295
296
297
298 static final class CachedArrayFactory implements IntFunction<double[]> {
299
300 private static final double[] EMPTY = new double[0];
301
302
303 private double[] array = EMPTY;
304
305 @Override
306 public double[] apply(int value) {
307 double[] a = array;
308 if (a.length < value) {
309 array = a = new double[value];
310 }
311 return a;
312 }
313 }
314
315
316
317
318
319
320
321
322 @Benchmark
323 public void twoD(Factors factors, Blackhole bh, Calculator calc) {
324 final TwoD fun = calc.getTwoD();
325 for (int i = 0; i < factors.getSize(); i++) {
326 final double[] a = factors.getA(i);
327 final double[] b = factors.getB(i);
328 bh.consume(fun.value(a[0], b[0], a[1], b[1]));
329 }
330 }
331
332
333
334
335
336
337
338
339 @Benchmark
340 public void threeD(Factors factors, Blackhole bh, Calculator calc) {
341 final ThreeD fun = calc.getThreeD();
342 for (int i = 0; i < factors.getSize(); i++) {
343 final double[] a = factors.getA(i);
344 final double[] b = factors.getB(i);
345 bh.consume(fun.value(a[0], b[0], a[1], b[1], a[2], b[2]));
346 }
347 }
348
349
350
351
352
353
354
355
356 @Benchmark
357 public void fourD(Factors factors, Blackhole bh, Calculator calc) {
358 final FourD fun = calc.getFourD();
359 for (int i = 0; i < factors.getSize(); i++) {
360 final double[] a = factors.getA(i);
361 final double[] b = factors.getB(i);
362 bh.consume(fun.value(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]));
363 }
364 }
365
366
367
368
369
370
371
372
373 @Benchmark
374 public void nD(LengthFactors factors, Blackhole bh, Calculator calc) {
375 final ND fun = calc.getND();
376 for (int i = 0; i < factors.getSize(); i++) {
377
378 final double[] a = factors.getA(i);
379 final double[] b = factors.getB(i);
380 bh.consume(fun.value(a, b));
381 }
382 }
383 }