マルチコアCPU環境でのスレッド数

マルチスレッド自体は結構使っているのだが、パフォーマンスに関してはちゃんと測定したことがなかったので、簡単な測定プログラムを作って測ってみることにした。


今回は Windows 上で作業中だったので、WinAPI を使用している。

#ifdef _WINDOWS
#include <Windows.h>
#elif __MINGW32__
#include <windows.h>
#include <winbase.h>
#endif

#include <process.h>
#include <stdio.h>

#include <xmmintrin.h>
#include <emmintrin.h>

const int VALUE = 90000000;
const int thread_num = 2;
const int NUM = 10;

struct SSS
{
    int start;
    int end;
    volatile bool work_start;
    volatile bool work_end;
//  bool work_start;
//  bool work_end;

    int* val;
};

unsigned int __stdcall func(void* p)
{
    SSS* s = (SSS*)p;

    while (!s->work_start)
    {
        Sleep(1);
        _mm_lfence();
    }

    for (int i = 0; i < NUM; i++)
    {
        for (int j = s->start; j < s->end; j++)
        {
            s->val[j] = s->val[j] * s->val[j];
        }
    }

    s->work_end = true;

    _mm_sfence();

    return 0;
}

int main(int argc, char** argv)
{
    SSS* s = new SSS[thread_num];

    int* val = new int[VALUE];

    for (int i = 0; i < thread_num; i++)
    {
        s[i].start = VALUE / thread_num * i + ((i == 0) ? 0 : 1);
        s[i].end = VALUE / thread_num * (i + 1);
        s[i].work_start = false;
        s[i].work_end = false;
        s[i].val = val;

        printf("s[%d].start = %d\n", i, s[i].start);
        printf("s[%d].end = %d\n", i, s[i].end);
    }

    for (int i = 0; i < VALUE; i++)
    {
        val[i] = i + 1;
    }

    HANDLE t[thread_num];

    DWORD start_time = timeGetTime();

    for (int i = 0; i < thread_num; i++)
    {
        t[i] = (HANDLE)_beginthreadex(NULL, 0, 
            func, &s[i], 0, NULL);
    }

    printf("start : %d\n", start_time);

    for (int i = 0; i < thread_num; i++)
    {
        s[i].work_start = true;
    }

    _mm_sfence();

    for (int i = 0; i < thread_num; i++)
    {
        s[i].val = val;
    }

    while (1)
    {
        bool end_ok = true;

        for (int i = 0; i < thread_num; i++)
        {
            if (!s[i].work_end)
            {
                end_ok = false;
            }
        }

        if (end_ok)
        {
            break;
        }

        Sleep(1);
        _mm_lfence();
    }

    DWORD end_time = timeGetTime();

    printf("end : %d\n", end_time);

    for (int i = 0; i < thread_num; i++)
    {
        WaitForSingleObject(t[i], INFINITE);
    }

    for (int i = 0; i < thread_num; i++)
    {
        CloseHandle(t[i]);
    }

    delete[] s;

    delete[] val;

    printf("time : %d\n", end_time - start_time);

    return 0;
}





測定結果(5回だけ)
使用CPU : Pentium D 2.80GHz(2コア)


・1スレッド
time : 7265
time : 7344
time : 7312
time : 7360
time : 7297


・2スレッド
time : 4422
time : 4344
time : 4328
time : 4359
time : 4406


・5スレッド
time : 4360
time : 4328
time : 4343
time : 4297
time : 4390


・20スレッド
time : 4281
time : 4250
time : 4250
time : 4281
time : 4266


・100スレッド
time : 4234
time : 4250
time : 4234
time : 4250
time : 4234


大体1.6倍〜1.7倍ぐらいパフォーマンスが上がっている。
おそらく Core 2 Duo なら更に上がると思う。


本当は1コアや4コアでも動作確認がしたいのだが、手元にないので断念した。
このプログラムは単純なものだが、やはり重い処理をコア数より多くに分割しても意味がないようだ。
よく見ると、スレッド数が増えるごとに若干パフォーマンスは上がっているが、実用的なアプリケーションは裏で監視スレッドとか色々動いてたりするので、そっちに回したほうがいいだろう。


【追記】
64bit Linux + Mingw + wine でもやってみた。


・1スレッド
time : 6734
time : 6795
time : 6985
time : 6941
time : 6736


・2スレッド
time : 3891
time : 4014
time : 3753
time : 3782
time : 3807


Linux 上のほうがパフォーマンスが高くなったが、VC++デバッグコンパイルだし、色々と条件違うから仕方ないか。