一貫した間隔でイベントを起動するためのビジー待機ループのパフォーマンスを評価しています。次のコードを使用すると、奇妙な動作に気付きました。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
int timespec_subtract(struct timespec *, struct timespec, struct timespec);
int main(int argc, char *argv[]) {
int iterations = atoi(argv[1])+1;
struct timespec t[2], diff;
for (int i = 0; i < iterations; i++) {
clock_gettime(CLOCK_MONOTONIC, &t[0]);
static volatile int i;
for (i = 0; i < 200000; i++)
;
clock_gettime(CLOCK_MONOTONIC, &t[1]);
timespec_subtract(&diff, t[1], t[0]);
printf("%ld\n", diff.tv_sec * 1000000000 + diff.tv_nsec);
}
}
テスト マシン (デュアル 14 コア E5-2683 v3 @ 2.00Ghz、256GB DDR4) では、for ループの 200k 反復は約 1ms です。またはそうでないかもしれません:
1030854
1060237
1012797
1011479
1025307
1017299
1011001
1038725
1017361
... (about 700 lines later)
638466
638546
638446
640422
638468
638457
638468
638398
638493
640242
... (about 200 lines later)
606460
607013
606449
608813
606542
606484
606990
606436
606491
606466
... (about 3000 lines later)
404367
404307
404309
404306
404270
404370
404280
404395
404342
406005
3 回目のシフトダウンでは、数百回の反復で約 450us に跳ね上がることがありますが、ほぼ一貫しています (約 2 または 3 マイクロ秒以内)。この動作は、同様のマシンで、多くの実行にわたって再現可能です。
ビジー ループがコンパイラによって最適化される可能性があることは理解していますが、ここでの問題ではないと思います。無効化は行われるべきではなく、突然の最適化を説明しないため、キャッシュが影響を与えるべきではないと思います。また、ループ カウンターにレジスタ int を使用してみましたが、顕著な効果はありませんでした。
何が起こっているのか、これを(より)一貫させる方法について何か考えはありますか?
編集: 詳細については、usleep、nanosleep、または示されているビジー待機を使用してこのプログラムを実行すると、10k の反復がすべて表示され、~20000 の非自発的なコンテキスト スイッチが表示されtime -v
ます。