浮動小数点演算のベンチマーク(デュアルCPU編)


ここに1,000,000個の3次方程式を解くベンチマークプログラムのことを書いたが, PC改造マニアである友人に 同じプログラムをAbit BP6+Celeron 300A@450MHz*2+128MB+Win2Kの 環境でテストしてもらったところ,8.765秒であった. この結果はPentium!!! 600MHzよりも約2秒遅い.

以下の図は,Win2Kのパフォーマンスで見たプログラム実行中の両CPU負荷の推移である. 青と緑が両CPUの負荷を示しており,赤はトータルの負荷を示している. この図から,プログラムがシングルスレッドのために片方のCPUだけが忙しくなっていることがわかる. そのためクロックの分だけPentium!!! 600MHzよりも遅くなっているのだろう.


図1 プログラム実行時のCPU負荷推移(シングルスレッド)

デュアルCPUの優位性を検証するために,プログラムをマルチスレッドにし, 1,000,000個の3次方程式を2個のCPUで500,000個ずつ計算するように書き直してみた. 書き直したコードを以下に示す. 後半部分はここに書いてあるコードと同じであるから省略した.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <windows.h>

#define PI 3.14159265358979323846264
#define number_of_equations 500000

int cubic_equation( double a, double b, double c, double d, double roots[] );

/* サブスレッド */
DWORD WINAPI sub_thread( LPARAM lParam ){

    double a, b, c, d, roots[ 3 ];
    int i, n;
    DWORD started, terminated;

    started = GetCurrentTime(); 
    for ( i = 1; i <= number_of_equations; i++ ){
        a = rand(); b = rand(); c = rand(); d = rand();
        if ( a != 0 ) n = cubic_equation( a, b, c, d, roots );
    }
    terminated = GetCurrentTime();
    printf( "second thread: total %g seconds\n", ( terminated - started ) * 1e-3 );
    return 0;
}

/* メインスレッド */
int main(){

    double a, b, c, d, roots[ 3 ];
    int i, n;
    DWORD started, terminated, thread_id;
    HANDLE hThread;

    started = GetCurrentTime(); 

    /* サブスレッドを作成 */
    hThread = CreateThread( NULL, 0, ( LPTHREAD_START_ROUTINE )sub_thread, 
                            NULL, 0, &thread_id );

    for ( i = 1; i <= number_of_equations; i++ ){
        a = rand(); b = rand(); c = rand(); d = rand();
        if ( a != 0 ) n = cubic_equation( a, b, c, d, roots );
    }

    /* 念のため,サブスレッドが終了するまで待つ */
    WaitForSingleObject( hThread, INFINITE );
    CloseHandle( hThread );

    terminated = GetCurrentTime();
    printf( "first thread:  total %g seconds\n", ( terminated - started ) * 1e-3 );
    return 0;
}
CreateThead関数によってサブスレッドを作り出す. 今の場合,スレッドのセキュリティおよびスタックサイズはデフォルトのままでよいので, 1番目および2番目の引数にはそれぞれNULLおよび0を渡す. 3番目の引数はサブスレッド関数のアドレスであり, LPTHREAD_START_ROUTINEでキャストする. 4番目の引数はサブスレッド関数に渡すパラメータである. ここでは何も渡さないのでNULLを指定する. 5番目の引数はサブスレッドの動作開始時期を指定するもので, 今の場合はスレッド作成と同時に処理を開始するので0を渡す. 最後の引数はサブスレッドのIDを受け取るDWORD値へのポインタである.

上記コードをVisual C/C++ 5.0でコンパイルし,まずSingle CPUのPentium!!! 600MHzで実行してみた. 結果は

second thread: total 7.22 seconds
first thread:  total 7.32 seconds
となり,シングルスレッドのときよりも0.5秒ほど遅くなってしまった. これはタスク切替等のオーバーヘッドが発生するためだろう.

次にDual CPUのBP6で実行してみた. 結果は5.453秒でありシングルスレッドのときより3秒以上短くなった. またシングルスレッドのときのPentium!!! 600MHzよりも1秒以上速い. CPU負荷推移の結果を図2に示すが, 両方のCPUの負荷がほぼ100%で推移していることがわかる. マルチスレッドにすればデュアルCPUの優位性が生きてくることが確認できた.


図2 プログラム実行時のCPU負荷推移(マルチスレッド)

忙しい中,貴重なデータを提供して くれた友人に感謝する.


お問い合わせはメールにて: akasaka@klc.ac.jp

戻る
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送