Warm tip: This article is reproduced from serverfault.com, please click

其他-如何从C ++获取x86_64中的CPU周期计数?

(其他 - How to get the CPU cycle count in x86_64 from C++?)

发布于 2012-12-07 23:18:41

我在SO上看到了这篇帖子,其中包含C代码以获取最新的CPU周期计数:

C / C ++ Linux x86_64中基于CPU周期计数的性能分析

有什么方法可以在C ++中使用此代码(欢迎使用Windows和Linux解决方案)?尽管是用C语言编写的(并且C是C ++的子集),但我不确定此代码是否可以在C ++项目中使用,如果不能,该如何翻译?

我正在使用x86-64

编辑2:

找到了此功能,但无法使VS2010识别汇编器。我需要包括什么吗?(我相信我有交换uint64_tlong long了窗户......?)

static inline uint64_t get_cycles()
{
  uint64_t t;
  __asm volatile ("rdtsc" : "=A"(t));
  return t;
}

编辑3:

从上面的代码中我得到错误:

“错误C2400:'opcode'中的内联汇编语法错误;找到了'data type'”

有人可以帮忙吗?

Questioner
user997112
Viewed
11
237k 2019-07-09 07:20:58

从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