1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.rng.examples.jmh.sampling.shape;
19
20 import org.apache.commons.rng.UniformRandomProvider;
21 import org.apache.commons.rng.sampling.ObjectSampler;
22 import org.apache.commons.rng.sampling.UnitSphereSampler;
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.Level;
28 import org.openjdk.jmh.annotations.Measurement;
29 import org.openjdk.jmh.annotations.Mode;
30 import org.openjdk.jmh.annotations.OutputTimeUnit;
31 import org.openjdk.jmh.annotations.Param;
32 import org.openjdk.jmh.annotations.Scope;
33 import org.openjdk.jmh.annotations.Setup;
34 import org.openjdk.jmh.annotations.State;
35 import org.openjdk.jmh.annotations.Warmup;
36 import org.openjdk.jmh.infra.Blackhole;
37 import java.util.concurrent.TimeUnit;
38
39
40
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", "-Xms512M", "-Xmx512M" })
48 public class TriangleSamplerBenchmark {
49
50 private static final String BASELINE = "Baseline";
51
52 private static final String BASELINE_IF = "BaselineIf";
53
54 private static final String VECTORS = "Vectors";
55
56 private static final String COORDINATES = "Coordinates";
57
58 private static final String UNKNOWN_SAMPLER = "Unknown sampler type: ";
59
60
61
62
63 private abstract static class VectorTriangleSampler implements ObjectSampler<double[]> {
64
65 private final UniformRandomProvider rng;
66
67
68
69
70
71
72 VectorTriangleSampler(UniformRandomProvider rng) {
73 this.rng = rng;
74 }
75
76
77
78
79 @Override
80 public double[] sample() {
81 final double s = rng.nextDouble();
82 final double t = rng.nextDouble();
83 if (s + t > 1) {
84 return createSample(1.0 - s, 1.0 - t);
85 }
86 return createSample(s, t);
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100
101 protected abstract double[] createSample(double s, double t);
102 }
103
104
105
106
107 private abstract static class CoordinateTriangleSampler implements ObjectSampler<double[]> {
108
109 private final UniformRandomProvider rng;
110
111
112
113
114
115
116 CoordinateTriangleSampler(UniformRandomProvider rng) {
117 this.rng = rng;
118 }
119
120
121
122
123 @Override
124 public double[] sample() {
125 final double s = rng.nextDouble();
126 final double t = rng.nextDouble();
127 final double spt = s + t;
128 if (spt > 1) {
129
130
131
132
133
134 return createSample(s - 1.0 + t, 1.0 - s, 1.0 - t);
135 }
136
137 return createSample(1.0 - spt, s, t);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153 protected abstract double[] createSample(double p1msmt, double s, double t);
154 }
155
156
157
158
159
160
161 @State(Scope.Benchmark)
162 public abstract static class SamplerData {
163
164 private ObjectSampler<double[]> sampler;
165
166
167 @Param({"1000"})
168 private int size;
169
170
171
172
173
174
175 public int getSize() {
176 return size;
177 }
178
179
180
181
182
183
184 public ObjectSampler<double[]> getSampler() {
185 return sampler;
186 }
187
188
189
190
191 @Setup(Level.Iteration)
192 public void setup() {
193
194 final UniformRandomProvider rng = RandomSource.XO_RO_SHI_RO_128_PP.create();
195 final int dimension = getDimension();
196 final UnitSphereSampler s = UnitSphereSampler.of(rng, dimension);
197 final double[] a = s.sample();
198 final double[] b = s.sample();
199 final double[] c = s.sample();
200 sampler = createSampler(rng, a, b, c);
201 }
202
203
204
205
206
207
208 protected abstract int getDimension();
209
210
211
212
213
214
215
216
217
218
219 protected abstract ObjectSampler<double[]> createSampler(UniformRandomProvider rng,
220 double[] a, double[] b, double[] c);
221 }
222
223
224
225
226 @State(Scope.Benchmark)
227 public static class Sampler2D extends SamplerData {
228
229 @Param({BASELINE, BASELINE_IF, VECTORS, COORDINATES})
230 private String type;
231
232
233 @Override
234 protected int getDimension() {
235 return 2;
236 }
237
238
239 @Override
240 protected ObjectSampler<double[]> createSampler(final UniformRandomProvider rng,
241 final double[] a, final double[] b, final double[] c) {
242 if (BASELINE.equals(type)) {
243 return () -> {
244 final double s = rng.nextDouble();
245 final double t = rng.nextDouble();
246 return new double[] {s, t};
247 };
248 } else if (BASELINE_IF.equals(type)) {
249 return () -> {
250 final double s = rng.nextDouble();
251 final double t = rng.nextDouble();
252 if (s + t > 1) {
253 return new double[] {s, t};
254 }
255 return new double[] {t, s};
256 };
257 } else if (VECTORS.equals(type)) {
258 return new VectorTriangleSampler2D(rng, a, b, c);
259 } else if (COORDINATES.equals(type)) {
260 return new CoordinateTriangleSampler2D(rng, a, b, c);
261 }
262 throw new IllegalStateException(UNKNOWN_SAMPLER + type);
263 }
264
265
266
267
268 private static class VectorTriangleSampler2D extends VectorTriangleSampler {
269
270 private final double ax;
271 private final double ay;
272 private final double vx;
273 private final double vy;
274 private final double wx;
275 private final double wy;
276
277
278
279
280
281
282
283
284 VectorTriangleSampler2D(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
285 super(rng);
286 ax = a[0];
287 ay = a[1];
288 vx = b[0] - ax;
289 vy = b[1] - ay;
290 wx = c[0] - ax;
291 wy = c[1] - ay;
292 }
293
294 @Override
295 protected double[] createSample(double s, double t) {
296 return new double[] {ax + s * vx + t * wx,
297 ay + s * vy + t * wy};
298 }
299 }
300
301
302
303
304 private static class CoordinateTriangleSampler2D extends CoordinateTriangleSampler {
305
306 private final double ax;
307 private final double ay;
308 private final double bx;
309 private final double by;
310 private final double cx;
311 private final double cy;
312
313
314
315
316
317
318
319
320 CoordinateTriangleSampler2D(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
321 super(rng);
322 ax = a[0];
323 ay = a[1];
324 bx = b[0];
325 by = b[1];
326 cx = c[0];
327 cy = c[1];
328 }
329
330 @Override
331 protected double[] createSample(double p1msmt, double s, double t) {
332 return new double[] {p1msmt * ax + s * bx + t * cx,
333 p1msmt * ay + s * by + t * cy};
334 }
335 } }
336
337
338
339
340 @State(Scope.Benchmark)
341 public static class Sampler3D extends SamplerData {
342
343 @Param({BASELINE, BASELINE_IF, VECTORS, COORDINATES})
344 private String type;
345
346
347 @Override
348 protected int getDimension() {
349 return 3;
350 }
351
352
353 @Override
354 protected ObjectSampler<double[]> createSampler(final UniformRandomProvider rng,
355 final double[] a, final double[] b, final double[] c) {
356 if (BASELINE.equals(type)) {
357 return () -> {
358 final double s = rng.nextDouble();
359 final double t = rng.nextDouble();
360 return new double[] {s, t, s};
361 };
362 } else if (BASELINE_IF.equals(type)) {
363 return () -> {
364 final double s = rng.nextDouble();
365 final double t = rng.nextDouble();
366 if (s + t > 1) {
367 return new double[] {s, t, s};
368 }
369 return new double[] {t, s, t};
370 };
371 } else if (VECTORS.equals(type)) {
372 return new VectorTriangleSampler3D(rng, a, b, c);
373 } else if (COORDINATES.equals(type)) {
374 return new CoordinateTriangleSampler3D(rng, a, b, c);
375 }
376 throw new IllegalStateException(UNKNOWN_SAMPLER + type);
377 }
378
379
380
381
382 private static class VectorTriangleSampler3D extends VectorTriangleSampler {
383
384 private final double ax;
385 private final double ay;
386 private final double az;
387 private final double vx;
388 private final double vy;
389 private final double vz;
390 private final double wx;
391 private final double wy;
392 private final double wz;
393
394
395
396
397
398
399
400
401 VectorTriangleSampler3D(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
402 super(rng);
403 ax = a[0];
404 ay = a[1];
405 az = a[2];
406 vx = b[0] - ax;
407 vy = b[1] - ay;
408 vz = b[2] - az;
409 wx = c[0] - ax;
410 wy = c[1] - ay;
411 wz = c[2] - az;
412 }
413
414 @Override
415 protected double[] createSample(double s, double t) {
416 return new double[] {ax + s * vx + t * wx,
417 ay + s * vy + t * wy,
418 az + s * vz + t * wz};
419 }
420 }
421
422
423
424
425 private static class CoordinateTriangleSampler3D extends CoordinateTriangleSampler {
426
427 private final double ax;
428 private final double ay;
429 private final double az;
430 private final double bx;
431 private final double by;
432 private final double bz;
433 private final double cx;
434 private final double cy;
435 private final double cz;
436
437
438
439
440
441
442
443
444 CoordinateTriangleSampler3D(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
445 super(rng);
446 ax = a[0];
447 ay = a[1];
448 az = a[2];
449 bx = b[0];
450 by = b[1];
451 bz = b[2];
452 cx = c[0];
453 cy = c[1];
454 cz = c[2];
455 }
456
457 @Override
458 protected double[] createSample(double p1msmt, double s, double t) {
459 return new double[] {p1msmt * ax + s * bx + t * cx,
460 p1msmt * ay + s * by + t * cy,
461 p1msmt * az + s * bz + t * cz};
462 }
463 }
464 }
465
466
467
468
469 @State(Scope.Benchmark)
470 public static class SamplerND extends SamplerData {
471
472 @Param({"2", "3", "4", "8", "16", "32"})
473 private int dimension;
474
475 @Param({BASELINE, BASELINE_IF, VECTORS, COORDINATES})
476 private String type;
477
478
479 @Override
480 protected int getDimension() {
481 return dimension;
482 }
483
484
485 @Override
486 protected ObjectSampler<double[]> createSampler(final UniformRandomProvider rng,
487 final double[] a, final double[] b, final double[] c) {
488 if (BASELINE.equals(type)) {
489 return () -> {
490 double s = rng.nextDouble();
491 double t = rng.nextDouble();
492 final double[] x = new double[a.length];
493 for (int i = 0; i < x.length; i++) {
494 x[i] = s;
495 s = t;
496 t = x[i];
497 }
498 return x;
499 };
500 } else if (BASELINE_IF.equals(type)) {
501 return () -> {
502 double s = rng.nextDouble();
503 double t = rng.nextDouble();
504 final double[] x = new double[a.length];
505 if (s + t > 1) {
506 for (int i = 0; i < x.length; i++) {
507 x[i] = t;
508 t = s;
509 s = x[i];
510 }
511 return x;
512 }
513 for (int i = 0; i < x.length; i++) {
514 x[i] = s;
515 s = t;
516 t = x[i];
517 }
518 return x;
519 };
520 } else if (VECTORS.equals(type)) {
521 return new VectorTriangleSamplerND(rng, a, b, c);
522 } else if (COORDINATES.equals(type)) {
523 return new CoordinateTriangleSamplerND(rng, a, b, c);
524 }
525 throw new IllegalStateException(UNKNOWN_SAMPLER + type);
526 }
527
528
529
530
531 private static class VectorTriangleSamplerND extends VectorTriangleSampler {
532
533 private final double[] a;
534 private final double[] v;
535 private final double[] w;
536
537
538
539
540
541
542
543
544 VectorTriangleSamplerND(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
545 super(rng);
546 this.a = a.clone();
547 v = new double[a.length];
548 w = new double[a.length];
549 for (int i = 0; i < a.length; i++) {
550 v[i] = b[i] - a[i];
551 w[i] = c[i] - a[i];
552 }
553 }
554
555 @Override
556 protected double[] createSample(double s, double t) {
557 final double[] x = new double[a.length];
558 for (int i = 0; i < x.length; i++) {
559 x[i] = a[i] + s * v[i] + t * w[i];
560 }
561 return x;
562 }
563 }
564
565
566
567
568 private static class CoordinateTriangleSamplerND extends CoordinateTriangleSampler {
569
570 private final double[] a;
571 private final double[] b;
572 private final double[] c;
573
574
575
576
577
578
579
580
581 CoordinateTriangleSamplerND(UniformRandomProvider rng, double[] a, double[] b, double[] c) {
582 super(rng);
583 this.a = a.clone();
584 this.b = b.clone();
585 this.c = c.clone();
586 }
587
588 @Override
589 protected double[] createSample(double p1msmt, double s, double t) {
590 final double[] x = new double[a.length];
591 for (int i = 0; i < x.length; i++) {
592 x[i] = p1msmt * a[i] + s * b[i] + t * c[i];
593 }
594 return x;
595 }
596 }
597 }
598
599
600
601
602
603
604
605 private static void runSampler(Blackhole bh, SamplerData data) {
606 final ObjectSampler<double[]> sampler = data.getSampler();
607 for (int i = data.getSize() - 1; i >= 0; i--) {
608 bh.consume(sampler.sample());
609 }
610 }
611
612
613
614
615
616
617
618 @Benchmark
619 public void create2D(Blackhole bh, Sampler2D data) {
620 runSampler(bh, data);
621 }
622
623
624
625
626
627
628
629 @Benchmark
630 public void create3D(Blackhole bh, Sampler3D data) {
631 runSampler(bh, data);
632 }
633
634
635
636
637
638
639
640 @Benchmark
641 public void createND(Blackhole bh, SamplerND data) {
642 runSampler(bh, data);
643 }
644 }