プログラムの性能を測定するにはどうすればよいでしょうか? すぐに思いつくのは,プログラムの実行時間を測定することです。しかし,現在のコンピュータの環境では,プログラムの実行が常に一定の速度で行われる保証はありません。また,Haskellではすべての値が遅延評価されるという事情もあります。

 そこで,今回はHaskellプログラムの性能を測定するために用意されているベンチマーク・フレームワークである「criterionパッケージ」について説明します。

ベンチマーク・フレームワークを使うべき理由

 プログラムの性能を測定する手軽な方法は,timeやtimeit.exeを使ってプログラムの実行時間を計ることです。しかし,OSの上では様々なプロセスが動作しており,それによってプログラムの実行時間にばらつきが生じます。ほかにも,実行時間にばらつきを生じさせる要因は数多く存在します。ばらつきを生じさせるすべての要因を除去することは困難です。信頼できる測定結果を得るには,測定を複数回行って統計的に評価する必要があります(参考リンク)。

 また,timeやtimeit.exeには,プログラム全体の実行時間しか測定できないという欠点があります。例えば,リストや配列といった各データ構造ごとにsort関数の性能を調べようとする場合,プログラム全体の実行時間には,「sort関数に渡すデータ構造を準備する時間」と「sort関数の実行時間」の両方が含まれます。もし,データ構造を準備する時間の割合が大きければ,sort関数の実行時間を正確に比較することはできません。この問題に対処するには,事前準備を行う処理を性能測定の対象から分離しておく必要があります。

 一般的には,プログラムの性能を測定するには,性能測定を行うコードをソースコードに埋め込むという手法がよく使われます。しかし,Haskellでは基本的にはすべての値が遅延評価されます。このため,性能測定を行うコードをソースコードに埋め込む場合には,「事前準備の処理」と「性能測定を行う比較対象のコード」が別々に評価されるようにソースコードの中で明示的に指定する必要があります。

 性能評価の際にメモリーが不足すると,ガーベジ・コレクション(GC)や新たなメモリーの確保により,測定結果がゆがんでしまうという問題もあります。この問題を避けるには,System.MemモジュールのperformGC関数を使用してGCを強制的に実行した後に,性能測定を行う必要があります。

 このように,性能を正しく測定するには,複数回の測定を統計結果としてまとめるための仕組みや,Haskellプログラムの評価・実行方法に対する様々な知識が必要です。そこで,ユーザーがHaskellの基礎的な知識しか持っていなくても性能を正確に測定できるように用意されているのが,ベンチマーク・フレームワークです。今回,紹介するcriterionは,その代表的なものです(参考リンク1参考リンク2)。