マシンサイクルの計測

昨日の日記(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回