英特尔失去了周期? rdtsc和CPU_CLK_UNHALTED.REF_TSC

时间:2017-08-02 22:41:52

标签: performance x86 x86-64 cpu-architecture rdtsc

在最近的CPU上(至少在过去十年左右),除了各种可配置的性能计数器之外,英特尔还提供了三个固定功能硬件性能计数器。三个固定计数器是:

INST_RETIRED.ANY
CPU_CLK_UNHALTED.THREAD
CPU_CLK_UNHALTED.REF_TSC

第一个计算退役指令,第二个计算实际周期,最后一个是我们感兴趣的。英特尔软件开发人员手册第3卷的描述是:

  

此事件计算TSC速率时的参考周期数   核心不处于暂停状态而不处于TM停止时钟状态。该   当核心运行HLT指令时,核心进入暂停状态   MWAIT指令。此事件不受核心频率的影响   改变(例如,P状态)但是以与时间相同的频率计数   邮票柜台。此事件可以近似核心的经过时间   没有处于暂停状态而且没有处于TM stopclock状态。

因此,对于CPU绑定循环,我希望此值与从rdstc读取的自由运行TSC值相同,因为它们应该仅针对暂停的循环指令或“TM stopclock states”进行分歧“是。

我使用以下循环(整个standalone demo is available on 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);
}

定时区域唯一重要的是busy_loop(CALIBRATION_LOOPS);,它只是一个紧密的易失性商店循环,gccclangvoid busy_loop(uint64_t iters) { volatile int sink; do { sink = 0; } while (--iters > 0); (void)sink; } 按一个周期执行迭代最近的硬件:

PFCSTART

PFCENDCPU_CLK_UNHALTED.REF_TSC命令使用as compiled读取__rdtsc()计数器。 rdtsc是通过nanos()指令读取TSC的内在函数。最后,我们使用int64_t nanos() { auto t = std::chrono::high_resolution_clock::now(); return std::chrono::time_point_cast<std::chrono::nanoseconds>(t).time_since_epoch().count(); } 来衡量实时,这只是:

cpuid

是的,我没有发出CPU# REF_TSC rdtsc Eff Mhz Ratio 0 2392.05 2591.76 2981.30 0.922946 0 2381.74 2591.79 3032.86 0.918955 0 2399.12 2591.79 3032.50 0.925660 0 2385.04 2591.79 3010.58 0.920230 0 2378.39 2591.79 3010.21 0.917663 0 2355.84 2591.77 2928.96 0.908970 0 2364.99 2591.79 2942.32 0.912492 0 2339.64 2591.77 2935.36 0.902720 0 2366.43 2591.79 3022.08 0.913049 0 2401.93 2591.79 3023.52 0.926747 0 2452.87 2591.78 3070.91 0.946400 0 2350.06 2591.79 2961.93 0.906733 0 2340.44 2591.79 2897.58 0.903020 0 2403.22 2591.79 2944.77 0.927246 0 2394.10 2591.79 3059.58 0.923723 0 2359.69 2591.78 2957.79 0.910449 0 2353.33 2591.79 2916.39 0.907992 0 2339.58 2591.79 2951.62 0.902690 0 2395.82 2591.79 3017.59 0.924389 0 2353.47 2591.79 2937.82 0.908047 ,并且事情没有以精确的方式交错,但校准循环是一整秒,所以这样的纳秒级问题只是被稀释到或多或少什么都没有。

启用TurboBoost后,这是我的i7-6700HQ Skylake CPU上典型运行的前几个结果:

REF_TSC

此处,rdtsc是如上所述的固定TSC性能计数器,rdtscEff Mhz指令的结果。 Ratio是在该时间间隔内有效计算的真实CPU频率,主要是为了好奇而显示,以及快速确认涡轮增压的数量。REF_TSCrdtscrdstc的比率CPU# REF_TSC rdtsc Eff Mhz Ratio 0 2592.26 2592.25 2588.30 1.000000 0 2592.26 2592.26 2591.11 1.000000 0 2592.26 2592.26 2590.40 1.000000 0 2592.25 2592.25 2590.43 1.000000 0 2592.26 2592.26 2590.75 1.000000 0 2592.26 2592.26 2590.05 1.000000 0 2592.25 2592.25 2590.04 1.000000 0 2592.24 2592.24 2590.86 1.000000 0 2592.25 2592.25 2590.35 1.000000 0 2592.25 2592.25 2591.32 1.000000 0 2592.25 2592.25 2590.63 1.000000 0 2592.25 2592.25 2590.87 1.000000 0 2592.25 2592.25 2590.77 1.000000 0 2592.25 2592.25 2590.64 1.000000 0 2592.24 2592.24 2590.30 1.000000 0 2592.23 2592.23 2589.64 1.000000 0 2592.23 2592.23 2590.83 1.000000 0 2592.23 2592.23 2590.49 1.000000 0 2592.23 2592.23 2590.78 1.000000 0 2592.23 2592.23 2590.84 1.000000 0 2592.22 2592.22 2588.80 1.000000 列。我预计这将非常接近1,但在实践中我们看到它在0.90到0.92之间徘徊并伴随着很多变化(我在其他运行中看到它低至0.8)。

图形上看起来像 2

libpfc

hlt调用几乎返回精确结果 1 ,而PMU TSC计数器遍布整个地方,有时几乎低至2300 MHz。

如果我关闭turbo ,结果会更加一致:

mwait

基本上,该比率为1.000000至 6位小数

以图形方式(Y轴刻度强制与上一图相同):

PMU tsc vs rdstc

现在代码只是运行一个热循环,并且应该没有2591.97 MHzrdstc指令,当然没有任何暗示变化超过10%的指令。我不能说肯定什么是“TM停止时钟周期”,但我敢打赌它们是“热管理停止时钟周期”,这是一种用来临时限制CPU的技巧它的最高温度。然而,我查看了集成的热敏电阻读数,我从未看到CPU突破60C,远远低于90C-100C,正常管理开始(我认为)。

知道这可能是什么?在不同的turbo频率之间是否存在隐含的“停止周期”?这肯定发生,因为盒子不安静,因此涡轮增压频率随着其他核心开始和停止工作在背景材料上跳跃(最大涡轮机频率直接取决于活动核心数量:在我的盒子上它是3.5, 3.3,3.2,3.1 GHz分别用于1,2,3或4个核心活动。

1 事实上,有一段时间我真的得到精确结果到两位小数:ntpd - 迭代后的迭代。然后一些事情发生了变化,我不确定是什么,rdtsc结果中的变化很小,约为0.1%。一种可能性是逐步调整时钟,由Linux时序子系统进行调整,以使本地晶体导出的时间与{{1}}确定的时间内联。也许,它只是一个晶体漂移 - 上面的最后一个图表显示每秒{{1}}的测量周期稳定增加。

2 图表与文本中显示的值的运行不对应,因为每次更改文本输出格式时我都不会更新图表。然而,定性行为在每次运行时基本相同。

0 个答案:

没有答案