【发布时间】:2013-07-25 14:13:12
【问题描述】:
我想对 C/C++ 代码进行基准测试。我想测量 CPU 时间、挂墙时间和周期/字节。我写了一些测量函数,但是周期/字节有问题。
为了获得 CPU 时间,我编写了一个函数 getrusage() 和 RUSAGE_SELF,对于墙上时间我使用 clock_gettime 和 MONOTONIC,以获得周期/字节我使用 rdtsc。
我处理一个大小为 1024 的输入缓冲区:char buffer[1024]。我如何进行基准测试:
- 做一个热身阶段,只需拨打
fun2measure(args)1000 次:
for(int i=0; i<1000; i++)
fun2measure(args);
-
然后,针对挂钟时间做一个实时基准测试:
`unsigned long i; 双倍时间; 双倍时间总计 = 3.0; // 处理 3 秒
for (timeTaken=(double)0, i=0; timeTaken
-
而对于cpu时间(几乎相同):
for (timeTaken=(double)0, i=0; timeTaken <= timeTotal; timeTaken = walltime(1), i++) fun2measure(args);
但是当我想获得函数的 cpu 循环计数时,我使用了这段代码:
`unsigned long s = cyclecount();
for (timeTaken=(double)0, i=0; timeTaken <= timeTotal; timeTaken = walltime(1), i++)
{
fun2measure(args);
}
unsigned long e = cyclecount();
unsigned long s = cyclecount();
for (timeTaken=(double)0, i=0; timeTaken <= timeTotal; timeTaken = cputime(1), i++)
{
fun2measure(args);
}
unsigned long e = cyclecount();`
然后,计算周期/字节:((e - s) / (i * inputsSize);。这里inputsSize 是1024,因为它是buffer 的长度。但是当我将totalTime 提高到 10 秒时,我得到了奇怪的结果:
10 秒:
Did fun2measure 1148531 times in 10.00 seconds for 1024 bytes, 0 cycles/byte [CPU]
Did fun2measure 1000221 times in 10.00 seconds for 1024 bytes, 3.000000 cycles/byte [WALL]
5s:
Did fun2measure 578476 times in 5.00 seconds for 1024 bytes, 0 cycles/byte [CPU]
Did fun2measure 499542 times in 5.00 seconds for 1024 bytes, 7.000000 cycles/byte [WALL]
4s:
Did fun2measure 456828 times in 4.00 seconds for 1024 bytes, 4 cycles/byte [CPU]
Did fun2measure 396612 times in 4.00 seconds for 1024 bytes, 3.000000 cycles/byte [WALL]
我的问题:
- 这些结果正常吗?
- 为什么当我增加时间时,我的 cpu 总是 0 个周期/字节?
- 如何测量此类基准测试的平均时间、平均值、标准差等统计数据?
- 我的基准测试方法是否 100% 正常?
干杯!
第一次编辑:
将i更改为double后:
Did fun2measure 1138164.00 times in 10.00 seconds for 1024 bytes, 0.410739 cycles/byte [CPU]
Did fun2measure 999849.00 times in 10.00 seconds for 1024 bytes, 3.382036 cycles/byte [WALL]
我的结果似乎还可以。所以问题 #2 不再是问题了:)
【问题讨论】:
-
在计算周期/字节时要小心使用浮点除法
-
@VaughnCato:为什么?我应该改用
i=1吗?你的意思是我可能在这里处理zero division error? -
如果不使用浮点除法,那么小于一的值将被四舍五入为零。
-
另外,请注意
rdtsc。我遇到了两个主要问题(也许更多):1)在许多多 CPU 系统上,TSC 计数器不保持同步,因此在起点和终点之间迁移到不同的 CPU 将给出虚假的结果,并且 2) TSC 可以可靠地(或多或少地)计算周期,但是中断、重新调度等意味着这些周期可能还没有全部用在你的代码中......不过,它可以作为一个有用的球场只要您意识到可能存在的问题,就可以估计... -
@nullpointer 我并不是建议您不要使用它,只是要确保您了解它的局限性。它最适合用于迁移到另一个 CPU 或被其他东西中断的机会很小的短期内,或者如果您有一个大部分空闲的系统,则作为较长时间间隔的粗略估计,并且可以保证同步 TSC 或固定您的进程持续时间到特定的 CPU。
标签: c++ c performance benchmarking microbenchmark