当前位置: 首页 > 知识库问答 >
问题:

在情报上丢失的周期?rdtsc与CPU_CLK_UNHALTED.REF_TSC之间的不一致

徐飞尘
2023-03-14

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

INST_RETIRED.ANY
CPU_CLK_UNHALTED.THREAD
CPU_CLK_UNHALTED.REF_TSC

第一个计算退役的指令,第二个计算实际循环的数量,最后一个计算我们感兴趣的。《英特尔软件开发人员手册》第3卷的描述如下:

当内核不处于停止状态和TM停止时钟状态时,此事件以TSC速率计算参考周期数。内核在运行HLT指令或MWAIT指令时进入halt状态。该事件不受核心频率变化(例如,P状态)的影响,而是以与时间戳计数器相同的频率计数。此事件可以近似地表示内核未处于停止状态和TM停止时钟状态时所经过的时间。

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);
}
void busy_loop(uint64_t iters) {
    volatile int sink;
    do {
        sink = 0;
    } while (--iters > 0);
    (void)sink;
}
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,事情也没有以精确的方式交织,但是校准循环是一整秒钟,所以这种纳秒级的问题只是被稀释到或多或少没有什么。

启用涡轮增压后,在我的i7-6700HQ Skylake CPU上典型运行的前几个结果如下:

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

这里,ref_tsc是上述固定的TSC性能计数器,rdtscrdtsc指令的结果。eff MHz是在该间隔内有效计算的真实CPU频率,主要是出于好奇心的考虑,也是为了快速确认turbo正在发挥多大作用。ratioref_tscrdtsc列的比率。我希望这个值非常接近1,但在实践中,我们看到它在0.90到0.92之间徘徊,差异很大(我在其他运行中看到它低至0.8)。

从图形上看,它类似于2:

RDSTC调用返回几乎精确的结果1,而PMU TSC计数器到处都是,有时几乎低至2300 MHz。

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

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事实上,有一段时间,我确实得到了精确到小数点后两位的结果:2591.97MHz-一次又一次迭代。然后发生了一些变化,我不确定是什么,在RDSTC结果中有大约0.1%的小变化。一种可能是渐进式时钟调整,由Linux计时子系统进行,使本地crystal导出的时间与NTPD确定的时间一致。也许,这只是一个晶体漂移--上面的最后一张图显示了rdtsc每秒测量的周期稳步增加。

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

共有1个答案

宋高谊
2023-03-14

您在rdtscreftsc之间观察到的差异是由于TurboBoost p态转换造成的。在这些转换期间,大部分核心(包括固定函数性能计数器ref_tsc)将停止大约20000-21000个周期(8.5us),但rdtsc将以其不变的频率继续。rdtsc可能处于一个独立的电源和时钟域中,因为它非常重要,而且它的行为类似于Wallclock。

这种差异表现为rdtsc超支reftsc的趋势。程序运行的时间越长,rdtsc-reftsc的差异越大。在很长一段时间内,它可以高达1%-2%,甚至更高。

当然,您已经观察到,当禁用TurboBoost时,过计数会消失,使用intel_pstate,可以如下所示:

echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo

TurboBoost是一种动态的频率和电压缩放解决方案,可以适时地利用工作包络(热或电)中的净空。在可能的情况下,TurboBoost会将处理器的核心频率和电压扩大到超出其标称值,从而以更高的功耗为代价来提高性能。

更高的功耗当然会增加核心温度和功耗。最终,某种极限将被击中,涡轮增压将不得不曲柄降低性能。

我首先调查热监视器1(TM1)或2(TM2)的热控制电路(TCC)是否导致热节流。TM1通过插入TM停止时钟周期来降低功耗,这些是导致reftsc停止的条件之一。TM2,另一方面,不门时钟;它只调节频率。

  • IA32_Thread_Stall:计算由于该逻辑处理器上强制空闲而停顿的循环数。
  • msr_core_hdc_residency:与上面相同,但是对于物理处理器,当该内核的一个或多个逻辑处理器强制空闲时计算周期。
  • MSR_PKG_HDC_SHALLOW_RESTESENCY:计算包处于C2状态且至少有一个逻辑处理器处于强制空闲状态的周期。
  • MSR_PKG_HDC_Deep_Residency:计算包处于更深(精确地说是可配置的)C状态并且至少有一个逻辑处理器处于强制空闲状态的周期。

有关详细信息,请参阅Intel SDM第3卷第14章§14.5.1硬件占空比循环编程接口

但是我的i7-4700MQ 2.4GHz CPU不支持HDC,所以这就是HDC。

  • 0:PROCHOT状态
  • 1:热状态
  • 4:图形驱动程序状态。设置后,由于处理器图形驱动程序重写,频率会降低到低于操作系统请求。
  • 5:基于自主使用的频率控制状态。设置后,频率降低到低于操作系统请求,因为处理器检测到利用率很低。
  • 6:电压调节器热警报状态。设置后,由于电压调节器发出热警报,频率降低到低于操作系统要求。
  • 8:电气设计点状态。设置后,由于电气设计点限制(例如最大电流消耗),频率会降低到操作系统要求以下。
  • 9:核心功率限制状态。设置后,由于域级功率限制,频率会降低到低于操作系统请求。
  • 10:封装级功率限制PL1状态。设置后,由于包级功率限制PL1,频率降低到低于操作系统请求。
  • 11:包级功率限制PL2状态。设置后,由于包级功率限制PL2,频率降低到低于操作系统请求。
  • 12:最大Turbo限制状态。设置后,由于多核turbo限制,频率会降低到低于操作系统请求。
  • 13:Turbo转换衰减状态。当设置时,由于Turbo转换衰减,频率降低到操作系统要求以下。这可以防止由于频繁的操作比率更改而导致的性能下降。
  • 16:PROCHOT log
  • 17:热日志
  • 20:图形驱动程序日志
  • 21:基于自主利用率的频率控制日志
  • 22:电压调节器热警报日志
  • 24:电气设计点日志
  • 25:核心功率限制日志
  • 26:包级功率限制PL1 log
  • 27:包级功率限制PL2 log
  • 28:最大Turbo限制日志
  • 29:Turbo转换衰减日志

pfc.ko现在支持这个MSR,演示会显示这些日志位中哪些是活动的。pfc.ko驱动程序在每次读取时清除粘滞位。

我在打印位的同时重新运行了您的实验,我的CPU报告在非常重的负载下(所有4个内核/8个线程活动)有几个限制因素,包括电气设计点和内核功率限制。由于我不知道的原因,包级PL2和最大Turbo限制位总是在我的CPU上设置。我也看到有时涡轮过渡衰减。

echo   0 > /sys/devices/system/cpu/cpu1/online
echo   0 > /sys/devices/system/cpu/cpu2/online
echo   0 > /sys/devices/system/cpu/cpu4/online
echo   0 > /sys/devices/system/cpu/cpu5/online
echo   0 > /sys/devices/system/cpu/cpu6/online
echo   0 > /sys/devices/system/cpu/cpu7/online
echo  98 > /sys/devices/system/cpu/intel_pstate/min_perf_pct
echo 100 > /sys/devices/system/cpu/intel_pstate/max_perf_pct

我运行了10000个示例的演示应用程序

1000,     1500,     2500,     4000,     6300,
10000,    15000,    25000,    40000,    63000,
100000,   150000,   250000,   400000,   630000,
1000000,  1500000,  2500000,  4000000,  6300000,
10000000, 15000000, 25000000, 40000000, 63000000

以标称CPU频率执行的每add_alibrary()毫微秒数(将上面的数字乘以2.4以获得add_alibrary())的实际参数)。

这将生成如下所示的日志(250000 nanos的情况):

CPU 0, measured CLK_REF_TSC MHz        :          2392.56
CPU 0, measured rdtsc MHz              :          2392.46
CPU 0, measured add   MHz              :          3286.30
CPU 0, measured XREF_CLK  time (s)     :       0.00018200
CPU 0, measured delta     time (s)     :       0.00018258
CPU 0, measured tsc_delta time (s)     :       0.00018200
CPU 0, ratio ref_tsc :ref_xclk         :      24.00131868
CPU 0, ratio ref_core:ref_xclk         :      33.00071429
CPU 0, ratio rdtsc   :ref_xclk         :      24.00032967
CPU 0, core CLK cycles in OS           :                0
CPU 0, User-OS transitions             :                0
CPU 0, rdtsc-reftsc overcount          :              -18
CPU 0, MSR_IA32_PACKAGE_THERM_STATUS   : 000000008819080a
CPU 0, MSR_IA32_PACKAGE_THERM_INTERRUPT: 0000000000000003
CPU 0, MSR_CORE_PERF_LIMIT_REASONS     : 0000000018001000
        PROCHOT
        Thermal
        Graphics Driver
        Autonomous Utilization-Based Frequency Control
        Voltage Regulator Thermal Alert
        Electrical Design Point (e.g. Current)
        Core Power Limiting
        Package-Level PL1 Power Limiting
      * Package-Level PL2 Power Limiting
      * Max Turbo Limit (Multi-Core Turbo)
        Turbo Transition Attenuation
CPU 0, measured CLK_REF_TSC MHz        :          2392.63
CPU 0, measured rdtsc MHz              :          2392.62
CPU 0, measured add   MHz              :          3288.03
CPU 0, measured XREF_CLK  time (s)     :       0.00018192
CPU 0, measured delta     time (s)     :       0.00018248
CPU 0, measured tsc_delta time (s)     :       0.00018192
CPU 0, ratio ref_tsc :ref_xclk         :      24.00000000
CPU 0, ratio ref_core:ref_xclk         :      32.99983509
CPU 0, ratio rdtsc   :ref_xclk         :      23.99989006
CPU 0, core CLK cycles in OS           :                0
CPU 0, User-OS transitions             :                0
CPU 0, rdtsc-reftsc overcount          :               -2
CPU 0, MSR_IA32_PACKAGE_THERM_STATUS   : 000000008819080a
CPU 0, MSR_IA32_PACKAGE_THERM_INTERRUPT: 0000000000000003
CPU 0, MSR_CORE_PERF_LIMIT_REASONS     : 0000000018001000
        PROCHOT
        Thermal
        Graphics Driver
        Autonomous Utilization-Based Frequency Control
        Voltage Regulator Thermal Alert
        Electrical Design Point (e.g. Current)
        Core Power Limiting
        Package-Level PL1 Power Limiting
      * Package-Level PL2 Power Limiting
      * Max Turbo Limit (Multi-Core Turbo)
        Turbo Transition Attenuation
CPU 0, measured CLK_REF_TSC MHz        :          2284.69
CPU 0, measured rdtsc MHz              :          2392.63
CPU 0, measured add   MHz              :          3151.99
CPU 0, measured XREF_CLK  time (s)     :       0.00018121
CPU 0, measured delta     time (s)     :       0.00019036
CPU 0, measured tsc_delta time (s)     :       0.00018977
CPU 0, ratio ref_tsc :ref_xclk         :      24.00000000
CPU 0, ratio ref_core:ref_xclk         :      33.38540919
CPU 0, ratio rdtsc   :ref_xclk         :      25.13393301
CPU 0, core CLK cycles in OS           :                0
CPU 0, User-OS transitions             :                0
CPU 0, rdtsc-reftsc overcount          :            20548
CPU 0, MSR_IA32_PACKAGE_THERM_STATUS   : 000000008819080a
CPU 0, MSR_IA32_PACKAGE_THERM_INTERRUPT: 0000000000000003
CPU 0, MSR_CORE_PERF_LIMIT_REASONS     : 0000000018000000
        PROCHOT
        Thermal
        Graphics Driver
        Autonomous Utilization-Based Frequency Control
        Voltage Regulator Thermal Alert
        Electrical Design Point (e.g. Current)
        Core Power Limiting
        Package-Level PL1 Power Limiting
      * Package-Level PL2 Power Limiting
      * Max Turbo Limit (Multi-Core Turbo)
        Turbo Transition Attenuation
CPU 0, measured CLK_REF_TSC MHz        :          2392.46
CPU 0, measured rdtsc MHz              :          2392.45
CPU 0, measured add   MHz              :          3287.80
CPU 0, measured XREF_CLK  time (s)     :       0.00018192
CPU 0, measured delta     time (s)     :       0.00018249
CPU 0, measured tsc_delta time (s)     :       0.00018192
CPU 0, ratio ref_tsc :ref_xclk         :      24.00000000
CPU 0, ratio ref_core:ref_xclk         :      32.99978012
CPU 0, ratio rdtsc   :ref_xclk         :      23.99989006
CPU 0, core CLK cycles in OS           :                0
CPU 0, User-OS transitions             :                0
CPU 0, rdtsc-reftsc overcount          :               -2
CPU 0, MSR_IA32_PACKAGE_THERM_STATUS   : 000000008819080a
CPU 0, MSR_IA32_PACKAGE_THERM_INTERRUPT: 0000000000000003
CPU 0, MSR_CORE_PERF_LIMIT_REASONS     : 0000000018001000
        PROCHOT
        Thermal
        Graphics Driver
        Autonomous Utilization-Based Frequency Control
        Voltage Regulator Thermal Alert
        Electrical Design Point (e.g. Current)
        Core Power Limiting
        Package-Level PL1 Power Limiting
      * Package-Level PL2 Power Limiting
      * Max Turbo Limit (Multi-Core Turbo)
        Turbo Transition Attenuation

饱和绿点:-3个标准差(低于平均值)

在大约250000纳秒的持续衰减之前、期间和之后有显著的差异。

在阈值之前,CSV日志如下所示:

24.00,33.00,24.00,-14,0,0
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,-4,3639,1
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-14,0,0
24.00,33.00,24.00,-14,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-44,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-14,0,0
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,12,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,32,3171,1
24.00,33.00,24.00,-20,0,0
24.00,33.00,24.00,10,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,2,0,0
24.00,33.00,24.00,22,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.05,25.11,20396,0,0
24.00,33.38,25.12,20212,0,0
24.00,33.39,25.12,20308,0,0
24.00,33.42,25.12,20296,0,0
24.00,33.43,25.11,20158,0,0
24.00,33.43,25.11,20178,0,0
24.00,33.00,24.00,-4,0,0
24.00,33.00,24.00,20,3920,1
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-4,0,0
24.00,33.44,25.13,20396,0,0
24.00,33.46,25.11,20156,0,0
24.00,33.46,25.12,20268,0,0
24.00,33.41,25.12,20322,0,0
24.00,33.40,25.11,20216,0,0
24.00,33.46,25.12,20168,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,-2,0,0
24.00,33.00,24.00,22,0,0
24.00,33.75,24.45,20166,0,0
24.00,33.78,24.45,20302,0,0
24.00,33.78,24.45,20202,0,0
24.00,33.68,24.91,41082,0,0
24.00,33.31,24.90,40998,0,0
24.00,33.70,25.30,58986,3668,1
24.00,33.74,24.42,18798,0,0
24.00,33.74,24.45,20172,0,0
24.00,33.77,24.45,20156,0,0
24.00,33.78,24.45,20258,0,0
24.00,33.78,24.45,20240,0,0
24.00,33.77,24.42,18826,0,0
24.00,33.75,24.45,20372,0,0
24.00,33.76,24.42,18798,4081,1
24.00,33.74,24.41,18460,0,0
24.00,33.75,24.45,20234,0,0
24.00,33.77,24.45,20284,0,0
24.00,33.78,24.45,20150,0,0
24.00,33.78,24.45,20314,0,0
24.00,33.78,24.42,18766,0,0
24.00,33.71,25.36,61608,0,0
24.00,33.76,24.45,20336,0,0
24.00,33.78,24.45,20234,0,0
24.00,33.78,24.45,20210,0,0
24.00,33.78,24.45,20210,0,0
24.00,33.00,24.00,-10,0,0
24.00,33.00,24.00,4,0,0
24.00,33.00,24.00,18,0,0
24.00,33.00,24.00,2,4132,1
24.00,33.00,24.00,44,0,0
 类似资料:
  • 问题内容: 我想在特定时间获取CPU周期。我当时使用此功能: (编者注:是错的x86-64,捡起 _任何_RDX或RAX仅在32位模式下将它挑EDX:你想EAX输出中看到的。 问题是它总是返回一个 递增的 数字(每次运行)。好像是在指绝对时间。 我使用的功能不正确吗? 问题答案: 只要您的线程停留在相同的CPU内核上,RDTSC指令就会一直返回递增的数字,直到它回绕为止。对于2GHz CPU,这种

  • 问题内容: 我正在运行基本的ELK堆栈。在vm中运行的所有三个组件。Logstash正在侦听TCP 9140,以获取其输入通过NxLog代理从大约30个Windows Server 2008s和30个Windows Server 2003事件(evts)中接收的信息,并将其输出到elasticsearch。 这个已经运行了好几个星期了。我可以看到ElasticSearch每天都在创建索引,并且可以

  • 我的spring boot应用程序总是在早上向我显示这个白标签错误:无法打开JPA EntityManager进行事务处理;嵌套异常为javax.persistence.persistenceException:org.hibernate.transactionException:JDBC begin transaction Failed: 对于数据源,我使用spring Data的存储库: 下面

  • 鉴于下面的代码片段,为什么最后四个输出周期是相同的?我希望这些行的天数部分是4,3,2,1,而不是4,4,4,4。这是一个错误还是我遗漏了一些明显的东西?(天晚了,我很累,所以很可能是后者。)我用的是野田佳彦时间1.2.0。

  • 问题内容: 大家好,如果在Java中提供了开始日期和结束日期,那么如何生成日期呢? 像下面这样: 例:如果有并且我希望日期与以下类似,则列表应省略和 我已经完成了以下操作,但是如果日期范围是同一个月,它将生成一个月。` 因此,请为我提供建议。 问候托尼 问题答案: 使用以下乔达时间

  • 问题内容: servlet和过滤器生命周期之间有什么区别吗? 问题答案: 不,一个servlet和一个过滤器: 在上下文开始时实例化(一次) 该方法称为 他们处理每个请求-首先,它通过所有过滤器,然后到达servlet 当上下文被破坏时(即,当您的容器停止运行或从管理器控制台取消部署您的应用程序时),该方法被调用