Skip to content

Commit

Permalink
Looking at the cost of trait fowarders
Browse files Browse the repository at this point in the history
Hypothesis is that the forwarders in subclasses impose
a cost due to megamorphic virtual calls.

    // Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)
    > jmh:run -i 10 -wi 5 -f2 -t1 .*Mixin.*
    [info] Benchmark                                  (count)   Mode  Cnt         Score        Error  Units
    [info] MixinForwarderBenchmark.baseClass_1             16  thrpt   20  18537399.061 ± 521221.353  ops/s
    [info] MixinForwarderBenchmark.baseClass_16            16  thrpt   20  19137762.320 ± 510049.157  ops/s
    [info] MixinForwarderBenchmark.baseTrait_1             16  thrpt   20  18178697.687 ± 404180.617  ops/s
    [info] MixinForwarderBenchmark.baseTrait_16            16  thrpt   20  10786408.479 ± 162705.033  ops/s
    [info] MixinForwarderBenchmark.jbaseInterface_1        16  thrpt   20  18531993.312 ± 401611.669  ops/s
    [info] MixinForwarderBenchmark.jbaseInterface_16       16  thrpt   20   9642052.651 ± 228326.457  ops/s
    [success] Total time: 188 s, completed 22/04/2016 6:39:08 PM
  • Loading branch information
retronym committed Apr 22, 2016
1 parent 637d3d8 commit 3b4594c
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 0 deletions.
140 changes: 140 additions & 0 deletions src/main/scala/scala/tools/nsc/MixinForwarderBenchmark.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package scala.tools.nsc

import java.util.Random

import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole

import scala.annotation.meta.{field, getter}

@State(Scope.Thread)
class MixinForwarderBenchmark {
class C {
def foo = 42
}
class C_1 extends C
class C_2 extends C
class C_3 extends C
class C_4 extends C
class C_5 extends C
class C_6 extends C
class C_7 extends C
class C_8 extends C
class C_9 extends C
class C_10 extends C
class C_11 extends C
class C_12 extends C
class C_13 extends C
class C_14 extends C
class C_15 extends C
class C_16 extends C
trait T {
def foo = 42
}
class T_1 extends T
class T_2 extends T
class T_3 extends T
class T_4 extends T
class T_5 extends T
class T_6 extends T
class T_7 extends T
class T_8 extends T
class T_9 extends T
class T_10 extends T
class T_11 extends T
class T_12 extends T
class T_13 extends T
class T_14 extends T
class T_15 extends T
class T_16 extends T

@(Param @field)(Array("16"))
private[this] var count: Int = 0

private[this] var zero: Int = 0

private[this] val cs_16 = Array(new C_1, new C_2, new C_3, new C_4, new C_5, new C_6, new C_7, new C_8, new C_9, new C_10, new C_11, new C_12, new C_13, new C_14, new C_15, new C_16)
private[this] val ts_16 = Array(new T_1, new T_2, new T_3, new T_4, new T_5, new T_6, new T_7, new T_8, new T_9, new T_10, new T_11, new T_12, new T_13, new T_14, new T_15, new T_16)
import MixinForwarderBenchmarkSupport._
private[this] val js_16 = Array[J](new J_1, new J_2, new J_3, new J_4, new J_5, new J_6, new J_7, new J_8, new J_9, new J_10, new J_11, new J_12, new J_13, new J_14, new J_15, new J_16)

private[this] var cs_16_random: Array[C] = _
private[this] var ts_16_random: Array[T] = _
private[this] var js_16_random: Array[J] = _

@Setup
def create(): Unit = {
val r = new Random()
cs_16_random = Array.tabulate(count) {
_ => cs_16.apply(r.nextInt(cs_16.length))
}

ts_16_random = Array.tabulate(count) {
_ => ts_16.apply(r.nextInt(ts_16.length))
}

js_16_random = Array.tabulate(count) {
_ => js_16.apply(r.nextInt(js_16.length))
}
}

@Benchmark
def baseClass_1(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(cs_16_random(zero))
i += 1
}
}

@Benchmark
def baseClass_16(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(cs_16_random(i).foo)
i += 1
}
}

@Benchmark
def baseTrait_1(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(ts_16_random(zero).foo)
i += 1
}
}

@Benchmark
def baseTrait_16(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(ts_16_random(i).foo)
i += 1
}
}

@Benchmark
def jbaseInterface_1(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(js_16_random(zero).foo)
i += 1
}
}

@Benchmark
def jbaseInterface_16(bh: Blackhole): Unit = {
var i = 0
val c = count
while (i < c) {
bh.consume(js_16_random(i).foo)
i += 1
}
}
}
23 changes: 23 additions & 0 deletions src/main/scala/scala/tools/nsc/MixinForwarderBenchmarkSupport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package scala.tools.nsc;

public class MixinForwarderBenchmarkSupport {
interface J {
default int foo() { return 42; }
}
public static class J_1 implements J {}
public static class J_2 implements J {}
public static class J_3 implements J {}
public static class J_4 implements J {}
public static class J_5 implements J {}
public static class J_6 implements J {}
public static class J_7 implements J {}
public static class J_8 implements J {}
public static class J_9 implements J {}
public static class J_10 implements J {}
public static class J_11 implements J {}
public static class J_12 implements J {}
public static class J_13 implements J {}
public static class J_14 implements J {}
public static class J_15 implements J {}
public static class J_16 implements J {}
}

2 comments on commit 3b4594c

@lrytz
Copy link
Member

@lrytz lrytz commented on 3b4594c Apr 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the scala code is compiled with 2.11.x?

@retronym
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep

Please sign in to comment.