我在SO上看到这篇文章,其中包含C代码以获取最新的CPU周期数:
基于CPU周期计算的C/C++ Linux x86_64中的分析
有没有办法在C++中使用这个代码(欢迎使用windows和linux解决方案)?虽然用C语言编写(而C是C++的一个子集)但我不太确定这段代码是否适用于C++项目,如果没有,如何翻译呢?
我使用的是x86-64
EDIT2:
找到此功能但无法让VS2010识别汇编程序.我需要包含任何内容吗?(我相信我必须换uint64_t
到long long
窗户......?)
static inline uint64_t get_cycles()
{
uint64_t t;
__asm volatile ("rdtsc" : "=A"(t));
return t;
}
Run Code Online (Sandbox Code Playgroud)
EDIT3:
从上面的代码我得到错误:
"错误C2400:'操作码'中的内联汇编语法错误;找到'数据类型'"
有人可以帮忙吗?
使用Visual Studio,我可以从处理器读取时钟周期计数,如下所示.我如何与GCC做同样的事情?
#ifdef _MSC_VER // Compiler: Microsoft Visual Studio
#ifdef _M_IX86 // Processor: x86
inline uint64_t clockCycleCount()
{
uint64_t c;
__asm {
cpuid // serialize processor
rdtsc // read time stamp counter
mov dword ptr [c + 0], eax
mov dword ptr [c + 4], edx
}
return c;
}
#elif defined(_M_X64) // Processor: x64
extern "C" unsigned __int64 __rdtsc();
#pragma intrinsic(__rdtsc)
inline uint64_t clockCycleCount()
{
return __rdtsc();
}
#endif
#endif
Run Code Online (Sandbox Code Playgroud) 在i386 linux上.如果可能的话,最好在c /(c/posix std libs)/ proc中.如果没有,是否有任何组装或第三方库可以做到这一点?
编辑:我正在尝试开发测试内核模块是否清除缓存行或整个proccesor(使用wbinvd()).程序以root身份运行,但如果可能的话,我宁愿留在用户空间.
我正在研究使用x86 CPU中的时间戳寄存器(TSR)来测量基准性能.它是一个有用的寄存器,因为它以单调时间单位测量,不受时钟速度变化的影响.很酷.
这是一份英特尔文档,显示了使用TSR进行可靠基准测试的asm片段,包括使用cpuid进行管道同步.见第16页:
要读取开始时间,它说(我注释了一下):
__asm volatile (
"cpuid\n\t" // writes e[abcd]x
"rdtsc\n\t" // writes edx, eax
"mov %%edx, %0\n\t"
"mov %%eax, %1\n\t"
//
:"=r" (cycles_high), "=r" (cycles_low) // outputs
: // inputs
:"%rax", "%rbx", "%rcx", "%rdx"); // clobber
Run Code Online (Sandbox Code Playgroud)
我不知道为什么暂存寄存器用来取的价值观edx
和eax
.为什么不删除MOVS和读取TSR值右出的edx
和eax
?像这样:
__asm volatile(
"cpuid\n\t"
"rdtsc\n\t"
//
: "=d" (cycles_high), "=a" (cycles_low) // outputs
: // inputs
: "%rbx", "%rcx"); // clobber
Run Code Online (Sandbox Code Playgroud)
通过这样做,您可以保存两个寄存器,从而降低C编译器需要溢出的可能性.
我对吗?或者那些MOV在某种程度上是战略性的?
(我同意你确实需要临时寄存器来读取停止时间,因为在那种情况下指令的顺序是相反的:你有rdtscp,...,cpuid.cpuid指令破坏了rdtscp的结果).
谢谢
在最近的英特尔ISA文档中,该lfence
指令被定义为序列化指令流(防止指令流无序执行).特别是,该指令的描述包括以下行:
具体来说,LFENCE不会执行,直到所有先前的指令在本地完成,并且在LFENCE完成之前没有后续指令开始执行.
请注意,这适用于所有的指令,不只是内存加载指令,使得lfence
更多的不仅仅是一个存储排序防护.
虽然这现在出现在ISA文档中,但不清楚它是否是"架构",即所有x86实现都遵守,或者它是否特定于Intel.特别是AMD处理器是否也将lfence
序列化为指令流?
我试图通过编写和运行测试程序来了解硬件缓存的工作原理:
#include <stdio.h>
#include <stdint.h>
#include <x86intrin.h>
#define LINE_SIZE 64
#define L1_WAYS 8
#define L1_SETS 64
#define L1_LINES 512
// 32K memory for filling in L1 cache
uint8_t data[L1_LINES*LINE_SIZE];
int main()
{
volatile uint8_t *addr;
register uint64_t i;
int junk = 0;
register uint64_t t1, t2;
printf("data: %p\n", data);
//_mm_clflush(data);
printf("accessing 16 bytes in a cache line:\n");
for (i = 0; i < 16; i++) {
t1 = __rdtscp(&junk);
addr = &data[i];
junk = *addr;
t2 = __rdtscp(&junk) - t1; …
Run Code Online (Sandbox Code Playgroud) 在x86-64
平台上,CLFLUSH
汇编指令允许刷新对应于给定地址的缓存行.相反,冲洗与特定地址的缓存,会有一种通过使其充满了虚拟的内容,以刷新整个高速缓存(或者相关程序的缓存中执行,或整个高速缓存),例如(或任何我不会意识到的其他方法):
以下函数的内容是什么:(无论编译器优化如何,该函数都应该工作)?
void flush_cache()
{
// Contents
}
Run Code Online (Sandbox Code Playgroud) 我正在NASM中使用RDTSC和RDTSCP测量各种汇编语言指令的机器周期,以帮助优化。
我读了Intel的Gabriele Paoloni撰写的“如何在Intel IA-32和IA-64指令集体系结构上对代码执行时间进行基准测试”(2010年9月)和其他Web资源(其中大多数是C语言中的示例)。
使用下面的代码(从C转换),我测试了各种指令,但RDTSCP在RDX中始终返回零,在RAX中始终返回7。我首先认为7是周期数,但显然并非所有指令都需要7个周期。
rdtsc
cpuid
addsd xmm14,xmm1 ; Instruction to time
rdtscp
cpuid
Run Code Online (Sandbox Code Playgroud)
返回7,这并不奇怪,因为在某些体系结构上,添加了7个周期(包括延迟)。前两个指令(根据某些情况)可以颠倒,先是cpuid,然后是rdtsc,但这在这里没有什么区别。
当我将指令更改为2周期指令时:
rdtsc
cpuid
add rcx,rdx ; Instruction to time
rdtscp
cpuid
Run Code Online (Sandbox Code Playgroud)
这还会在rax中返回7,在rdx中返回零。
所以我的问题是:
如何访问和解释RDX:RAX中返回的值?
为什么RDX总是返回零,应该返回什么?
更新:
如果我将代码更改为此:
cpuid
rdtsc
mov [start_time],rax
addsd xmm14,xmm1 ; INSTRUCTION
rdtscp
mov [end_time],rax
cpuid
mov rax,[end_time]
mov rdx,[start_time]
sub rax,rdx
Run Code Online (Sandbox Code Playgroud)
我的rax达到了64,但这听起来像是周期太多。
As far as I know, the main difference in runtime ordering in a processor with respect to rdtsc and rdtscp instruction is that whether the execution waits until all previous instructions are executed locally.
In other words, it means lfence + rdtsc = rdtscp because lfence preceding the rdtsc instruction makes the following rdtsc to be executed after all previous instruction finish locally.
However, I've seen some example code that uses rdtsc at the start of measurement and rdtscp at …
unsigned int lo = 0;
unsigned int hi = 0;
__asm__ __volatile__ (
"mfence;rdtsc" : "=a"(lo), "=d"(hi) : : "memory"
);
Run Code Online (Sandbox Code Playgroud)
mfence
在上面的代码中,是否有必要?
根据我的测试,找不到cpu重新排序.
测试代码片段包含在下面.
inline uint64_t clock_cycles() {
unsigned int lo = 0;
unsigned int hi = 0;
__asm__ __volatile__ (
"rdtsc" : "=a"(lo), "=d"(hi)
);
return ((uint64_t)hi << 32) | lo;
}
unsigned t1 = clock_cycles();
unsigned t2 = clock_cycles();
assert(t2 > t1);
Run Code Online (Sandbox Code Playgroud) 我正在尝试将clock_gettime(CLOCK_REALTIME, &ts) 替换为rdtsc,以CPU 周期而不是服务器时间来衡量代码执行时间。基准测试代码的执行时间对于软件至关重要。我尝试在独立核心上的 x86_64 3.20GHz ubuntu 机器上运行代码并得到以下数字:
情况 1:时钟获取时间: 24 纳秒
void gettime(Timespec &ts) {
clock_gettime(CLOCK_REALTIME, &ts);
}
Run Code Online (Sandbox Code Playgroud)
情况 2:rdtsc(没有 mfence 和编译器屏障): 10 ns
void rdtsc(uint64_t& tsc) {
unsigned int lo,hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
tsc = ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)
情况 3:rdtsc(带有 mfence 和编译器屏障): 30 ns
void rdtsc(uint64_t& tsc) {
unsigned int lo,hi;
__asm__ __volatile__ ("mfence;rdtsc" : "=a" (lo), "=d" (hi) :: "memory");
tsc = ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是我知道 …
前一段时间,我问了一个关于堆栈溢出的问题,并展示了如何在C++中执行rdtsc操作码.我最近使用rdtsc创建了一个基准函数,如下所示:
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);
}
typedef uint64_t (*FuncOneInt)(uint32_t n);
/**
time a function that takes an integer parameter and returns a 64 bit number
Since this is capable of timing in clock cycles, we won't have to do it a
huge …
Run Code Online (Sandbox Code Playgroud)