【发布时间】:2013-11-25 08:01:47
【问题描述】:
我正在编写一个 C 代码来测量获取信号量所需的时钟周期数。我正在使用 rdtsc,在对信号量进行测量之前,我连续两次调用 rdtsc 来测量开销。我在一个 for 循环中重复了很多次,然后我使用平均值作为 rdtsc 开销。
首先使用平均值是否正确?
不过,这里最大的问题是,有时我会得到开销的负值(不一定是平均的,但至少是 for 循环中的部分)。
这也会影响sem_wait() 操作所需的 cpu 周期数的连续计算,有时结果也是负数。如果我写的不清楚,这里有一部分我正在处理的代码。
为什么我会得到这样的负值?
(编者注:有关获取完整 64 位时间戳的正确且可移植的方法,请参阅 Get CPU cycle count?。"=A" asm 约束在为 x86-64 编译时只会获得低 32 位或高 32 位,具体取决于寄存器分配是否恰好为uint64_t 输出选择RAX 或RDX。它不会选择edx:eax。)
(编辑的第二条注释:哎呀,这就是为什么我们得到负面结果的答案。仍然值得在这里留下一个注释作为警告不要复制这个rdtsc 实现。)
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
static inline uint64_t get_cycles()
{
uint64_t t;
// editor's note: "=A" is unsafe for this in x86-64
__asm volatile ("rdtsc" : "=A"(t));
return t;
}
int num_measures = 10;
int main ()
{
int i, value, res1, res2;
uint64_t c1, c2;
int tsccost, tot, a;
tot=0;
for(i=0; i<num_measures; i++)
{
c1 = get_cycles();
c2 = get_cycles();
tsccost=(int)(c2-c1);
if(tsccost<0)
{
printf("#### ERROR!!! ");
printf("rdtsc took %d clock cycles\n", tsccost);
return 1;
}
tot = tot+tsccost;
}
tsccost=tot/num_measures;
printf("rdtsc takes on average: %d clock cycles\n", tsccost);
return EXIT_SUCCESS;
}
【问题讨论】:
-
__asm volatile ("rdtsc" : "=A"(t));在 GCC (gcc.gnu.org/bugzilla/show_bug.cgi?id=21249) 中存在问题(或令人惊讶?)。=A约束表示 x86_64 中的rax,而不是edx:eax。 SHLrdx乘以 32 并 OR 到rax,或 SHLDrdx向左移动,同时从右侧移入rax的位。
标签: c x86-64 inline-assembly overhead rdtsc