在最近的CPU上(至少在过去十年左右),除了各种可配置的性能计数器之外,英特尔还提供了三个固定功能硬件性能计数器.三个固定柜台是:
INST_RETIRED.ANY
CPU_CLK_UNHALTED.THREAD
CPU_CLK_UNHALTED.REF_TSC
Run Code Online (Sandbox Code Playgroud)
第一个计算退役指令,第二个计算实际周期,最后一个是我们感兴趣的."英特尔软件开发人员手册"第3卷的描述如下:
当核心未处于暂停状态而不处于TM停止时钟状态时,此事件计算TSC速率下的参考周期数.核心在运行HLT指令或MWAIT指令时进入暂停状态.此事件不受核心频率变化(例如,P状态)的影响,但计数与时间戳计数器的频率相同.当核心未处于暂停状态而不处于TM stopclock状态时,此事件可以估计经过的时间.
因此,对于CPU绑定循环,我希望该值与从中读取的自由运行TSC值相同rdstc,因为它们应该仅针对暂停的循环指令或"TM stopclock state"是什么发散.
我使用以下循环测试它(整个独立演示在github上可用):
for (int i = 0; i < 100; i++) {
PFC_CNT cnt[7] = {};
int64_t start = nanos();
PFCSTART(cnt);
int64_t tsc =__rdtsc();
busy_loop(CALIBRATION_LOOPS);
PFCEND(cnt);
int64_t tsc_delta = __rdtsc() - tsc;
int64_t nanos_delta = nanos() - start;
printf(CPU_W "d" REF_W ".2f" TSC_W ".2f" MHZ_W ".2f" RAT_W ".6f\n",
sched_getcpu(),
1000.0 * cnt[PFC_FIXEDCNT_CPU_CLK_REF_TSC] / nanos_delta,
1000.0 * tsc_delta / nanos_delta,
1000.0 * CALIBRATION_LOOPS / nanos_delta,
1.0 * cnt[PFC_FIXEDCNT_CPU_CLK_REF_TSC]/tsc_delta); …Run Code Online (Sandbox Code Playgroud) 我在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:'操作码'中的内联汇编语法错误;找到'数据类型'"
有人可以帮忙吗?
我想在特定点获得CPU周期.我在这一点上使用这个功能:
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
Run Code Online (Sandbox Code Playgroud)
问题是它总是返回一个增加的数字(在每次运行中).就好像它指的是绝对时间.
我错误地使用了这些功能吗?
对于我的项目,我必须使用内联汇编指令(如rdtsc)来计算某些C/C++指令的执行时间.
以下代码似乎适用于英特尔,但不适用于ARM处理器:
{unsigned a, d;asm volatile("rdtsc" : "=a" (a), "=d" (d)); t0 = ((unsigned long)a) | (((unsigned long)d) << 32);}
//The C++ statement to measure its execution time
{unsigned a, d;asm volatile("rdtsc" : "=a" (a), "=d" (d)); t1 = ((unsigned long)a) | (((unsigned long)d) << 32);}
time = t1-t0;
Run Code Online (Sandbox Code Playgroud)
我的问题是:
如何在ARM处理器上编写类似于上面的内联汇编代码(计算指令的执行经过时间)?
是否可以通过perf收集硬件计数器统计信息,仅用于程序执行的一部分?如果是这样,怎么样?
likwid提供了能够定义命名区域的功能,但如果只在安装了perf的系统上实现这一点,那将会很棒.
以前的一些问题已经返回相关答案,但仍有一些缺点:
我试图用来clflush手动驱逐缓存行,以确定缓存和行大小.我没有找到任何关于如何使用该指令的指南.我所看到的,是一些使用更高级别功能的代码.
有一个内核函数void clflush_cache_range(void *vaddr, unsigned int size),但我仍然不知道在我的代码中包含什么以及如何使用它.我不知道size该功能是什么.
更重要的是,我怎样才能确定该行被驱逐以验证我的代码的正确性?
更新:
这是我想要做的初始代码.
#include <immintrin.h>
#include <stdint.h>
#include <x86intrin.h>
#include <stdio.h>
int main()
{
int array[ 100 ];
/* will bring array in the cache */
for ( int i = 0; i < 100; i++ )
array[ i ] = i;
/* FLUSH A LINE */
/* each element is 4 bytes */
/* assuming that cache line size is 64 bytes */
/* array[0] till …Run Code Online (Sandbox Code Playgroud) std::chrono提供几个时钟来测量时间。同时,我猜 cpu 评估时间的唯一方法是计数周期。
问题 1: cpu 或 gpu 是否可以通过计数周期来评估时间?
如果是这样的话,因为计算机计数周期的方式永远不会像原子钟那样精确,这意味着period = std::ratio<1>计算机的“秒”()实际上可能比实际秒更短或更大,从而导致在长时间运行计算机时钟和 GPS 之间的时间测量。
问题2:正确吗?
某些硬件具有不同的频率(例如空闲模式和 Turbo 模式)。在这种情况下,这意味着循环数将在一秒钟内发生变化。
问题 3: cpu 和 gpus 测量的“周期数”是否因硬件频率而异?如果是,那么如何std::chrono处理?如果不是,一个周期对应什么(比如什么是“基本”时间)?有没有办法在编译时访问转换?有没有办法在运行时访问转换?
在最近的英特尔ISA文档中,该lfence指令被定义为序列化指令流(防止指令流无序执行).特别是,该指令的描述包括以下行:
具体来说,LFENCE不会执行,直到所有先前的指令在本地完成,并且在LFENCE完成之前没有后续指令开始执行.
请注意,这适用于所有的指令,不只是内存加载指令,使得lfence 更多的不仅仅是一个存储排序防护.
虽然这现在出现在ISA文档中,但不清楚它是否是"架构",即所有x86实现都遵守,或者它是否特定于Intel.特别是AMD处理器是否也将lfence序列化为指令流?
我是C ++和基准测试的新手
我不明白这段代码的作用是什么?因此,我找到了一些有关edx,eax寄存器的信息,但是我不完全了解它如何在代码中发挥作用。所以我理解这段代码本质上返回了cpu周期的当前滴答声。因此,它是否将当前的滴答存储在寄存器中,一部分存储在hi中,另一部分存储在lo中。并且,“ = a”和“ = d”是否指定将其存储在哪个寄存器中。
将其分为两个部分的意义何在?
"rdtsc" : "=a" (lo), "=d" (hi)
Run Code Online (Sandbox Code Playgroud)
上下文中的代码:
int64_t rdtsc(){
unsigned int lo,hi;
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
return ((uint64_t)hi << 32) | lo;
}
Run Code Online (Sandbox Code Playgroud)