Skip to content

Commit

Permalink
add specialization and loop optis benchmark suites
Browse files Browse the repository at this point in the history
  • Loading branch information
tnielens committed May 26, 2022
1 parent 830564b commit 20712e9
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
73 changes: 73 additions & 0 deletions saddle-jmh/src/main/scala/org/saddle/LoopOptimizations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.saddle

import org.openjdk.jmh.annotations._

/** Benchmark suite comparing different loop patterns and the impact of loop optimizations.
* https://wiki.openjdk.java.net/pages/viewpage.action?pageId=20415918
*/
@State(Scope.Benchmark)
@Warmup(iterations = 10)
@Measurement(iterations = 10)
@Fork(1)
@Threads(1)
class LoopOptimisations {
@Param(Array("10000"))
var size: Int = _
var arr: Array[Double] = _
var vec1: Vec[Double] = _
var b: Double = _

@Setup(Level.Iteration)
def setup() = {
arr = vec.rand(size).toArray
vec1 = Vec(arr)
b = scala.util.Random.nextDouble()
}

@Benchmark
/** Simplest variant, should trigger vectorization and other optimisations.
*/
def array(): Array[Double] = {
var i = 0
while (i < arr.length) {
arr(i) = arr(i) + b
i += 1
}
arr
}

/** hand-unrolled loops prevent vectorization and potentially other
* optimisations
*/
@Benchmark
def arrayHandUnrolled(): Array[Double] = {
var i = 0
val length = arr.length
val unrolledStride = 2
val preloopIterations = length % unrolledStride
while (i < preloopIterations) {
arr(i) += b
i += 1
}
while (i < length) {
arr(i + 0) += b
arr(i + 1) += b
i += unrolledStride
}
arr
}

@Benchmark
def vecBinOps(): Vec[Double] = {
import ops.BinOps._
vec1 += b
vec1
}

@Benchmark
def vecBinOpsMacros(): Vec[Double] = {
import macros.BinOps._
vec1 += b
vec1
}
}
58 changes: 58 additions & 0 deletions saddle-jmh/src/main/scala/org/saddle/Specialization.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.saddle

import org.saddle.scalar.ScalarTag
import org.saddle.vec.VecDefault

import org.openjdk.jmh.annotations._

class VecBoxed[T: ScalarTag](values: Array[T])
extends VecDefault[T](values, implicitly[ScalarTag[T]])

/** Benchmark suite illustrating the performance boost of specialization.
*/
@State(Scope.Benchmark)
@Warmup(iterations = 3)
@Measurement(iterations = 1)
@Fork(1)
@Threads(1)
class Specialization {
@Param(Array("10", "10000"))
var size: Int = _

var v1: Vec[Double] = _
var v2: VecBoxed[Double] = _
var b: Double = _

@Setup(Level.Iteration)
def setup() = {
v1 = vec.rand(size)
v2 = new VecBoxed(v1.toArray)
b = scala.util.Random.nextDouble()
}
@Benchmark
def vecBoxed(): Vec[Double] = {
import org.saddle.ops.BinOps._
v2 /= b
v2
}

@Benchmark
def vecSpecialized(): Vec[Double] = {
import org.saddle.ops.BinOps._
v1 += b
v1
}

@Benchmark
def array(): Vec[Double] = {
val v1a = v1.toArray
var i = 0
i = 0
val N = v1a.length
while (i < N) {
v1a(i) += b
i += 1
}
v1
}
}

0 comments on commit 20712e9

Please sign in to comment.