PR

WindowsのSleep()の精度とtimeBeginPeriod()

指定した待ち時間を得るSleep()。ms(ミリ秒)単位で設定できるが、調べてみたら思いの外精度が悪い。元々いいとは思っていなかったのだけど、こんなに悪いのかと。

timeBeginPeriod()を使うと精度の指定ができるそうなので、それも確認するテストプログラムを書いてみた。

#define LOOP_NUM    10

#include <iostream>
#include <stdio.h>
#include <windows.h>

#pragma comment(lib, "winmm.lib")

int main()
{
    int i;

    std::cout << "Seep 10, 20, 50, 100ms\n";

    for (i = 0; i < LOOP_NUM; i++) {
        DWORD start_10 = timeGetTime();
        Sleep(10);
        DWORD end_10 = GetTickCount();

        DWORD start_20 = timeGetTime();
        Sleep(20);
        DWORD end_20 = GetTickCount();

        DWORD start_50 = timeGetTime();
        Sleep(50);
        DWORD end_50 = GetTickCount();

        DWORD start_100 = timeGetTime();
        Sleep(100);
        DWORD end_100 = GetTickCount();

        printf("%3d %3d %3d %3d\n", (end_10 - start_10), 
            (end_20 - start_20), (end_50 - start_50), (end_100 - start_100));
    }

    std::cout << "\ntimeBeginPeriod()\n";

    for (i = 0; i < LOOP_NUM; i++) {
        timeBeginPeriod(1);

        DWORD start_10 = timeGetTime();
        Sleep(10);
        DWORD end_10 = GetTickCount();

        DWORD start_20 = timeGetTime();
        Sleep(20);
        DWORD end_20 = GetTickCount();

        DWORD start_50 = timeGetTime();
        Sleep(50);
        DWORD end_50 = GetTickCount();

        DWORD start_100 = timeGetTime();
        Sleep(100);
        DWORD end_100 = GetTickCount();

        timeEndPeriod(1);

        printf("%3d %3d %3d %3d\n", (end_10 - start_10),
            (end_20 - start_20), (end_50 - start_50), (end_100 - start_100));
    }
}

何の工夫もないベタ書き。10ms、20ms、50ms、100msSleepの前後で時刻を取得してその差分を表示。さらに、timeBeginPeriod()を使った場合も同様に計測・表示。これを10回繰り返す。

実行環境はWindows 10。

Seep 10, 20, 50, 100ms
 15  31  57 108
 14  31  63 139
 32  25  55 118
 28  36  60 110
 25  32  62 109
 16  33  61 112
 24  14  54 118
 47  37  68 115
 19  34  65 114
 21  36  68 115

timeBeginPeriod()
  5  25  67  96
  9  25  48  92
  7  27  53  96
 10  15  56  99
 14  18  44 104
  3  23  49 107
 16  36  73 122
  8  25  51  94
  8  13  55  97
 10  15  56  99

かなりバラバラ。こんなだから、実行する度にだいぶ違う。

Seep 10, 20, 50, 100ms
 15  26  57 103
 11  26  60 105
 11  28  57 104
 13  30  61 103
 34  30  60 109
 14  30  64 109
 16  32  63 108
 16  31  62 111
 13  31  63 110
 19  33  63 110

timeBeginPeriod()
 -1  19  45 103
  2  22  48  90
  6  10  52  95
  7  12  54  96
 11  16  42 102
  1  22  48  92
  7  12  39  97
  9  12 100 137
 22  21  47 102
 21  29  49  92
Seep 10, 20, 50, 100ms
 16  23  53 101
  6  23  51 102
 16  20  53 103
  8  26  57 103
  9  24  56 101
  8  24  55 103
  8  24  54 100
  6  24  54 101
  6  22  55 103
  8  27  58 105

timeBeginPeriod()
  8  12  53  96
  0  20  46 105
  3  23  49  92
  6  11  51  92
  7  11  53  96
  9  24  48  91
  6  10  52  96
  9  13  39  98
 14  17  43 102
  1  21  47  89
Seep 10, 20, 50, 100ms
 32  30  48 100
  8  24  54 102
  8  23  55 102
 18  23  71 110
 39  16  55 101
 10  26  54 104
  7  22  54 100
  5  22  54 102
 33  32  60 101
 14  30  61 109

timeBeginPeriod()
 11  15  41  99
 14  19  45 102
  1  20  46  99
 15  20  46 104
  3  23  49  93
  7  13  39  98
 13  18  43 117
 12  42  49 113
 12  23  49 100
  0  20  46  89
Seep 10, 20, 50, 100ms
 47  41  83 123
 27  62 103 124
 30  47  63 125
 29  42  62 126
 29  45  75 123
 14  47  61 110
 16  32  63 126
 14  31  64 112
 31  31  79 113
 19  36  68 112

timeBeginPeriod()
 21  25  52 111
 26  31  57 116
 15  34  60 104
 19  22  64 116
 15  35  61 105
 20  24  50 110
 24  29  56 114
 14  34  61 104
 19  23  65 107
 22  27  53 112

timeBeginPeriod()を使わない場合は全体的に遅いという印象だけど、そうとも言えない場合もある。

timeBeginPeriod()を使うと遅さ(オーバヘッド時間みたいな感じ)は減るが、指定時間よりも短くなることもある。特に、時間が短いと影響(割合)が大きい。

バラツキはどっちもどっちだなぁ。

しかし、これほどまでに精度が悪いんじゃ、パドルエミュレータで打鍵ミスが出るのも仕方ないわな。エレキーの速度よりもパドルエミュレータの設定速度を多少早めに設定すると打鍵ミスが減るように感じたのもこのせいだな(timeBeginPeriod()は使っていないので、遅めの傾向になりがち)。

コメント