我正在评估以一致的时间间隔触发事件的繁忙等待循环的性能。我注意到使用以下代码的一些奇怪行为:
#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
当时间第三次向下移动时,它们基本上保持一致(大约 2 或 3 微秒内),除了偶尔会跳到大约 450us 进行几百次迭代。这种行为在类似的机器上和多次运行中是可重复的。
我知道编译器可以优化繁忙的循环,但我认为这不是问题所在。我不认为缓存应该影响它,因为不应该发生失效,也不会解释突然的优化。我还尝试使用寄存器 int 作为循环计数器,但没有明显效果。
关于正在发生的事情以及如何使这(更)一致的任何想法?
编辑:有关信息,使用 usleep、nanosleep 运行此程序或显示的忙等待 10k 次迭代都显示 ~20000 次非自愿上下文切换time -v
。