我在SO上看到了这篇帖子,其中包含C代码以获取最新的CPU周期计数:
C / C ++ Linux x86_64中基于CPU周期计数的性能分析
有什么方法可以在C ++中使用此代码(欢迎使用Windows和Linux解决方案)?尽管是用C语言编写的(并且C是C ++的子集),但我不确定此代码是否可以在C ++项目中使用,如果不能,该如何翻译?
我正在使用x86-64
编辑2:
找到了此功能,但无法使VS2010识别汇编器。我需要包括什么吗?(我相信我有交换uint64_t
到long long
了窗户......?)
static inline uint64_t get_cycles()
{
uint64_t t;
__asm volatile ("rdtsc" : "=A"(t));
return t;
}
编辑3:
从上面的代码中我得到错误:
“错误C2400:'opcode'中的内联汇编语法错误;找到了'data type'”
有人可以帮忙吗?
从GCC 4.5开始,后来,在__rdtsc()
固有现在由两个MSVC和海湾合作委员会的支持。
但是所需的包含内容有所不同:
#ifdef _WIN32
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
这是GCC 4.5之前的原始答案。
直接退出我的项目之一:
#include <stdint.h>
// Windows
#ifdef _WIN32
#include <intrin.h>
uint64_t rdtsc(){
return __rdtsc();
}
// Linux/GCC
#else
uint64_t rdtsc(){
unsigned int lo,hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32) | lo;
}
#endif
这个GNU C Extended asm告诉编译器:
volatile
:输出不是输入的纯粹功能(因此必须每次都重新运行,而不是重用旧的结果)。"=a"(lo)
和"=d"(hi)
:输出操作数是固定寄存器:EAX和EDX。(x86机器约束)。x86rdtsc
指令将其64位结果放入EDX:EAX中,因此让编译器选择输出结果"=r"
是行不通的:没有办法要求CPU将结果传送到其他地方。((uint64_t)hi << 32) | lo
-将两个32位半部分零扩展到64位(因为lo和hi是unsigned
),然后将它们逻辑或+或移位到一个64位C变量中。在32位代码中,这只是重新解释。这些值仍只保留在一对32位寄存器中。在64位代码中,你通常会获得实际的shift + OR asm指令,除非上半部分已优化掉。(编辑者的注:如果使用unsigned long
代替,可能会更有效unsigned int
。然后,编译器将知道lo
已经对RAX进行了零扩展。它不知道上半部分为零,因此|
,+
如果要对等价,则等效。合并的方式也不同。从理论上讲,内在函数应该让你两全其美,只要让优化器做好就行。)
https://gcc.gnu.org/wiki/DontUseInlineAsm(如果可以避免的话)。但是希望本节对你需要了解使用内联汇编的旧代码,以便可以使用内部函数重写它很有用。另请参阅https://stackoverflow.com/tags/inline-assembly/info
这是打包的好方法。
FWIW,gcc 4.5及更高版本包括__rdtsc()-#include <x86intrin.h>进行获取。标头还包含在Microsoft的<intrin.h>中发现的许多其他intel内在函数,这些天默认包含大多数SIMD标头(emmintrin.h,xmmintrin.h等),这些默认情况下已包含在内。
std::uint64_t x; asm volatile ("rdtsc" : "=A"(x));
是另一种阅读EAX
和EDX
在一起的方式。@Orient:仅在32位模式下。在64位模式下,
"=A"
将选择任一RAX或RDX。您对GNU编译器偏爱内联asm的任何理由是什么? 为MSVC以外的编译器
<x86intrin.h>
定义__rdtsc()
,因此您只需即可#ifdef _MSC_VER
。我为这个问题添加了一个答案,因为它看起来像是有关rdtsc
内在函数规范的好地方,并且是如何使用的陷阱rdtsc
。