问题描述
我正在尝试重现 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) {...}
。