From 0fba9237fe8b12fe84d25ccb2762d508e0f8bec8 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 8 Sep 2020 15:21:49 +0200 Subject: [PATCH 1/8] Fix source directory --- .../src/main/scala/{ => dotty/tools/benchmarks}/tuples/Drop.scala | 0 .../main/scala/{ => dotty/tools/benchmarks}/tuples/Split.scala | 0 .../src/main/scala/{ => dotty/tools/benchmarks}/tuples/Take.scala | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename bench-run/src/main/scala/{ => dotty/tools/benchmarks}/tuples/Drop.scala (100%) rename bench-run/src/main/scala/{ => dotty/tools/benchmarks}/tuples/Split.scala (100%) rename bench-run/src/main/scala/{ => dotty/tools/benchmarks}/tuples/Take.scala (100%) diff --git a/bench-run/src/main/scala/tuples/Drop.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Drop.scala similarity index 100% rename from bench-run/src/main/scala/tuples/Drop.scala rename to bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Drop.scala diff --git a/bench-run/src/main/scala/tuples/Split.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Split.scala similarity index 100% rename from bench-run/src/main/scala/tuples/Split.scala rename to bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Split.scala diff --git a/bench-run/src/main/scala/tuples/Take.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Take.scala similarity index 100% rename from bench-run/src/main/scala/tuples/Take.scala rename to bench-run/src/main/scala/dotty/tools/benchmarks/tuples/Take.scala From e788487acb559ddeed80a643032d14b22a68c2a3 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 8 Sep 2020 15:28:21 +0200 Subject: [PATCH 2/8] Move input files to correct directory --- bench-run/inputs/map.in | 1 - bench-run/inputs/{ => tuples}/drop.in | 0 bench-run/inputs/{ => tuples}/split.in | 0 bench-run/inputs/{ => tuples}/take.in | 0 bench-run/inputs/zip.in | 1 - 5 files changed, 2 deletions(-) delete mode 100644 bench-run/inputs/map.in rename bench-run/inputs/{ => tuples}/drop.in (100%) rename bench-run/inputs/{ => tuples}/split.in (100%) rename bench-run/inputs/{ => tuples}/take.in (100%) delete mode 100644 bench-run/inputs/zip.in diff --git a/bench-run/inputs/map.in b/bench-run/inputs/map.in deleted file mode 100644 index 4555a56acbc3..000000000000 --- a/bench-run/inputs/map.in +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/bench-run/inputs/drop.in b/bench-run/inputs/tuples/drop.in similarity index 100% rename from bench-run/inputs/drop.in rename to bench-run/inputs/tuples/drop.in diff --git a/bench-run/inputs/split.in b/bench-run/inputs/tuples/split.in similarity index 100% rename from bench-run/inputs/split.in rename to bench-run/inputs/tuples/split.in diff --git a/bench-run/inputs/take.in b/bench-run/inputs/tuples/take.in similarity index 100% rename from bench-run/inputs/take.in rename to bench-run/inputs/tuples/take.in diff --git a/bench-run/inputs/zip.in b/bench-run/inputs/zip.in deleted file mode 100644 index 4555a56acbc3..000000000000 --- a/bench-run/inputs/zip.in +++ /dev/null @@ -1 +0,0 @@ -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 From 6827b9fb4adfa1c0ebf3d021de1ac3389d76b05a Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Tue, 8 Sep 2020 16:55:30 +0200 Subject: [PATCH 3/8] Add specialization benchmarks --- .../benchmarks/specialization/Functions.scala | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala new file mode 100644 index 000000000000..9ae26697b234 --- /dev/null +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -0,0 +1,55 @@ +package dotty.tools.benchmarks.specialization + +import org.openjdk.jmh.annotations._ +import scala.util.Random + +class Functions { + extension (x: Int) + inline def times(op: => Unit): Unit = { + var count = 0 + while count < x do + op + count += x + } + + class ByName { + def foo(x: => Int): Int = x + } + + @Benchmark + def byNameBench() = 10000.times { + val a = new ByName + var list = List(a) + list.head.foo(6) + 10 + } + + @Benchmark + def lambdaBench() = 10000.times { + val fn = (x: Int) => x + 1 + var list = List(fn) + list.head(2) + } + + class Func1[T](fn: T => Int) extends Function1[T, Int] { + def apply(x: T): Int = fn(x) + } + class Fn extends Func1(identity[Int]) + + @Benchmark + def extendFun1Bench() = 10000.times { + val a: Function1[Int, Int] = new Fn + var list = List(a) + list.head(123) + 10 + } + + class Func2 extends Function2[Int, Int, Int] { + def apply(i: Int, j: Int) = i + j + } + + @Benchmark + def extendFun2Bench() = 10000.times { + val a: Function2[Int, Int, Int] = new Func2 + var list = List(a) + list.head(1300, 37) + 100 + } +} From 6fbdfcd52e98c06680f9059840b2c04011e1ea4b Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 10 Sep 2020 09:08:51 +0200 Subject: [PATCH 4/8] Update bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala Co-authored-by: Nicolas Stucki --- .../scala/dotty/tools/benchmarks/specialization/Functions.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala index 9ae26697b234..22a9e8ede748 100644 --- a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -9,7 +9,7 @@ class Functions { var count = 0 while count < x do op - count += x + count += 1 } class ByName { From 2ce8da32ff6455bfda7467945607c6a37610eb1a Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Thu, 10 Sep 2020 16:14:58 +0200 Subject: [PATCH 5/8] Update bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala Co-authored-by: Nicolas Stucki --- .../scala/dotty/tools/benchmarks/specialization/Functions.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala index 22a9e8ede748..0f0b5939c231 100644 --- a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -5,7 +5,7 @@ import scala.util.Random class Functions { extension (x: Int) - inline def times(op: => Unit): Unit = { + inline def times(inline op: Unit): Unit = { var count = 0 while count < x do op From 8818fd47715ef7468acc279bde2876448e19c39f Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 10 Sep 2020 16:25:12 +0200 Subject: [PATCH 6/8] Make sure computation goes to blackhole to prevent optimization --- .../benchmarks/specialization/Functions.scala | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala index 0f0b5939c231..c3cfc1814480 100644 --- a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -5,11 +5,13 @@ import scala.util.Random class Functions { extension (x: Int) - inline def times(inline op: Unit): Unit = { + inline def times(inline work: Int): Int = { + var res = 0 var count = 0 while count < x do - op + res += work count += 1 + res } class ByName { @@ -17,17 +19,17 @@ class Functions { } @Benchmark - def byNameBench() = 10000.times { + def byNameBench(): Int = { val a = new ByName var list = List(a) - list.head.foo(6) + 10 + 10000.times { list.head.foo(6) } } @Benchmark - def lambdaBench() = 10000.times { + def lambdaBench(): Int = { val fn = (x: Int) => x + 1 var list = List(fn) - list.head(2) + 10000.times { list.head(2) } } class Func1[T](fn: T => Int) extends Function1[T, Int] { @@ -36,10 +38,10 @@ class Functions { class Fn extends Func1(identity[Int]) @Benchmark - def extendFun1Bench() = 10000.times { + def extendFun1Bench(): Int = { val a: Function1[Int, Int] = new Fn var list = List(a) - list.head(123) + 10 + 10000.times { list.head(123) } } class Func2 extends Function2[Int, Int, Int] { @@ -47,9 +49,9 @@ class Functions { } @Benchmark - def extendFun2Bench() = 10000.times { + def extendFun2Bench(): Int = { val a: Function2[Int, Int, Int] = new Func2 var list = List(a) - list.head(1300, 37) + 100 + 10000.times { list.head(1300, 37) } } } From cdc14b0958927abe1e1e4d65ee78410b39ade24f Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Thu, 10 Sep 2020 17:01:25 +0200 Subject: [PATCH 7/8] Use explicit state and volatile to avoid optimization --- .../benchmarks/specialization/Functions.scala | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala index c3cfc1814480..8d5145410cad 100644 --- a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -3,13 +3,15 @@ package dotty.tools.benchmarks.specialization import org.openjdk.jmh.annotations._ import scala.util.Random + +@State(Scope.Benchmark) class Functions { extension (x: Int) inline def times(inline work: Int): Int = { var res = 0 var count = 0 while count < x do - res += work + res += work + 1 count += 1 res } @@ -18,40 +20,33 @@ class Functions { def foo(x: => Int): Int = x } + var byName = new ByName + @Benchmark - def byNameBench(): Int = { - val a = new ByName - var list = List(a) - 10000.times { list.head.foo(6) } - } + def byNameBench(): Int = 10000.times { byName.foo(6) } + + var fn = (x: Int) => x + 1 @Benchmark - def lambdaBench(): Int = { - val fn = (x: Int) => x + 1 - var list = List(fn) - 10000.times { list.head(2) } - } + def lambdaBench(): Int = 10000.times { fn(2) } class Func1[T](fn: T => Int) extends Function1[T, Int] { def apply(x: T): Int = fn(x) } class Fn extends Func1(identity[Int]) + var fn1: Function1[Int, Int] = new Fn + @Benchmark - def extendFun1Bench(): Int = { - val a: Function1[Int, Int] = new Fn - var list = List(a) - 10000.times { list.head(123) } - } + def extendFun1Bench(): Int = 10000.times { fn1(12) } + class Func2 extends Function2[Int, Int, Int] { def apply(i: Int, j: Int) = i + j } + var fn2: Function2[Int, Int, Int] = new Func2 + @Benchmark - def extendFun2Bench(): Int = { - val a: Function2[Int, Int, Int] = new Func2 - var list = List(a) - 10000.times { list.head(1300, 37) } - } + def extendFun2Bench(): Int = 1000000.times { fn2(1300, 37) } } From 62339a0bff46925026cf7100055b5b8e304f30b6 Mon Sep 17 00:00:00 2001 From: Liu Fengyun Date: Fri, 11 Sep 2020 16:20:29 +0200 Subject: [PATCH 8/8] Outsmart JVM --- .../benchmarks/specialization/Functions.scala | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala index 8d5145410cad..191e5e9fa2f9 100644 --- a/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala +++ b/bench-run/src/main/scala/dotty/tools/benchmarks/specialization/Functions.scala @@ -20,15 +20,26 @@ class Functions { def foo(x: => Int): Int = x } + // outsmart JVM with storage in mutable array var byName = new ByName + var arrByName = Array(byName, null) @Benchmark - def byNameBench(): Int = 10000.times { byName.foo(6) } + def byNameBench(): Int = 10000.times { + // necessary to outsmart JVM + // remove it will result in 200x speed up + arrByName(1) = null + arrByName(0).foo(6) + } var fn = (x: Int) => x + 1 + var arr = Array(fn, null) @Benchmark - def lambdaBench(): Int = 10000.times { fn(2) } + def lambdaBench(): Int = 10000.times { + arr(1) = null + arr(0)(2) + } class Func1[T](fn: T => Int) extends Function1[T, Int] { def apply(x: T): Int = fn(x) @@ -36,9 +47,13 @@ class Functions { class Fn extends Func1(identity[Int]) var fn1: Function1[Int, Int] = new Fn + var arr1 = Array(fn1, null) @Benchmark - def extendFun1Bench(): Int = 10000.times { fn1(12) } + def extendFun1Bench(): Int = 10000.times { + arr1(1) = null + arr1(0)(12) + } class Func2 extends Function2[Int, Int, Int] { @@ -46,7 +61,11 @@ class Functions { } var fn2: Function2[Int, Int, Int] = new Func2 + var arr2 = Array(fn2, null) @Benchmark - def extendFun2Bench(): Int = 1000000.times { fn2(1300, 37) } + def extendFun2Bench(): Int = 10000.times { + arr2(1) = null + arr2(0)(1300, 37) + } }