斯卡拉的REPL是一個美妙的遊樂場,可以交互地測試某些代碼段。最近,我一直在使用REPL進行一些性能比較,以反覆執行操作和相對測量掛鐘時間。將Scala的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
[2] https://gist.github.com/maasg/6808879
REPL將你的代碼包裝到它自己的內環中(所以你可以重新定義vals/vars/functions/classes/objects並做其他討厭的事情),所以基本上你要測量的是編譯代碼的時間,包裝它的時間最後由於[一堆理由],實際執行時間充滿了不同的波動(但你說你知道最後一個組件不可靠)。 **顯然這種測量不可靠**。 –
@ om-nom-nom換行和編譯基本上是一次性的,這會佔用一些開銷,但是對於任何正在測試的選項來說,這將是相同的開銷,所以相對分數應該仍然具有代表性,或者不是?例如在上面的例子中,它顯示了一個粗略的2倍慢,這是足夠的信息。 – maasg