【发布时间】:2011-12-17 15:25:50
【问题描述】:
我需要一个高分辨率计时器,用于我们应用程序的 Linux 构建中的嵌入式分析器。我们的分析器测量的范围小到单个函数,因此它需要优于 25 纳秒的计时器精度。
以前我们的实现使用内联汇编和rdtsc 操作直接从CPU 查询高频定时器,但是this is problematic 并且需要经常重新校准。
所以我尝试使用clock_gettime 函数来查询CLOCK_PROCESS_CPUTIME_ID。文档声称这给了我纳秒级的时间,但我发现单次调用 clock_gettime() 的开销超过 250ns。这使得对事件进行 100ns 长的计时是不可能的,并且在计时器功能上具有如此高的开销会严重拖累应用程序的性能,使配置文件失真超出价值。 (我们每秒有数十万个分析节点。)
有没有一种方法可以调用 clock_gettime() 的开销小于 ¼μs? 或者有没有其他方法可以可靠地获得具有 rdtsc?
下面是我用来计时clock_gettime()的代码。
// calls gettimeofday() to return wall-clock time in seconds:
extern double Get_FloatTime();
enum { TESTRUNS = 1024*1024*4 };
// time the high-frequency timer against the wall clock
{
double fa = Get_FloatTime();
timespec spec;
clock_getres( CLOCK_PROCESS_CPUTIME_ID, &spec );
printf("CLOCK_PROCESS_CPUTIME_ID resolution: %ld sec %ld nano\n",
spec.tv_sec, spec.tv_nsec );
for ( int i = 0 ; i < TESTRUNS ; ++ i )
{
clock_gettime( CLOCK_PROCESS_CPUTIME_ID, &spec );
}
double fb = Get_FloatTime();
printf( "clock_gettime %d iterations : %.6f msec %.3f microsec / call\n",
TESTRUNS, ( fb - fa ) * 1000.0, (( fb - fa ) * 1000000.0) / TESTRUNS );
}
// and so on for CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID.
结果:
CLOCK_PROCESS_CPUTIME_ID resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 3115.784947 msec 0.371 microsec / call
CLOCK_MONOTONIC resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2505.122119 msec 0.299 microsec / call
CLOCK_REALTIME resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2456.186031 msec 0.293 microsec / call
CLOCK_THREAD_CPUTIME_ID resolution: 0 sec 1 nano
clock_gettime 8388608 iterations : 2956.633930 msec 0.352 microsec / call
这是在标准的 Ubuntu 内核上。该应用程序是 Windows 应用程序的一个端口(我们的 rdtsc 内联汇编工作得很好)。
附录:
x86-64 GCC 是否有一些与__rdtsc() 等效的内在属性,所以我至少可以避免内联汇编?
【问题讨论】:
-
这个问题的答案可能对你有帮助:stackoverflow.com/questions/638269/…
-
@Crash: My sympathies :) 想吃点儿烤肉吗?谁最能加速一些代码?
-
@Mike 我希望!现在,我更像是“我们需要将这段代码加速 20%,否则我们就完蛋了”。查看采样分析器中的函数列表,主循环的比例不超过 2%。 (我尝试了你的秒表和调试器中断技巧,并从 20 个不同的暂停中获得了 20 个不同的调用堆栈。)
-
@Crash:我相信你做到了。我所做的是查看每个示例,然后向自己解释(在纸上或在我的脑海中进行描述)该程序当时在做什么以及为什么这样做。这意味着要注意堆栈每一层的源代码。 (这也可能意味着查看其他状态信息,例如相关变量。)如果有些事情不是严格必须完成的,并且如果您在 >1 个样本上看到类似的事情,请修复它并获得您的加速。您的代码可能非常紧凑,但如果有什么要挤出来的,应该可以找到它。
-
@Crash:例如,请耐心等待。我经常在数据结构代码中找到示例,例如索引、递增迭代器或测试结束条件。我可以在不同例程的不同代码行上看到这一点,因此没有任何代码行或例程上升到显着百分比。即使只是其中的一项,例如索引或递增,也可能不会上升到显着的百分比。但是综合起来,他们可以。通常普通的旧数组虽然可能不那么正统,但可以节省所有时间。
标签: linux performance ubuntu profiling