【发布时间】:2013-10-14 14:37:45
【问题描述】:
Scala 的 REPL 是交互式测试某些代码片段的绝佳场所。最近,我一直在使用 REPL 进行一些性能比较,以重复执行操作并比较测量挂钟时间。
这是我最近创建的一个示例,用于帮助回答 SO 问题 [1][2]:
// Figure out the perfomance difference between direct method invocation and reflection-based method.invoke
def invoke1[T,U](obj:Any, method:Method)(param:T):U = method.invoke(obj,Seq(param.asInstanceOf[java.lang.Object]):_*) match {
case x: java.lang.Object if x==null => null.asInstanceOf[U]
case x => x.asInstanceOf[U]
}
def time[T](b: => T):(T, Long) = {
val t0 = System.nanoTime()
val res = b
val t = System.nanoTime() - t0
(res,t )
}
class Test {
def op(l:Long): Long = (2 until math.sqrt(l).toInt).filter(x=>l%x==0).sum
}
val t0 = new Test
val method = classOf[Test].getMethods.find(_.getName=="op").get
def timeDiff = {
val (timeDirectCall,res) = time { (0 to 1000000).map(x=>t0.op(x)) }
val (timeInvoke, res2) = time { (0 to 1000000).map(x=>{val res:Long=invoke1(t0,method)(x);res}) }
(timeInvoke-timeDirectCall).toDouble/timeDirectCall.toDouble
}
//scala> timeDiff
//res60: Double = 2.1428745665357445
//scala> timeDiff
//res61: Double = 2.1604176409796683
在另一种情况下,我一直在生成随机数据点的 MM,以比较开源项目的并发模型。 REPL 非常适合在没有代码-编译-测试循环的情况下使用不同的配置。
我知道常见的基准测试缺陷,例如 JIT 优化和预热需求。
我的问题是:
在使用时是否需要考虑任何 REPL 特定元素 它执行宏观基准的比较微观?
这些测量值在相互使用时是否可靠?即他们能回答这个问题吗:
A比B快吗?预先执行相同的代码是 jit 的良好热身吗 编译器?
还有其他需要注意的问题吗?
[1]Scala reflection: How to pass an object's method as parameter to another method
【问题讨论】:
-
REPL 将你的代码包装到它自己的内环中(这样你就可以重新定义 vals/vars/functions/classes/objects 并做其他讨厌的事情)所以基本上你要测量的是编译你的代码的时间,包装它的时间,最后是由于pile of reasons而充满不同波动的实际执行时间(但你说你知道最后一个组件不可靠)。 显然这样的测量是不可靠的。
-
@om-nom-nom wrap & compile 基本上是一次性的,这将占一些开销,但这对于任何正在测试的选项来说都是相同的开销,因此相对分数应该仍然具有代表性, 或不?例如在上面的示例中,它显示慢了大约 2 倍,这已经足够了。
标签: scala performance-testing read-eval-print-loop