【发布时间】:2020-05-04 10:32:44
【问题描述】:
我想对在我的 Skylake (i5-6500) CPU 上进行一次添加所需的时间进行基准测试。 C对我来说足够低级了,所以我写了以下代码:
// Initializing stuffs
int a = rand();
int b = rand();
const unsigned long loop_count = 1000000000;
unsigned int ignored; // used for __rdtscp
// Warming up whatever needs to be warmed up
for (int i = 0; i < 100000; i++) {
asm volatile("" : "+r" (a)); // prevents Clang from replacing the loop with a multiplication
a += b;
}
// The actual measurement
uint64_t timer = __rdtscp(&ignored);
for (unsigned long i = 0; i < loop_count; i++) {
asm volatile("" : "+r" (a)); // prevents Clang from replacing the loop with a multiplication
a += b;
}
timer = __rdtscp(&ignored) - timer;
printf("%.2f cycles/iteration\n", (double)timer / loop_count);
使用 Clang 7.0.0 -O3 编译,我得到以下程序集(仅用于循环):
# %bb.2:
rdtscp
movq %rdx, %rdi
movl %ecx, 4(%rsp)
shlq $32, %rdi
orq %rax, %rdi
movl $1000000000, %eax # imm = 0x3B9ACA00
.p2align 4, 0x90
.LBB0_3: # =>This Inner Loop Header: Depth=1
#APP
#NO_APP
addl %esi, %ebx
addq $-1, %rax
jne .LBB0_3
# %bb.4:
rdtscp
并运行此代码输出
0.94 cycles/iteration
(或几乎总是介于 0.93 和 0.96 之间的数字)
我很惊讶这个循环可以在不到 1 个周期/迭代中执行,因为对 a 的数据依赖应该会阻止 a += b 的并行执行。
IACA 还确认预期吞吐量为 0.96 个周期。另一方面,llvm-mca 预测总共需要 104 个循环来执行 100 次循环迭代。 (如果需要,我可以在痕迹中进行编辑;让我知道)
当我使用 SSE 寄存器而不是通用寄存器时,我观察到了类似的行为。
我可以想象 CPU 足够聪明,可以注意到b 是恒定的,并且由于加法是可交换的,它可以展开循环并以某种方式优化加法。然而,我从来没有听说过也没有读过任何关于这个的东西。此外,如果这是正在发生的事情,我预计性能会比 0.94 个周期/迭代更好(即。 更少的周期/迭代)。
发生了什么事?这个循环如何能够在每次迭代不到 1 个周期内执行?
为了完整起见,有些背景。如果您对我为什么要对单个添加进行基准测试不感兴趣,请忽略剩下的问题。
我知道有一些工具(例如 llvm-exegesis)旨在对单个指令进行基准测试,我应该代替它们(或者只是查看 agner fog 的文档)。但是,我实际上是在尝试compare three different additions:一个在循环中进行单个添加(我的问题的对象);一种是每个循环进行 3 次加法(在 SSE 寄存器上,应该最大限度地使用端口,并且不受数据依赖性的限制),另一种是在软件中将加法实现为电路。虽然结果大多符合我的预期;该版本的 0.94 个循环/迭代在循环中添加了一个单独的内容,这让我感到困惑。
【问题讨论】:
-
你芯片上的TSC频率是多少?运行
dmesg | grep 'tsc'找出答案。核心频率是多少?核心频率是固定的吗? -
@HadiBrais 不错。修复CPU频率解决了这个问题。我认为将 cpufreq 调速器设置为“性能”就足够了。但是我已经将频率设置为 3.2GHz (
cpupower frequency-set -f 3.2G),现在我得到了 1.00 个周期/迭代,正如预期的那样。想把它作为答案发布吗? ;) -
可以作为How to get the CPU cycle count in x86_64 from C++? 的副本关闭,我的回答解释了 RDTSC 在参考周期中计数。可能有一个更具体的问题,这个问题更像你的问题,答案就集中在这个问题上。这是关于 RDTSC 工作原理的一个众所周知的事实,所以它似乎不值得一个 long 答案,但如果有人想写一个带有链接的简短答案。跨度>
标签: performance x86 intel rdtsc