Gaucheでベンチマーク

Gaucheでベンチマークするためのマクロを組んでみました。github.com

ベンチマーク取るならgauche.timeかsrfi-19でだいたい事足りるはずなんですが、

  • ベンチマークのためのcounterについて、実コードを書く上であまり意識したくなかった
    • ベンチマークするまでに必要な手順を減らしたい
    • 実コードの広いスコープにcounterが見えてると気になる
  • ベンチマークの関数には、対象の式の実行時間を計測した上で返り値としてはその対象の式の結果を返して欲しい場面があった
    • 例えば、
gosh> (bench (+ 1 1))
<実行時間の出力>
2 <= 式の結果を返す

という理由から書きましたmm


コード

  (define-syntax bench
    (syntax-rules ()
                  ((_ exprs) (bench-with-msg exprs (quote exprs)))
                  ((_ msg exprs) (bench-with-msg exprs msg))))

  (define-macro (bench-with-msg exprs msg)
                (let1 counter (gensym)
                      `(let1 ,counter (make <real-time-counter>)
                             (dynamic-wind
                               (lambda () (time-counter-start! ,counter))
                               (lambda () ,exprs)
                               (lambda () (begin
                                            (time-counter-stop! ,counter)
                                            (print "** " ,msg ": " (time-counter-value ,counter))))))))

だいたい動く(はず)

gosh> (bench (+ 1 1))
** (+ 1 1): 5.0e-6
2
gosh> (bench (sys-sleep 1))
** (sys-sleep 1): 1.000249
0
gosh> (bench "with msg" (+ 1 1))
** with msg: 4.0e-6
2
gosh> (bench "2?" (begin
              (sys-sleep 1)
              (bench "1?" (sys-sleep 1))))
** 1?: 1.002626
** 2?: 2.007946
0
gosh> (dotimes (i 3) (bench "1?" (sys-sleep 1)))
** 1?: 1.005189
** 1?: 1.004585
** 1?: 1.00527
#t

(let1 counter "it's a dummy counter"
      (bench "variable capture ok?" (print counter)))
it's a dummy counter
** variable capture ok?: 2.6e-6
#<undef>

これで、こんな感じにベンチできます。

(let* ((a (bench "ベンチマーク取りたくなる何かしらの重い処理1"))
       (b (bench "ベンチマーク取りたくなる何かしらの重い処理2")))
  (bench "a,bの結果を使って何か処理する式"))
** ベンチマーク取りたくなる何かしらの重い処理1: 4.0e-6
** ベンチマーク取りたくなる何かしらの重い処理2: 2.0e-6
** a,bの結果を使って何か処理する式: 2.0e-6
"a,bの結果を使って何か処理する式"

© karahiyo