パフォーマンスの測定 | Programming Place Plus アルゴリズムとデータ構造編【導入】 第2章

トップページアルゴリズムとデータ構造編

この章の概要

この章の概要です。


処理時間の測定

前章では、計算量を用いて、アルゴリズムの性能(パフォーマンス)を評価する考え方を示しました。しかし、計算量が優れていても、実際のプログラムが十分に高速に動作しなければ意味がありません。

先に断っておくと、すべてのプログラムが必ずしも高速に動作しなければならないわけではありません。そのプログラムの目的を必要十分に達成できているのであれば、それ以上高速にする必要性はまったくないといえます。また、プログラムを高速化する方法は、この章が扱う範囲ではありません。


ところで、プログラムを改良して、高速化を図ったとします。しかし、本当に高速化されたかどうか判断するには、実測に頼るしかありません。「××× という高速化策を講じたので、高速になっているはず」と考えることは危険です。コンピュータやコンパイラは、とても複雑なものであって、どんなコードを書くとプログラムの速度がどう変わるかを想像することは困難です。プログラマーの想像はほとんど当たらないと思ったほうがいいです。

そのため、処理時間を簡単に測定できるようにしておくと便利です。C言語であれば、clock関数を使うのが簡単です。

#include <stdio.h>
#include <time.h>

static void process(void);

int main(void)
{
    clock_t begin = clock();
    process();
    clock_t end = clock();

    printf( "result: %f seconds\n", (double)(end - begin) / CLOCKS_PER_SEC );

    return 0;
}

void process(void)
{
    char buf[80];

    puts( "何か入力すると終了します。" );
    fgets( buf, sizeof(buf), stdin );
}

実行結果

何か入力すると終了します。
abcde
result: 3.679000 seconds

処理時間を計測したい箇所を挟み込むように、clock関数を呼び出し、その戻り値を保存します。その差分を取り、CLOCKS_PER_SEC で割ると、秒単位の結果が取得できます。

clock関数ではうまく計測できない環境もあります。その場合は、その環境に用意されている他の手段を探してください。

計測したい部分が、非常に短時間で通過してしまう場合、結果が 0.000000 のようになってしまい計測できないことがあります。こういう場合は、その部分を何度もループさせるようにするなどの工夫を加えると良いでしょう。


ごく簡単に実行速度を計測するには、ここで取り上げた方法で十分ですが、実際にはさまざまな要因で速度は変化することに注意が必要です。たとえば、コンピュータが実行しているプログラムは、自分のプログラムだけとは限りません(同時に Webブラウザを開いていたら、そちらにもコンピュータの処理能力は割かれているはずです)。

少しでも計測の信用度を高めるには、ほかのプログラムの実行を止めたり、マウスなどの入力装置を触らないようにしたりして、とにかく余計な処理を同時に行わせないようにします。

また、もっと厳密な計測が必要なら、パフォーマンス測定専用のツールを使う検討もするといいでしょう。

測定用マクロ

C言語では、先ほどのサンプルプログラムのように、clock関数を利用して時間を測定できますが、準備することが多くて面倒です。具体的には、以下のような要求があります。

最後の1つには触れていませんでしたが、デバッグのために使ったコードは、本番コードでも #if(C言語編第23章参照)を使うなどして無効にした状態で残しておいた方が良いでしょう。デバッグコードは、プログラムに何らかの手を加えるたびに、再確認する機会が多いので、そのたびに作り直すのは開発時間を無駄に浪費します。

毎回、こんな面倒なことを書くのは嫌なので、自分用のライブラリの中にマクロを作っておくと良いでしょう。たとえば、次のようなヘッダファイルを作ります。

/*
    ppp_perform.h

    パフォーマンス測定
*/

#ifndef PPP_PERFORM_H_INCLUDED
#define PPP_PERFORM_H_INCLUDED

#include <time.h>


/*
    パフォーマンス測定を開始する。
    引数:
        times:  測定回数。

    使い方:
        PPP_CHECK_PERFORM_BEGIN(1000);  <-- PPP_CHECK_PERFORM_END までの範囲を 1000回繰り返す
        func();                         <-- 測定したい処理
        PPP_CHECK_PERFORM_END("func");  <-- 測定したい処理を 1000回繰り返した測定結果を出力

    備考:
        PPP_DISABLE_PERFORM が定義されているときには、何もしない。
*/
#ifdef PPP_DISABLE_PERFORM
#define PPP_CHECK_PERFORM_BEGIN(times)    // 何もしない
#else
#define PPP_CHECK_PERFORM_BEGIN(times)             \
    {                                              \
        clock_t check_perform_begin = clock();     \
        for(int check_perform_i = 0; check_perform_i < times; ++check_perform_i){
#endif


/*
    パフォーマンス測定を終了する。
    引数:
        title:  結果のメッセージの先頭に出力する見出し文字列。

    備考:
        PPP_DISABLE_PERFORM が定義されているときには、何もしない。
*/
#ifdef PPP_DISABLE_PERFORM
#define PPP_CHECK_PERFORM_END(times)    // 何もしない
#else
#define PPP_CHECK_PERFORM_END(title)         \
        }   /* for の終わり */          \
        clock_t check_perform_end = clock();         \
        printf( "%s: %f seconds\n", title, (double)(check_perform_end - check_perform_begin) / CLOCKS_PER_SEC ); \
    }   // 計測範囲の終わり
#endif


#endif

これを用意しておけば、測定を次のように行えます。

#include <stdio.h>
#include "ppp_perform.h"

static void process(void);

int main(void)
{
    PPP_CHECK_PERFORM_BEGIN(1);
    process();
    PPP_CHECK_PERFORM_END("result");

    return 0;
}

void process(void)
{
    char buf[80];

    puts( "何か入力すると終了します。" );
    fgets( buf, sizeof(buf), stdin );
}

実行結果

何か入力すると終了します。
abcde
result: 3.679000 seconds

計測を無効にしたければ、ppp_perform.h を #include する前に、PPP_DISABLE_PERFORM を定義します。

#define PPP_DISABLE_PERFORM
#include "ppp_perform.h"


参考リンク


更新履歴

’2015/2/21 サンプルプログラムで、ファイルスコープでよい関数に static を付加。

’2012/1/2 「測定用マクロ」の項の perform.h を、コードライブラリで公開しているものに差し替え。

’2011/11/5 「測定用マクロ」の項を追加。

’2011/10/31 新規作成。



前の章へ (第1章 計算量)

アルゴリズムとデータ構造編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る