【发布时间】:2010-11-25 16:38:21
【问题描述】:
我正在寻找一种快速的方法来获取 C 中函数的两次调用之间经过的时间。
我考虑过使用 jiffies,但它们在用户空间中不可用。那么,我应该使用 getimeofday() 还是有最快的方法来做到这一点。
我只对两次调用之间经过的时间感兴趣,以便在基准工具中使用。
【问题讨论】:
我正在寻找一种快速的方法来获取 C 中函数的两次调用之间经过的时间。
我考虑过使用 jiffies,但它们在用户空间中不可用。那么,我应该使用 getimeofday() 还是有最快的方法来做到这一点。
我只对两次调用之间经过的时间感兴趣,以便在基准工具中使用。
【问题讨论】:
如果您使用的是 x86/x64 架构,并且在单个 CPU 上运行,则可以考虑读取 CPU 上的时间戳计数器以获取循环计数。维基百科有more information。请注意,如果您的应用程序在多个 CPU 上运行,则此方法不太有用,因为每个 CPU 都有自己的 TSC。如果您决定要转换周期 -> 时间单位,请注意频率缩放。
【讨论】:
是的,如果您想找到实际经过的时间,gettimeofday() 就足够了。如果需要查找 CPU 时间,则可以使用 clock()。在许多情况下,这两种方法都会给出相似的结果(除非代码中有睡眠或某种等待)。可以在此处找到 clock() 的示例:
http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_19.html
【讨论】:
查看clock_gettime,它提供对高分辨率计时器的访问。
【讨论】:
我将通过clock() 从time.h 获取处理器时间。要获得有用的值,请通过CLOCKS_PER_SEC 转换为毫秒:
clock_t start = clock();
// [...]
clock_t end = clock();
unsigned long millis = (end - start) * 1000 / CLOCKS_PER_SEC;
【讨论】:
如果您的内核支持 gettimeofday() 作为 vsyscall(虚拟系统调用),那么使用它会比调用常规系统调用(例如 clock())更快。有关 vsyscall 工作原理的一些信息,请参阅 Andrea Arcangeli's presentation。
【讨论】:
添加的有点晚,但是任何 linux/unix 上可用的时间实用程序可能是实现您想要的更轻量级的方式。这里有两个例子
time ls -l stuff*
ls: stuff*: No such file or directory
0.01s real 0.00s user 0.00s system
time -c run_script.csh`
...
real 1m22.38s
user 0m14.67s
sys 0m1.06s
【讨论】:
以下在 CentOS 6 上适用于我:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if ! defined(_POSIX_C_SOURCE)
# error "_POSIX_C_SOURCE undefined"
#endif
#if _POSIX_C_SOURCE < 199309L
# error "_POSIX_C_SOURCE < 199309L"
#endif
int main(int, char**){
struct timespec start, stop;
struct timespec stop;
if(clock_gettime(CLOCK_MONOTONIC, &start )) goto err_out;
if(clock_gettime(CLOCK_MONOTONIC, &stop )) goto err_out;
printf("start == {tv_sec: %d, tv_nsec: %d}\n", start.tv_sec, start.tv_nsec);
printf("stop == {tv_sec: %d, tv_nsec: %d}\n", stop.tv_sec, stop.tv_nsec );
printf("stop.tv_nsec - start.tv_nsec == %d\n", stop.tv_nsec - start.tv_nsec);
return EXIT_SUCCESS;
err_out:
perror("clock_gettime");
return EXIT_FAILURE ;
}
...虽然它确实需要librt:
$ make dur
cc dur.c -o dur
/tmp/cc1yF58x.o: In function `main':
dur.c:(.text+0x1c): undefined reference to `clock_gettime'
dur.c:(.text+0x4e): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make: *** [dur] Error 1
$ LDFLAGS="-lrt" make dur
cc -lrt dur.c -o dur
$ ./dur
start == {tv_sec: 206247, tv_nsec: 411717209}
stop == {tv_sec: 206247, tv_nsec: 411759791}
stop.tv_nsec - start.tv_nsec == 42582
【讨论】: