在Unix / Linux上用C代码测量一段代码占用的CPU时间

时钟()可以用作一个可靠的API来测量CPU执行一段代码所花费的时间? 经过validation的时间()/时钟(),两者似乎都没有精确地测量CPU时间。

首先,可以使用API​​ clock()/ times()来测量函数/代码片段的执行时间,如下例所示: 有更好更可靠的select吗? 该机制将在Linux,HP-UX,IBM-AIX和Sun Solaris上工作,因为我们需要测量(&&比较)所有这些平台上的一段代码的性能

请build议。 另外,请让我知道如果我错过了任何琐事。

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数据库select并用来自数据库的数据填充这些结构)。 即使这显示0滴答,这是让我困惑。

谢谢!

在最近的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文件。 你将需要验证你的系统是否有。

我会尝试getrusage并检查系统和用户时间。

还请检查gettimeofday与挂钟时间进行比较。

我会尝试将时间与shell的time命令关联起来,作为一个完整的检查。

你也应该考虑到编译器可能正在优化循环。 由于memset不依赖于循环变量,所以编译器肯定会尝试应用称为循环不变代码运动的优化。

我还要警告说,10MB可能在高速缓存清除将确实是1.25或250万CPU操作,因为memset肯定以4字节或8字节数量写入。 虽然我相当怀疑这可以在不到一微秒的时间内完成,因为商店有点贵,而100K增加了一些L1高速缓存的压力,你所说的每纳秒只有一个操作,这不是很难维持一个多GHz的CPU。

我们可以想象,600 nS会变成1时钟刻度,但我也会担心这一点。

您可以使用clock_t来获取自程序启动以来CPU的滴答数量。

或者你可以使用linux time命令。 例如:time [program] [arguments]

有关HP高分辨率计时器页面的一些信息。 另外,同样的技巧_Asm_mov_from_ar (_AREG_ITC); 也在http://www.fftw.org/cycle.h中使用&#x3002;

必须确认这是否可以真正解决问题。

示例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 > 

进程/线程的资源使用情况仅由操作系统定期更新。 在下一次更新之前完全可以完成代码片段,从而产生零资源使用差异。 不能说惠普或AIX的任何事情,会引用你的Solaris性能和工具书的Sun。 对于Linux,您需要查看oprofile和更新的perf工具 。 在配置文件方面valgrind会有很大的帮助。