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

先頭へ戻る

このエントリーをはてなブックマークに追加

この章の概要

この章の概要です。

処理時間の測定

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

先に断っておくと、全てのプログラムが必ずしも高速に動作しなければならない訳ではありません。 そのプログラムの目的を必要十分に達成できているのであれば、それ以上高速にする必要性はまったく無いと言えます。

どのようにプログラムを高速化できるかは、この章が扱う範囲ではありませんが、 何らかの対策を講じたとして、本当に高速化されたかどうか判断するには、実測に頼るしかありません。
思い込みで、「×××という対策を講じたので高速になっているはず」と考えることは危険です。 特に現代のコンピュータは非常に複雑ですから、プログラマの想像する通りには高速化されない可能性は高いです。

という訳で、処理時間を簡単に測定できるようにしておくと便利です。 C言語であれば、clock関数(⇒リファレンス)を使うのが簡単です。

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

static void process(void);

int main(void)
{
	clock_t begin, end;

	begin = clock();
	process();
	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 のようになってしまい計測できないことがあります。 こういう場合は、その部分を何度もループさせるようにする等の工夫を加えると良いでしょう。

測定用マクロ

C言語では、先ほどのサンプルのように clock関数を利用して測定できますが、結構準備することが多くて面倒です。 具体的には、

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

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

/*
	ppp_perform.h
	
	パフォーマンス測定
*/

#ifndef PPP_PERFORM_H
#define PPP_PERFORM_H

#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_t check_perform_end;          \
		int check_perform_i;                \
		                                    \
		check_perform_begin = clock();      \
		for(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 の終わり */           \
		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 新規作成。



前の章へ

次の章へ

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

Programming Place Plus のトップページへ