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 编译器的良好预热吗?
还有其他需要注意的问题吗?