From c6474a1ad823caae9f8c22fb8ed0c077ef3d176b Mon Sep 17 00:00:00 2001 From: Simon Parten Date: Thu, 26 Sep 2024 11:07:15 +0200 Subject: [PATCH] benchmark logicals --- benchmark/src/logical.scala | 81 +++++++++++++++++++++++ justfile | 2 +- vecxt/jvm/src/package.scala | 49 +++++++------- vecxt/test/src/arrayExtensions.test.scala | 6 +- 4 files changed, 111 insertions(+), 27 deletions(-) create mode 100644 benchmark/src/logical.scala diff --git a/benchmark/src/logical.scala b/benchmark/src/logical.scala new file mode 100644 index 0000000..1266403 --- /dev/null +++ b/benchmark/src/logical.scala @@ -0,0 +1,81 @@ +/* + * Copyright 2020, 2021, Ludovic Henry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Please contact git@ludovic.dev or visit ludovic.dev if you need additional + * information or have any questions. + */ + +package vecxt.benchmark + +import org.openjdk.jmh.annotations.* +import org.openjdk.jmh.infra.Blackhole +// import vecxt.Matrix.* +import vecxt.BoundsCheck +import scala.compiletime.uninitialized +import vecxt.* +import jdk.incubator.vector.VectorSpecies +import jdk.incubator.vector.VectorOperators +import jdk.incubator.vector.DoubleVector + +@State(Scope.Thread) +class LogicalBenchmark extends BLASBenchmark: + + @Param(Array("3", "128", "100000")) + var len: String = uninitialized; + + var arr: Array[Double] = uninitialized + + + // format: off + @Setup(Level.Trial) + def setup: Unit = + arr = randomDoubleArray(len.toInt); + () + end setup + + extension (vec: Array[Double]) + inline def lte2(num: Double) = + val idx: Array[Boolean] = new Array[Boolean](vec.length) + var i = 0 + + while i < vec.length do + idx(i) = vec(i) <= num + i += 1 + end while + idx + end extension + + @Benchmark + def lte_vec(bh: Blackhole) = + val r = arr <= 4.0 + bh.consume(r); + end lte_vec + + + + @Benchmark + def lte_loop(bh: Blackhole) = + val r = arr.lte2(4.0) + bh.consume(r); + end lte_loop + +end LogicalBenchmark + diff --git a/justfile b/justfile index e40c35d..1d65b3f 100644 --- a/justfile +++ b/justfile @@ -7,7 +7,7 @@ benchmark: mill benchmark.runJmh -jvmArgs --add-modules=jdk.incubator.vector -rf json benchmarkOnly: - mill benchmark.runJmh -jvmArgs --add-modules=jdk.incubator.vector -rf json vecxt.benchmark.OrBooleanBenchmark + mill benchmark.runJmh -jvmArgs --add-modules=jdk.incubator.vector -rf json vecxt.benchmark.LogicalBenchmark setJvm: eval "$(cs java --jvm 21 --env)" \ No newline at end of file diff --git a/vecxt/jvm/src/package.scala b/vecxt/jvm/src/package.scala index 647d803..d54b058 100644 --- a/vecxt/jvm/src/package.scala +++ b/vecxt/jvm/src/package.scala @@ -136,12 +136,9 @@ object extensions: newVec end apply - - /** - * Apparently, left packing is hard problem in SIMD land. - * https://stackoverflow.com/questions/79025873/selecting-values-from-java-simd-doublevector - * - */ + /** Apparently, left packing is hard problem in SIMD land. + * https://stackoverflow.com/questions/79025873/selecting-values-from-java-simd-doublevector + */ // inline def apply(index: Array[Boolean])(using inline boundsCheck: BoundsCheck): Array[Double] = // dimCheck(vec, index) @@ -382,11 +379,17 @@ object extensions: vec.clone.tap(_ /= d) end / + inline def =:=(num: Double): Array[Boolean] = + logicalIdx(VectorOperators.EQ, num) + + inline def !:=(num: Double): Array[Boolean] = + logicalIdx(VectorOperators.NE, num) + inline def <(num: Double): Array[Boolean] = - logicalIdx( VectorOperators.LT, num) + logicalIdx(VectorOperators.LT, num) inline def <=(num: Double): Array[Boolean] = - logicalIdx( VectorOperators.LE, num) + logicalIdx(VectorOperators.LE, num) inline def >(num: Double): Array[Boolean] = logicalIdx(VectorOperators.GT, num) @@ -395,30 +398,30 @@ object extensions: logicalIdx(VectorOperators.GE, num) inline def logicalIdx( - inline op: VectorOperators.Comparison, + inline op: VectorOperators.Comparison, num: Double ): Array[Boolean] = val species = Matrix.doubleSpecies val l = species.length() - val idx = new Array[Boolean](vec.length) + val idx = new Array[Boolean](vec.length) var i = 0 while i < species.loopBound(vec.length) do - DoubleVector.fromArray(species, vec, i).compare(op, num).intoArray(idx, i) + DoubleVector.fromArray(species, vec, i).compare(op, num).intoArray(idx, i) i += l end while inline op match - // case VectorOperators.EQ => - // while i < vec.length do - // idx(i) = vec(i) == num - // i += 1 - // end while - // case VectorOperators.NE => - // while i < vec.length do - // idx(i) = vec(i) != num - // i += 1 - // end while + case VectorOperators.EQ => + while i < vec.length do + idx(i) = vec(i) == num + i += 1 + end while + case VectorOperators.NE => + while i < vec.length do + idx(i) = vec(i) != num + i += 1 + end while case VectorOperators.LT => while i < vec.length do idx(i) = vec(i) < num @@ -430,8 +433,8 @@ object extensions: idx(i) = vec(i) <= num i += 1 end while - - case VectorOperators.GT => + + case VectorOperators.GT => while i < vec.length do idx(i) = vec(i) > num i += 1 diff --git a/vecxt/test/src/arrayExtensions.test.scala b/vecxt/test/src/arrayExtensions.test.scala index eac292a..5627b29 100644 --- a/vecxt/test/src/arrayExtensions.test.scala +++ b/vecxt/test/src/arrayExtensions.test.scala @@ -49,7 +49,7 @@ class ArrayExtensionSuite extends munit.FunSuite: val v2 = NArray[Double](1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0) val vIdx2 = NArray[Boolean](true, false, true, true, false, true, false, true, false) - val afterIndex2 = v2(vIdx2) + val afterIndex2 = v2(vIdx2) assertEqualsDouble(afterIndex2(4), 8.0, 0.0001) } @@ -160,8 +160,8 @@ class ArrayExtensionSuite extends munit.FunSuite: test("<= big") { val n = 50000 val rand = scala.util.Random - val vec = NArray.tabulate(n)(_ => rand.nextDouble()) - assertEqualsDouble((vec <= 0.2).countTrue / n.toDouble, 0.2, 0.01 ) + val vec = NArray.tabulate(n)(_ => rand.nextDouble()) + assertEqualsDouble((vec <= 0.2).countTrue / n.toDouble, 0.2, 0.01) } test("<=") {