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.core.precision.EpsilonDoublePrecisionContext;
    22  import org.apache.commons.geometry.euclidean.twod.RegionBSPTree2D;
    23  import org.apache.commons.geometry.euclidean.twod.Vector2D;
    24  import org.apache.commons.geometry.euclidean.twod.shape.Circle;
    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, new EpsilonDoublePrecisionContext(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 }