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 を使用してマクロ ベンチマークの比較ミクロを実行する際に考慮すべき REPL 固有の要素はありますか?
これらの測定値は、互いに相対的に使用した場合に信頼できますか? つまり、彼らは次の質問に答えることができますか: は
A
より速いですB
か?同じコードの予備実行は、jit コンパイラーのウォームアップに適していますか?
他に注意すべき問題はありますか?