マシンサイクルの計測
昨日の日記(id:giuseppe:20070310)では、処理時間の計測とゆうことでStopWatchというAPIを紹介しました。
let sw:StopWatch = {StopWatch} {sw.start} ||処理 {output {sw.elapsed}}
もうひとつ、curlにはプログラムのパフォーマンスを測定するためのAPIとして、count-cycles および count-proc-cycles というものがあります。これらはともに、コードの実行に要したマシンサイクル数を報告してくれます。
昨日の日記では、ふたつのDateTimeオブジェクトを引き算することによって経過時間を求めるコードについて触れました。そのためのコードを count-cycles を使って計測するためには、例えば以下のように記述します。
{count-cycles {do let dt:DateTime = {DateTime} {DateTime} - dt } }
count-cycles には、計測したいコードをひとつのコードブロックとして渡す必要があるため、上記のように通常は do ステートメントを用いることになると思います。count-cycles は、与えられたコードを指定された回数*1繰り返し実行し、そのうちで要した最小のサイクル数を戻り値として返します。ちなみに上記の処理は、手元のマシンでは 2548 という数値が返ってきました。
同様に、StopWatchを用いたコードも計測してみます。次の例では、StopWatchインスタンスの生成はあらかじめ行っておき、時間計測のためのstart、elapsedメソッドの呼出しのみをひとつのコードブロックとして、そのサイクル数を調べています。
{let sw:StopWatch = {StopWatch}} {count-cycles {do {sw.start} {sw.elapsed} }, {do {sw.stop} {sw.reset} } }
ここで、count-cycles のふたつ目の引数として渡しているコードブロックは、リセット処理のためのものです。ひとつめのコードブロックが実行された後、次の繰り返し処理の直前に実行されますが、最初の例のように省略することができます。この例では、ひとつ目のコードブロックでstartされたStopWatchを、リセット処理の部分で初期化しています。ちなみに、このコードの結果は 2028 となりました。最初の DateTime の場合と比べて約20%小さいことが分かります。
今回は count-cycles の例のみ紹介しましたが、count-proc-cycles も同様の目的で使うことができます。count-proc-cycles の場合は、コードブロックではなく、プロシージャを引数として受け取ることが異なります。詳しくはAPIリファレンスのドキュメントを参照してください。
[追記]
count-cycles の例で示したふたつのコードは、サイクル数の結果が約20%異なりましたが、これはふたつの方法で計測される経過時間自体が20%程度異なることを意味するわけではありません。おそらく得られる経過時間の精度の差は20%よりももっと小さくなるはずです。念のため
*1:デフォルトは100回