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  package org.apache.commons.geometry.examples.jmh.euclidean;
18  
19  import java.util.concurrent.TimeUnit;
20  
21  import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
22  import org.apache.commons.geometry.euclidean.twod.Vector2D;
23  import org.apache.commons.geometry.euclidean.twod.shape.Circle;
24  import org.apache.commons.numbers.core.Precision;
25  import org.apache.commons.rng.UniformRandomProvider;
26  import org.apache.commons.rng.simple.RandomSource;
27  import org.openjdk.jmh.annotations.Benchmark;
28  import org.openjdk.jmh.annotations.BenchmarkMode;
29  import org.openjdk.jmh.annotations.Fork;
30  import org.openjdk.jmh.annotations.Level;
31  import org.openjdk.jmh.annotations.Measurement;
32  import org.openjdk.jmh.annotations.Mode;
33  import org.openjdk.jmh.annotations.OutputTimeUnit;
34  import org.openjdk.jmh.annotations.Param;
35  import org.openjdk.jmh.annotations.Scope;
36  import org.openjdk.jmh.annotations.Setup;
37  import org.openjdk.jmh.annotations.State;
38  import org.openjdk.jmh.annotations.Warmup;
39  
40  /** Benchmarks for the {@link Circle} class.
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  @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"})
47  public class CirclePerformance {
48  
49      /** Precision epsilon value. */
50      private static final double EPS = 1e-10;
51  
52      /** Minimum value for random doubles. */
53      private static final double MIN_VALUE = 1e-1;
54  
55      /** Maximum value for random doubles. */
56      private static final double MAX_VALUE = 1e-100;
57  
58      /** Benchmark input providing a source of random {@link Circle} instances.
59       */
60      @State(Scope.Thread)
61      public static class RandomCircle {
62  
63          /** The circle instance for the benchmark iteration. */
64          private Circle circle;
65  
66          /** Set up the instance for the benchmark. */
67          @Setup(Level.Iteration)
68          public void setup() {
69              circle = randomCircle(RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP));
70          }
71  
72          /** Get the input circle.
73           * @return the input circle
74           */
75          public Circle getCircle() {
76              return circle;
77          }
78      }
79  
80      /** Class defining input values to the {@link Circle#toTree(int)} method.
81       */
82      @State(Scope.Thread)
83      public static class ToTreeInput {
84  
85          /** The number of segments in the circle approximation. */
86          @Param({"10", "100", "1000"})
87          private int segments;
88  
89          /** Get the number of segments to use for the circle approximation.
90           * @return the number of segments to use for the circle approximation
91           */
92          public int getSegments() {
93              return segments;
94          }
95      }
96  
97      /** Input class providing a pre-computed bsp tree circle approximation.
98       */
99      @State(Scope.Thread)
100     public static class ToTreeInstance extends ToTreeInput {
101 
102         /** The bsp tree input instance. */
103         private RegionBSPTree2D tree;
104 
105         /** Set up the instance for the benchmark. */
106         @Setup(Level.Iteration)
107         public void setup() {
108             final Circle circle = randomCircle(RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP));
109 
110             tree = circle.toTree(getSegments());
111         }
112 
113         /** Get the computed bsp tree circle approximation.
114          * @return the computed bsp tree circle approximation
115          */
116         public RegionBSPTree2D getTree() {
117             return tree;
118         }
119     }
120 
121     /** Create a random circle using the given random provider. The double values
122      * in the circle are between {@link #MIN_VALUE} and {@link #MAX_VALUE}.
123      * @param rand random provider
124      * @return a circle with random parameters.
125      */
126     private static Circle randomCircle(final UniformRandomProvider rand) {
127         final Vector2D center = Vector2D.of(nextDouble(rand), nextDouble(rand));
128         final double radius = nextDouble(rand);
129 
130         return Circle.from(center, radius, Precision.doubleEquivalenceOfEpsilon(EPS));
131     }
132 
133     /** Return a random double bounded by {@link #MAX_VALUE} and {@link #MIN_VALUE}.
134      * @param rand random provider
135      * @return a random double value
136      */
137     private static double nextDouble(final UniformRandomProvider rand) {
138         return (rand.nextDouble() * (MAX_VALUE - MIN_VALUE)) + MIN_VALUE;
139     }
140 
141     /** Benchmark testing the performance of the {@link Circle#toTree(int)} method.
142      * @param randomCircle circle input
143      * @param toTreeInput toTree input parameters
144      * @return created bsp tree
145      */
146     @Benchmark
147     public RegionBSPTree2D toTreeCreation(final RandomCircle randomCircle, final ToTreeInput toTreeInput) {
148         final Circle circle = randomCircle.getCircle();
149         final int segments = toTreeInput.getSegments();
150 
151         return circle.toTree(segments);
152     }
153 
154     /** Benchmark testing the performance of the computation of the size of the bsp trees
155      * created by the {@link Circle#toTree(int)} method.
156      * @param toTreeInstance bsp tree circle approximation instance
157      * @return the size (area) of the region represented by the tree
158      */
159     @Benchmark
160     public double toTreeSize(final ToTreeInstance toTreeInstance) {
161         final RegionBSPTree2D tree = toTreeInstance.getTree();
162 
163         return tree.getSize();
164     }
165 }