Cra*_*rks 20 linux ubuntu performance profiling
在我们的应用程序的Linux版本中,我需要一个用于嵌入式探查器的高分辨率计时器.我们的分析器测量的范围与单个功能一样小,因此它需要一个优于25纳秒的定时器精度.
以前我们的实现使用内联汇编和rdtsc操作直接从CPU查询高频定时器,但这是有问题的,需要经常重新校准.
所以我尝试使用该clock_gettime
函数来查询CLOCK_PROCESS_CPUTIME_ID.文档声称这给了我纳秒时间,但我发现单次调用的开销clock_gettime()
超过250ns.这使得不可能将事件计时100ns,并且在计时器功能上具有如此高的开销会严重降低应用程序性能,从而扭曲配置文件超出值.(我们每秒有数十万个分析节点.)
有没有办法调用clock_gettime()
开销小于¼μs?或者是否有其他方法可以可靠地获得时间戳计数器,开销<25ns?还是我坚持使用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.
Run Code Online (Sandbox Code Playgroud)
结果:
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
Run Code Online (Sandbox Code Playgroud)
这是在标准的Ubuntu内核上.该应用程序是Windows应用程序的端口(我们的rdtsc内联汇编工作正常).
x86-64 GCC是否有一些与__rdtsc()的内在等价物,所以我至少可以避免内联汇编?
不可以.您必须使用特定于平台的代码才能执行此操作.在x86和x86-64上,您可以使用'rdtsc'来读取时间戳计数器.
只需移植您正在使用的rdtsc程序集.
__inline__ uint64_t rdtsc(void) {
uint32_t lo, hi;
__asm__ __volatile__ ( // serialize
"xorl %%eax,%%eax \n cpuid"
::: "%rax", "%rbx", "%rcx", "%rdx");
/* We cannot use "=A", since this would use %rax on x86_64 and return only the lower 32bits of the TSC */
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return (uint64_t)hi << 32 | lo;
}
Run Code Online (Sandbox Code Playgroud)
我在我的系统上运行了一些基准测试,这是一个四核E5645 Xeon支持一个运行内核3.2.54的恒定TSC,结果如下:
clock_gettime(CLOCK_MONOTONIC_RAW) 100ns/call
clock_gettime(CLOCK_MONOTONIC) 25ns/call
clock_gettime(CLOCK_REALTIME) 25ns/call
clock_gettime(CLOCK_PROCESS_CPUTIME_ID) 400ns/call
rdtsc (implementation @DavidSchwarz) 600ns/call
Run Code Online (Sandbox Code Playgroud)
所以看起来在一个相当现代的系统上(接受的答案)rdtsc是最糟糕的路线.
归档时间: |
|
查看次数: |
13259 次 |
最近记录: |