未能从intel的白皮书中重现高精度时间测量内核模块

问题描述

我正在尝试重现 How to Benchmark Code Execution Times on Intel IA-32 and IA-64 Instruction Set Architectures White Paper。本白皮书提供了一个内核模块,可以通过禁用抢占和使用{ allContentfulArticle { edges { node { content { raw references { ... on ContentfulArticle { contentful_id title slug } } } } } } } 等来准确测量一段代码的执行时间。

但是,在运行白皮书中报告的基准代码时,我无法获得预期的低方差,这意味着白皮书中的技术不起作用。我不知道出了什么问题。

内核模块的核心只是几行

RDTSC

代码直接从白皮书中复制而来,并进行了优化。 从白皮书来看,预期的输出应该是

unsigned int flags;
preempt_disable();
raw_local_irq_save(flags);

asm volatile(
    "cpuID\n\t"
    "RDTSC\n\t"
    "mov %%edx,%0\n\t"
    "mov %%eax,%1\n\t"
    : "=r"(cycles_high),"=r"(cycles_low)::"%rax","%rbx","%rcx","%rdx");
/* call the function to measure here */
asm volatile(
    "RDTSCP\n\t"
    "mov %%edx,%1\n\t"
    "cpuID\n\t"
    : "=r"(cycles_high1),"=r"(cycles_low1)::"%rax","%rdx");
raw_local_irq_restore(flags);
preempt_enable();

然而,我得到的是

loop_size:995 >>>> variance(cycles): 0; max_deviation: 0 ;min time: 2216
loop_size:996 >>>> variance(cycles): 28; max_deviation: 4 ;min time: 2216
loop_size:997 >>>> variance(cycles): 0; max_deviation: 112 ;min time: 2216
loop_size:998 >>>> variance(cycles): 28; max_deviation: 116 ;min time: 2220
loop_size:999 >>>> variance(cycles): 0; max_deviation: 0 ;min time: 2224
total number of spurIoUs min values = 0
total variance = 1
absolute max deviation = 220
variance of variances = 2
variance of minimum values = 335757

比白皮书高得多的 max_deviation 和方差(周期)。 (请忽略不同的 [1418048.049032] loop_size:42 >>>> variance(cycles): 104027;max_deviation: 92312 ;min time: 17 [1418048.049222] loop_size:43 >>>> variance(cycles): 18694;max_deviation: 43238 ;min time: 17 [1418048.049413] loop_size:44 >>>> variance(cycles): 1;max_deviation: 60 ;min time: 17 [1418048.049602] loop_size:45 >>>> variance(cycles): 1;max_deviation: 106 ;min time: 17 [1418048.049792] loop_size:46 >>>> variance(cycles): 69198;max_deviation: 83188 ;min time: 17 [1418048.049985] loop_size:47 >>>> variance(cycles): 1;max_deviation: 60 ;min time: 17 [1418048.050179] loop_size:48 >>>> variance(cycles): 1;max_deviation: 61 ;min time: 17 [1418048.050373] loop_size:49 >>>> variance(cycles): 1;max_deviation: 58 ;min time: 17 [1418048.050374] total number of spurIoUs min values = 2 [1418048.050374] total variance = 28714 [1418048.050375] absolute max deviation = 101796 [1418048.050375] variance of variances = 1308070648 ,因为白皮书可能实际上是在对某些内容进行基准测试,但我的代码实际上并未对任何内容进行基准测试。)

我在报告中遗漏了什么吗?或者白皮书不是最新的,我错过了现代 x86 cpu 中的一些技术?如何在现代 intel x86 cpu 架构中以最高精度测量一段代码的执行时间?

附言我运行的代码 is placed here

解决方法

大多数英特尔处理器都有一个恒定的 TSC,这意味着核心频率和 TSC 频率可能不同。如果一个操作需要固定数量的核心周期才能完成,那么在不同运行中执行操作期间,根据核心频率,可能需要非常不同数量的 TSC 周期。当 max_deviation 较大时,表明在该迭代的执行过程中核心频率发生了显着变化。解决方案是将核心频率固定为处理器的最大非睿频频率。有关恒定 TSC 的更多信息,请参阅:Can constant non-invariant tsc change frequency across cpu states?

请忽略不同的分钟时间,因为白皮书可能 实际上对某些东西进行基准测试,但我的代码实际上并没有 对任何事物进行基准测试。

最小值取决于微架构、核心频率(可以动态更改)和 TSC 频率(接近基频的某个固定值)。白皮书的作者只说他们使用的是 Core i7 处理器。在 2010 年,这是 Nehalem 或 Westmere 处理器。

您从论文中复制的测量值来自标题为“使用替代方法的分辨率”的第 3.3.2 节。替代方法使用 mov cr0,rax 而不是 rdtscp 进行序列化。但是你的代码来自第 3.2.2 节。

请注意,当 if ((end - start) < 0) {...}end 是无符号整数时,start 永远不会为真,因为减法的结果是无符号的,并且常量 0 也被转换为无符号类型。将其更改为 if (end < start) {...}