可以将clock()用作可靠的API来测量CPU执行代码片段所花费的时间吗?当使用times()/ clock()验证时,两者似乎都不能精确测量所花费的CPU时间。
首先,可以使用API clock()/ times()来测量函数/代码片段的执行时间,如下例所示?有没有更好更可靠的选择?该机制适用于Linux,HP-UX,IBM-AIX和Sun Solaris,因为我们需要测量(和比较)所有这些平台上的一段代码的性能。
请建议。另外,如果我遗漏了任何小事,请告诉我。
bbb@m_001:/tmp/kk1$ ./perf_clock 102400
{clock(): S 0 E 0 D 0.0000000000}
bbb@m_001:/tmp/kk1$ ./perf_clock 204800
{clock(): S 0 E 10000 D 0.0100000000}
bbb@m_001:/tmp/kk1$ cat perf_clock.c
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
void test_clock(char* sbuf, int* len){
clock_t start, end; int i=0;
start = clock();
while(i++ < 500) memset((char*)sbuf,0,*len);
end = clock();
printf("{clock(): S %10lu E %10lu D %15.10f}\n",
start,end,(end-start)/(double) CLOCKS_PER_SEC);
}
int main(int argc,char* argv[])
{
int len=atoi(argv[1]);
char *sbuf=(char*)malloc(len);
test_clock(sbuf,&len);
free(sbuf); return 0;
}
结果似乎说到memset()一个100 KB的块,500次,没有花时间。或者是否说它在微秒内无法测量?
实际上,它不是memset()而是另一个函数[准备一个大小约1MB的巨大结构,mallocs这个结构的副本,Oracle DB选择并用DB中的数据填充这些结构]我试图测量。即使这显示0滴答,这也让我感到困惑。
谢谢!
答案 0 :(得分:7)
在最近的Linux上(*)。您可以从/ proc文件系统获取此信息。在文件/proc/PID/stat
中,第14个条目具有用户区代码中使用的jiffies数,第15个条目具有系统代码中使用的jiffies数。
如果要基于每个线程查看数据,则应该引用文件/proc/PID/task/TID/stat
。
要将jiffies转换为微秒,您可以使用以下命令:
define USEC_PER_SEC 1000000UL
long long jiffies_to_microsecond(long long jiffies)
{
long hz = sysconf(_SC_CLK_TCK);
if (hz <= USEC_PER_SEC && !(USEC_PER_SEC % hz))
{
return (USEC_PER_SEC / hz) * jiffies;
}
else if (hz > USEC_PER_SEC && !(hz % USEC_PER_SEC))
{
return (jiffies + (hz / USEC_PER_SEC) - 1) / (hz / USEC_PER_SEC);
}
else
{
return (jiffies * USEC_PER_SEC) / hz;
}
}
如果您关心的是每个进程的统计信息,getrusage
会更容易。但是如果你想准备在每个线程的基础上做这个,这个技术比文件名更好,代码对于获取每个进程或每个线程的数据是相同的。
* - 我不确定引入stat文件的确切时间。您需要验证您的系统是否已使用它。
答案 1 :(得分:5)
我会尝试使用getrusage
并检查系统和用户时间。
同时查看gettimeofday
以与挂钟时间进行比较。
答案 2 :(得分:4)
我会尝试将时间与shell的time
命令相关联,作为完整性检查。
您还应该考虑编译器可能正在优化循环。由于memset不依赖于循环变量,因此编译器肯定会尝试应用称为loop invariant code motion的优化。
我还要提醒一下,10MB可能的高速缓存清除将真正是1.25或250万CPU操作,因为memset肯定以4字节或8字节的数量写入。虽然我怀疑这可以在不到一微秒的时间内完成,因为存储有点贵,而且100K增加了一些L1缓存压力,你所说的每纳秒不超过一次操作,这并不难以维持一个多GHz CPU。
有人想象600 nS可以完成1个时钟滴答,但我也会担心这个问题。
答案 3 :(得分:1)
您可以使用clock_t
来获取自程序启动以来的CPU滴答数。
或者您可以使用linux time
命令。例如:time [program] [arguments]
答案 4 :(得分:0)
有关高分辨率计时器的一些信息here on HP's page。此外,http://www.fftw.org/cycle.h中也使用了相同的技巧_Asm_mov_from_ar (_AREG_ITC);
。
必须确认这是否真的能成为解决方案。
示例prog,在HP-UX 11.31上测试:
bbb@m_001/tmp/prof > ./perf_ticks 1024
ticks-memset {func [1401.000000] inline [30.000000]} noop [9.000000]
bbb@m_001/tmp/prof > cat perf_ticks.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "cycle.h" /* one from http://www.fftw.org/cycle.h */
void test_ticks(char* sbuf, int* len){
memset((char*)sbuf,0,*len);
}
int main(int argc,char* argv[]){
int len=atoi(argv[1]);
char *sbuf=(char*)malloc(len);
ticks t1,t2,t3,t4,t5,t6;
t1 =getticks(); test_ticks(sbuf,&len); t2 =getticks();
t3 =getticks(); memset((char*)sbuf,0,len); t4 =getticks();
t5=getticks();;t6=getticks();
printf("ticks-memset {func [%llf] inline [%llf]} noop [%llf]\n",
elapsed(t2,t1),elapsed(t4,t3),elapsed(t6,t5));
free(sbuf); return 0;
}
bbb@m_001/tmp/prof >
答案 5 :(得分:0)
进程/线程的资源使用仅由OS定期更新。完全有可能在下一次更新之前完成代码片段,从而产生零资源使用差异。无法说出有关HP或AIX的任何信息,请您参考Solaris Performance and Tools预订Sun.对于Linux,您需要查看oprofile和更新perf tool。在剖析方valgrind会有很大帮助。