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.oned.AffineTransformMatrix1D;
    22  import org.apache.commons.geometry.euclidean.oned.Vector1D;
    23  import org.apache.commons.geometry.euclidean.threed.AffineTransformMatrix3D;
    24  import org.apache.commons.geometry.euclidean.threed.Vector3D;
    25  import org.apache.commons.geometry.euclidean.twod.AffineTransformMatrix2D;
    26  import org.apache.commons.geometry.euclidean.twod.Vector2D;
    27  import org.apache.commons.geometry.examples.jmh.BenchmarkUtils;
    28  import org.apache.commons.rng.UniformRandomProvider;
    29  import org.apache.commons.rng.simple.RandomSource;
    30  import org.openjdk.jmh.annotations.Benchmark;
    31  import org.openjdk.jmh.annotations.BenchmarkMode;
    32  import org.openjdk.jmh.annotations.Fork;
    33  import org.openjdk.jmh.annotations.Level;
    34  import org.openjdk.jmh.annotations.Measurement;
    35  import org.openjdk.jmh.annotations.Mode;
    36  import org.openjdk.jmh.annotations.OutputTimeUnit;
    37  import org.openjdk.jmh.annotations.Param;
    38  import org.openjdk.jmh.annotations.Scope;
    39  import org.openjdk.jmh.annotations.Setup;
    40  import org.openjdk.jmh.annotations.State;
    41  import org.openjdk.jmh.annotations.Warmup;
    42
    43  /** Benchmarks for
    44   * {@link org.apache.commons.geometry.euclidean.AbstractAffineTransformMatrix AbstractAffineTransformMatrix}
    45   * subclasses.
    46   */
    47  @BenchmarkMode(Mode.AverageTime)
    48  @OutputTimeUnit(TimeUnit.NANOSECONDS)
    49  @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
    50  @Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
    51  @Fork(value = 1, jvmArgs = {"-server", "-Xms512M", "-Xmx512M"})
    52  public class AffineTransformMatrixPerformance {
    53
    54      /** Input class providing random arrays of double values for transformation.
    55       */
    56      @State(Scope.Thread)
    57      public static class TransformArrayInput {
    58
    59          /** The number of elements in the input array. */
    60          @Param({"6000", "600000"})
    61          private int size;
    62
    63          /** Array containing the input elements. */
    64          private double[] array;
    65
    66          /** Get the configured size of the input array.
    67           * @return the configured size of the input array
    68           */
    69          public int getSize() {
    70              return size;
    71          }
    72
    73          /** Get the input array.
    74           * @return input array
    75           */
    76          public double[] getArray() {
    77              return array;
    78          }
    79
    80          /** Set up the input array.
    81           */
    82          @Setup(Level.Iteration)
    83          public void setup() {
    84              final UniformRandomProvider rand = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP);
    85
    86              array = new double[size];
    87
    88              for (int i = 0; i < array.length; ++i) {
    89                  array[i] = BenchmarkUtils.randomDouble(rand);
    90              }
    91          }
    92      }
    93
    94      /** Input class providing a 1D transform matrix.
    95       */
    96      @State(Scope.Thread)
    97      public static class TransformMatrixInput1D {
    98
    99          /** Input transform matrix. */
    100         private AffineTransformMatrix1D transform;
    101
    102         /** Get the input transform matrix.
    103          * @return the input transform matrix
    104          */
    105         public AffineTransformMatrix1D getTransform() {
    106             return transform;
    107         }
    108
    109         /** Set up the input. */
    110         @Setup
    111         public void setup() {
    112             final UniformRandomProvider rand = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP);
    113
    114             transform = AffineTransformMatrix1D.of(BenchmarkUtils.randomDoubleArray(2, rand));
    115         }
    116     }
    117
    118     /** Input class providing a 2D transform matrix.
    119      */
    120     @State(Scope.Thread)
    121     public static class TransformMatrixInput2D {
    122
    123         /** Input transform matrix. */
    124         private AffineTransformMatrix2D transform;
    125
    126         /** Get the input transform matrix.
    127          * @return the input transform matrix
    128          */
    129         public AffineTransformMatrix2D getTransform() {
    130             return transform;
    131         }
    132
    133         /** Set up the input. */
    134         @Setup
    135         public void setup() {
    136             final UniformRandomProvider rand = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP);
    137
    138             transform = AffineTransformMatrix2D.of(BenchmarkUtils.randomDoubleArray(6, rand));
    139         }
    140     }
    141
    142     /** Input class providing a 3D transform matrix.
    143      */
    144     @State(Scope.Thread)
    145     public static class TransformMatrixInput3D {
    146
    147         /** Input transform matrix. */
    148         private AffineTransformMatrix3D transform;
    149
    150         /** Get the input transform matrix.
    151          * @return the input transform matrix
    152          */
    153         public AffineTransformMatrix3D getTransform() {
    154             return transform;
    155         }
    156
    157         /** Set up the input. */
    158         @Setup
    159         public void setup() {
    160             final UniformRandomProvider rand = RandomSource.create(RandomSource.XO_RO_SHI_RO_128_PP);
    161
    162             transform = AffineTransformMatrix3D.of(BenchmarkUtils.randomDoubleArray(12, rand));
    163         }
    164     }
    165
    166     /** Baseline benchmark for 1D transforms on array data.
    167      * @param arrayInput array input
    168      * @return transformed output
    169      */
    170     @Benchmark
    171     public double[] baselineArray1D(final TransformArrayInput arrayInput) {
    172         final double[] arr = arrayInput.getArray();
    173
    174         double x;
    175         for (int i = 0; i < arr.length; ++i) {
    176             x = arr[i];
    177
    178             arr[i] = x + 1;
    179         }
    180
    181         return arr;
    182     }
    183
    184     /** Benchmark testing the performance of transforming an array of doubles by converting each group
    185      * to a Vector1D.
    186      * @param arrayInput array input
    187      * @param transformInput transform input
    188      * @return transformed output
    189      */
    190     @Benchmark
    191     public double[] transformArrayAsVectors1D(final TransformArrayInput arrayInput,
    192             final TransformMatrixInput1D transformInput) {
    193         final double[] arr = arrayInput.getArray();
    194         final AffineTransformMatrix1D t = transformInput.getTransform();
    195
    196         Vector1D in;
    197         Vector1D out;
    198         for (int i = 0; i < arr.length; ++i) {
    199             in = Vector1D.of(arr[i]);
    200
    201             out = t.apply(in);
    202
    203             arr[i] = out.getX();
    204         }
    205
    206         return arr;
    207     }
    208
    209     /** Benchmark testing the performance of transforming an array of doubles by transforming
    210      * the components directly.
    211      * @param arrayInput array input
    212      * @param transformInput transform input
    213      * @return transformed output
    214      */
    215     @Benchmark
    216     public double[] transformArrayComponents1D(final TransformArrayInput arrayInput,
    217             final TransformMatrixInput1D transformInput) {
    218         final double[] arr = arrayInput.getArray();
    219         final AffineTransformMatrix1D t = transformInput.getTransform();
    220
    221         double x;
    222         for (int i = 0; i < arr.length; ++i) {
    223             x = arr[i];
    224
    225             arr[i] = t.applyX(x);
    226         }
    227
    228         return arr;
    229     }
    230
    231     /** Baseline benchmark for 2D transforms on array data.
    232      * @param arrayInput array input
    233      * @return transformed output
    234      */
    235     @Benchmark
    236     public double[] baselineArray2D(final TransformArrayInput arrayInput) {
    237         final double[] arr = arrayInput.getArray();
    238
    239         double x;
    240         double y;
    241         for (int i = 0; i < arr.length; i += 2) {
    242             x = arr[i];
    243             y = arr[i + 1];
    244
    245             arr[i] = x + 1;
    246             arr[i + 1] = y + 1;
    247         }
    248
    249         return arr;
    250     }
    251
    252     /** Benchmark testing the performance of transforming an array of doubles by converting each group
    253      * to a Vector2D.
    254      * @param arrayInput array input
    255      * @param transformInput transform input
    256      * @return transformed output
    257      */
    258     @Benchmark
    259     public double[] transformArrayAsVectors2D(final TransformArrayInput arrayInput,
    260             final TransformMatrixInput2D transformInput) {
    261         final double[] arr = arrayInput.getArray();
    262         final AffineTransformMatrix2D t = transformInput.getTransform();
    263
    264         Vector2D in;
    265         Vector2D out;
    266         for (int i = 0; i < arr.length; i += 2) {
    267             in = Vector2D.of(
    268                     arr[i],
    269                     arr[i + 1]);
    270
    271             out = t.apply(in);
    272
    273             arr[i] = out.getX();
    274             arr[i + 1] = out.getY();
    275         }
    276
    277         return arr;
    278     }
    279
    280     /** Benchmark testing the performance of transforming an array of doubles by transforming
    281      * the components directly.
    282      * @param arrayInput array input
    283      * @param transformInput transform input
    284      * @return transformed output
    285      */
    286     @Benchmark
    287     public double[] transformArrayComponents2D(final TransformArrayInput arrayInput,
    288             final TransformMatrixInput2D transformInput) {
    289         final double[] arr = arrayInput.getArray();
    290         final AffineTransformMatrix2D t = transformInput.getTransform();
    291
    292         double x;
    293         double y;
    294         for (int i = 0; i < arr.length; i += 2) {
    295             x = arr[i];
    296             y = arr[i + 1];
    297
    298             arr[i] = t.applyX(x, y);
    299             arr[i + 1] = t.applyY(x, y);
    300         }
    301
    302         return arr;
    303     }
    304
    305     /** Baseline benchmark for 3D transforms on array data.
    306      * @param arrayInput array input
    307      * @return transformed output
    308      */
    309     @Benchmark
    310     public double[] baselineArray3D(final TransformArrayInput arrayInput) {
    311         final double[] arr = arrayInput.getArray();
    312
    313         double x;
    314         double y;
    315         double z;
    316         for (int i = 0; i < arr.length; i += 3) {
    317             x = arr[i];
    318             y = arr[i + 1];
    319             z = arr[i + 2];
    320
    321             arr[i] = x + 1;
    322             arr[i + 1] = y + 1;
    323             arr[i + 2] = z + 1;
    324         }
    325
    326         return arr;
    327     }
    328
    329     /** Benchmark testing the performance of transforming an array of doubles by converting each group
    330      * to a Vector3D.
    331      * @param arrayInput array input
    332      * @param transformInput transform input
    333      * @return transformed output
    334      */
    335     @Benchmark
    336     public double[] transformArrayAsVectors3D(final TransformArrayInput arrayInput,
    337             final TransformMatrixInput3D transformInput) {
    338         final double[] arr = arrayInput.getArray();
    339         final AffineTransformMatrix3D t = transformInput.getTransform();
    340
    341         Vector3D in;
    342         Vector3D out;
    343         for (int i = 0; i < arr.length; i += 3) {
    344             in = Vector3D.of(
    345                     arr[i],
    346                     arr[i + 1],
    347                     arr[i + 2]);
    348
    349             out = t.apply(in);
    350
    351             arr[i] = out.getX();
    352             arr[i + 1] = out.getY();
    353             arr[i + 2] = out.getZ();
    354         }
    355
    356         return arr;
    357     }
    358
    359     /** Benchmark testing the performance of transforming an array of doubles by transforming
    360      * the components directly.
    361      * @param arrayInput array input
    362      * @param transformInput transform input
    363      * @return transformed output
    364      */
    365     @Benchmark
    366     public double[] transformArrayComponents3D(final TransformArrayInput arrayInput,
    367             final TransformMatrixInput3D transformInput) {
    368         final double[] arr = arrayInput.getArray();
    369         final AffineTransformMatrix3D t = transformInput.getTransform();
    370
    371         double x;
    372         double y;
    373         double z;
    374         for (int i = 0; i < arr.length; i += 3) {
    375             x = arr[i];
    376             y = arr[i + 1];
    377             z = arr[i + 2];
    378
    379             arr[i] = t.applyX(x, y, z);
    380             arr[i + 1] = t.applyY(x, y, z);
    381             arr[i + 2] = t.applyZ(x, y, z);
    382         }
    383
    384         return arr;
    385     }
    386 }