Skip to content

Runtime benchmarks infrastructure #7596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Dec 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/apply.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sizeAndIndex:20 0,20 1,20 2,20 3,20 4,20 5,20 6,20 7,20 8,20 9,20 10,20 11,20 12,20 13,20 14,20 15,20 16,20 17,20 18,20 19
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/concat.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sizes:15 0,15 1,15 2,15 3,15 4,15 5,15 6,15 7,15 8,15 9,15 10,15 11,15 12,15 13,15 14,15 15,15 16,15 17,15 18,15 19,15 20,15 21,15 22,15 23,15 24,15 25,15 26,15 27,15 28,15 29,15 30,15 31,15 32,15 33,15 34,15 35,15 36,15 37,15 38,15 39,15 40,15 41,15 42,15 43,15 44,15 45,15 46,15 47,15 48,15 49,15 50
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/cons.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
size:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/conversions.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
size:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/map.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
size:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/tail.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
size:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
1 change: 1 addition & 0 deletions bench-run/inputs/tuples/zip.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
size:0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50
81 changes: 81 additions & 0 deletions bench-run/src/main/scala/dotty/tools/benchmarks/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package dotty.tools.benchmarks

import org.openjdk.jmh.results.RunResult
import org.openjdk.jmh.runner.Runner
import org.openjdk.jmh.annotations._
import org.openjdk.jmh.results.format._
import org.openjdk.jmh.runner.options._
import java.util.concurrent.TimeUnit

import scala.io.Source

object Bench {
def main(args: Array[String]): Unit = {
if (args.contains("--help")) {
printUsage()
return
}

val (intArgs, args1) = args.span(x => try { x.toInt; true } catch { case _: Throwable => false } )

def getIntArg(i: Int, default: Int): Int =
if (intArgs.length > i) intArgs(i).toInt else default

val warmup = getIntArg(0, 20)
val iterations = getIntArg(1, 20)
val forks = getIntArg(2, 1)

if (args1.isEmpty) {
println("Error: no benchmark was specified.")
printUsage()
return
}

var builder = new OptionsBuilder()
.shouldFailOnError(true)
.jvmArgs("-Xms2G", "-Xmx2G")
.mode(Mode.AverageTime)
.timeUnit(TimeUnit.NANOSECONDS)
.warmupIterations(warmup)
.warmupTime(TimeValue.milliseconds(750))
.measurementIterations(iterations)
.measurementTime(TimeValue.milliseconds(500))
.forks(forks)
.include(args1(0))
.resultFormat(ResultFormatType.CSV)

if (args1.length > 1 && args1(1) != "--") {
for ((param, values) <- paramsFromFile("inputs/" ++ args1(1)))
builder = builder.param(param, values: _*)
}

if (args1.length > 2) {
builder = builder.result(args1(2))
}

val runner = new Runner(builder.build)
runner.run
}

def paramsFromFile(file: String): Array[(String, Array[String])] = {
Source.fromFile(file).getLines.toArray.map { l =>
val Array(param, values) = l split ':'
(param, values split ',')
}
}

def printUsage(): Unit = {
println()
println("Usage:")
println()
println("dotty-bench-run/jmh:run [<warmup>] [<iterations>] [<forks>] <regexp> [<input>|--] [<output>]")
println()
println("warmup: warmup iterations. defaults to 20.")
println("iterations: benchmark iterations. defaults to 20.")
println("forks: number of forks. defaults to 1.")
println("regexp: regular expression that selects which benchmarks to run.")
println("input: input vector file. each line should have format \'<paramName>: <comma-separated-values>\'")
println("output: output file for the results of benchmarks.")
println()
}
}
32 changes: 32 additions & 0 deletions bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Apply.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class Apply {
@Param(Array("1 0"))
var sizeAndIndex: String = _
var tuple: NonEmptyTuple = _
var index: Int = _

@Setup
def setup(): Unit = {
val size = sizeAndIndex.split(' ')(0).toInt
index = sizeAndIndex.split(' ')(1).toInt
tuple = "elem" *: ()

for (i <- 1 until size)
tuple = "elem" *: tuple
}

@Benchmark
def tupleApply(): Any = {
DynamicTuple.dynamicApply(tuple, index)
}

@Benchmark
def productElement(): Any = {
tuple.asInstanceOf[Product].productElement(index)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class ArrayOps {
@Param(Array("1"))
var size: Int = _
var tuple: Tuple = _
var array: Array[Object] = _
var iarray: IArray[Object] = _

@Setup
def setup(): Unit = {
tuple = ()

for (i <- 1 to size)
tuple = "elem" *: tuple

array = Array.fill(size)("elem")
iarray = IArray.fill(size)("elem")
}

@Benchmark
def tupleToArray(): Array[Object] = {
DynamicTuple.dynamicToArray(tuple)
}

@Benchmark
def tupleToIArray(): IArray[Object] = {
DynamicTuple.dynamicToIArray(tuple)
}

@Benchmark
def tupleFromArray(): Tuple = {
DynamicTuple.dynamicFromArray(array)
}

@Benchmark
def tupleFromIArray(): Tuple = {
DynamicTuple.dynamicFromIArray(iarray)
}

@Benchmark
def productToArray(): Array[Object] = {
DynamicTuple.productToArray(tuple.asInstanceOf[Product])
}

@Benchmark
def cloneArray(): Array[Object] = {
array.clone()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class Concat {
@Param(Array("0 0"))
var sizes: String = _
var tuple1: Tuple = _
var tuple2: Tuple = _
var array1: Array[Object] = _
var array2: Array[Object] = _

def tupleOfSize(n: Int): Tuple = {
var t: Tuple = ()
for (i <- 1 to n)
t = "elem" *: t
t
}

@Setup
def setup(): Unit = {
val size1 = sizes.split(' ')(0).toInt
val size2 = sizes.split(' ')(1).toInt
tuple1 = tupleOfSize(size1)
tuple2 = tupleOfSize(size2)
array1 = Array.fill(size1)("elem")
array2 = Array.fill(size2)("elem")
}

@Benchmark
def tupleConcat(): Tuple = {
DynamicTuple.dynamicConcat(tuple1, tuple2)
}

@Benchmark
def arrayConcat(): Array[Object] = {
array1 ++ array2
}
}
32 changes: 32 additions & 0 deletions bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Cons.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class Cons {
@Param(Array("0"))
var size: Int = _
var tuple: Tuple = _
var array: Array[Object] = _

@Setup
def setup(): Unit = {
tuple = ()

for (i <- 1 to size)
tuple = "elem" *: tuple

array = Array.fill(size)("elem")
}

@Benchmark
def tupleCons(): Tuple = {
DynamicTuple.dynamicCons("elem", tuple)
}

@Benchmark
def arrayCons(): Array[Object] = {
DynamicTuple.cons$Array("elem", array)
}
}
40 changes: 40 additions & 0 deletions bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Map.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class Map {
@Param(Array("0"))
var size: Int = _
var tuple: Tuple = _
var array: Array[Object] = _

@Setup
def setup(): Unit = {
tuple = ()

for (i <- 1 to size)
tuple = "elem" *: tuple

array = Array.fill(size)("elem")
}

def f: PolyFunction = new PolyFunction {
def apply[T](x: T): T = {
x.asInstanceOf[String].updated(0, 'a').asInstanceOf[T]
}
}

type Id[X] = X

@Benchmark
def tupleMap(): Tuple = {
DynamicTuple.dynamicMap[Tuple, Id](tuple, [T] => (x:T) => x.asInstanceOf[String].updated(0, 'a').asInstanceOf[T])
}

@Benchmark
def arrayMap(): Array[Object] = {
array.map(x => x.asInstanceOf[String].updated(0, 'a'))
}
}
32 changes: 32 additions & 0 deletions bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Tail.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._
import scala.runtime.DynamicTuple

@State(Scope.Thread)
class Tail {
@Param(Array("1"))
var size: Int = _
var tuple: NonEmptyTuple = _
var array: Array[Object] = _

@Setup
def setup(): Unit = {
tuple = "elem" *: ()

for (i <- 1 until size)
tuple = "elem" *: tuple

array = Array.fill(size)("elem")
}

@Benchmark
def tupleTail(): Tuple = {
DynamicTuple.dynamicTail(tuple)
}

@Benchmark
def arrayTail(): Array[Object] = {
array.tail
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package dotty.tools.benchmarks.tuples

import org.openjdk.jmh.annotations._

@State(Scope.Thread)
class TupleOps {
var tuple1: Tuple = _
var tuple2: Tuple = _

@Setup
def setup(): Unit = {
tuple1 = ()
for (i <- 1 until 15)
tuple1 = s"elem$i" *: tuple1

tuple2 = ()
for (i <- 1 until 10)
tuple2 = s"elem$i" *: tuple2
}

def tupleFlatMap(tuple: Tuple, f: [A] => A => Tuple): Tuple = {
def tailRecFlatMap(t: Tuple, acc: Tuple): Tuple = t match {
case () => acc
case x *: rest => tailRecFlatMap(rest, acc ++ f(x))
}
tailRecFlatMap(tuple, ())
}

def tupleReverse(tuple: Tuple): Tuple = {
def tailRecReverse(t: Tuple, acc: Tuple): Tuple = t match {
case () => acc
case x *: rest => tailRecReverse(rest, x *: acc)
}
tailRecReverse(tuple, ())
}

@Benchmark
def reverse(): Tuple = {
tupleReverse(tuple1)
}

@Benchmark
def flatMap(): Tuple = {
tupleFlatMap(tuple2, [A] => (x: A) => (x, x))
}
}
Loading