显然,现代处理器可以判断您是否做了一些愚蠢的事情,比如将寄存器移动到自身(mov %eax, %eax),并对其进行优化。为了验证这一说法,我运行了以下程序:
#include <stdio.h>
#include <time.h>
static inline void f1() {
for (int i = 0; i < 100000000; i++)
__asm__(
"mov %eax, %eax;"
"nop;"
);
}
static inline void f2() {
for (int i = 0; i < 100000000; i++)
__asm__(
"nop;"
);
}
static inline void f3() {
for (int i = 0; i < 100000000; i++)
__asm__(
"mov %ebx, %eax;"
"nop;"
);
}
int main() {
int NRUNS = 10;
clock_t t, t1, t2, t3;
t1 = t2 = t3 = 0;
for (int run = 0; run < NRUNS; run++) {
t = clock(); f1(); t1 += clock()-t;
t = clock(); f2(); t2 += clock()-t;
t = clock(); f3(); t3 += clock()-t;
}
printf("f1() took %f cycles on avg\n", (float) t1/ (float) NRUNS);
printf("f2() took %f cycles on avg\n", (float) t2/ (float) NRUNS);
printf("f3() took %f cycles on avg\n", (float) t3/ (float) NRUNS);
return 0;
}这给了我:
f1() took 175587.093750 cycles on avg
f2() took 188313.906250 cycles on avg
f3() took 194654.296875 cycles on avg正如人们所预料的那样,f3()的发布速度最慢。但令人惊讶的是(至少对我来说),f1()比f2()快。为什么会这样呢?
Update:使用-falign-loops进行编译在质量上具有相同的结果:
f1() took 164271.000000 cycles on avg
f2() took 173783.296875 cycles on avg
f3() took 177765.203125 cycles on avg发布于 2018-10-26 11:41:48
链接文章中让我认为可以优化的部分是:“移动函数负责检查等效位置”。
这是关于SBCL中的(move r x)函数,而不是x86 mov指令。它讨论的是从低级中间语言生成代码时的优化,而不是通过硬件在运行时进行的优化。
mov %eax, %eax和nop都不是完全免费的。它们都耗费了前端的吞吐量,而且mov %eax,%eax甚至不是64位模式下的NOP (它零-将EAX扩展到RAX,并且因为相同的寄存器mov消除在Intel CPU上失败)。
有关前端/后端吞吐量瓶颈和延迟的更多信息,请参见X86的MOV真的可以“免费”吗?为什么我不能复制这个?。
您可能会看到代码对齐的一些副作用,或者可能出现了类似于在没有优化的情况下编译时,添加冗余分配会加快代码的速度。的时髦沙桥家族存储转发延迟效应,因为您也在编译时禁用了优化功能,让编译器生成反优化代码,以便进行一致的调试,从而将循环计数器保存在内存中。(~6个循环循环-通过存储/重新加载来承载依赖链,而不是对一个普通的微小循环每时钟进行一次迭代。)
如果您的结果可以通过更大的迭代次数来重现,那么您所看到的可能有一些微观架构的解释,但它可能与您试图测量的任何内容无关。
当然,您还需要修复f3中的f3错误,以便在启用优化的情况下成功编译。在不告诉编译器的情况下破坏EAX,就会踩上编译器生成的代码。你没有解释你试图用它测试什么,所以IDK如果它是错误的话。
https://stackoverflow.com/questions/52992723
复制相似问题