我想对C/C++代码进行基准测试。我想测量cpu时间、墙时间和周期/字节。我写了一些度量函数,但循环/字节有问题。
为了获得cpu时间,我用RUSAGE_SELF
编写了一个函数getrusage()
,对于墙时间,我使用clock_gettime
和MONOTONIC
,为了获得周期/字节,我使用了rdtsc
。
我处理大小为1024:char buffer[1024]
的输入缓冲区。如何进行基准测试:
- 进行热身阶段,只需拨打
fun2measure(args)
1000次:
for(int i=0; i<1000; i++)
fun2measure(args);
-
然后,为墙时间做一个真正的计时基准:
`无符号长i;双倍计时;double timeTotal=3.0;//处理3秒
对于(timeTake=(双)0,i=0;时间占用<=timeTotal;timeTake=walltime(1),i++)fun2measure(args);`
-
对于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);
。这里CCD_ 11是1024,因为它是CCD_。但当我把totalTime
提高到10时,我会得到奇怪的结果:
10s:
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]
5秒:
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不再是问题了:)
您的cyclecount基准测试存在缺陷,因为它包含了walltime/cputime函数调用的成本。不过,总的来说,我强烈建议您使用适当的探查器,而不是试图重新发明轮子。特别是性能计数器会给你提供你可以依赖的数字。还要注意,周期非常不可靠,因为CPU通常没有以固定的频率运行,或者内核可能会切换任务并暂停你的应用程序一段时间。
我个人编写基准测试,这样它们就可以运行给定的函数N次,因为N足够大,这样你就可以获得足够的样本。在外部,我应用了一个探查器,比如linuxperf,来给我一些难以推理的数字。在给定的时间内重复基准测试,然后可以计算stddev/avg值,这可以在运行基准测试几次并评估探查器输出的脚本中完成。