我已经在gcc中成功编写了一些内联汇编程序来向右旋转一位 遵循一些不错的说明:http://www.cs.dartmouth.edu/~sergey/cs108/2009/gcc-inline-asm.pdf
以下是一个例子:
static inline int ror(int v) {
asm ("ror %0;" :"=r"(v) /* output */ :"0"(v) /* input */ );
return v;
}
但是,我希望代码计算时钟周期,并且看到一些错误的(可能是微软)格式。我不知道如何在gcc中做这些事情。有什么帮助吗?
unsigned __int64 inline GetRDTSC() {
__asm {
; Flush the pipeline
XOR eax, eax
CPUID
; Get RDTSC counter in edx:eax
RDTSC
}
}
我试过了:
static inline unsigned long long getClocks() {
asm("xor %%eax, %%eax" );
asm(CPUID);
asm(RDTSC : : %%edx %%eax); //Get RDTSC counter in edx:eax
但我不知道如何让edx:eax对以干净的方式返回64位,并且不知道如何真正刷新管道。
此外,我找到的最佳源代码位于:http://www.strchr.com/performance_measurements_with_rdtsc
那提到了奔腾,所以如果有不同的方式在不同的英特尔/ AMD变种上做,请告诉我。我更喜欢适用于所有x86平台的东西,即使它有点难看,也适用于各种变体的一系列解决方案,但我不介意了解它。
答案 0 :(得分:11)
以下是您想要的:
inline unsigned long long rdtsc() {
unsigned int lo, hi;
asm volatile (
"cpuid \n"
"rdtsc"
: "=a"(lo), "=d"(hi) /* outputs */
: "a"(0) /* inputs */
: "%ebx", "%ecx"); /* clobbers*/
return ((unsigned long long)lo) | (((unsigned long long)hi) << 32);
}
在代码中放置尽可能少的内联ASM非常重要,因为它会阻止编译器进行任何优化。这就是为什么我在C代码中完成了结果的转换和结果,而不是在ASM中进行编码。类似地,我使用0的“a”输入让编译器决定何时以及如何将eax归零。可能是程序中的其他一些代码已经将其清零,编译器可以在知道的情况下保存指令。
此外,上面的“clobbers”非常重要。 CPUID
会覆盖eax,ebx,ecx和edx中的所有内容。您需要告诉编译器您正在更改这些寄存器,以便它知道不要在那里保留任何重要内容。您不必列出eax和edx,因为您将它们用作输出。如果你没有列出clobbers,那么你的程序很可能会崩溃,你会发现追踪问题非常困难。
答案 1 :(得分:1)
这会将结果存储在值中。组合结果需要额外的周期,因此调用此代码之间的周期数将比结果的差异少一些。
unsigned int hi,lo;
unsigned long long value;
asm (
"cpuid\n\t"
"rdtsc"
: "d" (hi), "a" (lo)
);
value = (((unsigned long long)hi) << 32) | lo;