【发布时间】:2014-03-01 03:55:42
【问题描述】:
这让我很惊讶,因为我一直认为loop应该有一些内部优化。
这是我今天做的实验。我使用的是 Microsoft Visual Studio 2010。我的操作系统是 64 位 Windows 8。我的问题在最后。
第一个实验:
平台:Win32
模式:调试(禁用优化)
begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
loop start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 3.583
(每次运行的数字都会略有变化,但在道德上是相同的大小。)
第二次实验:
平台:Win32
模式:调试
begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
dec ecx
jnz start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 0.903
第三和第四个实验:
只需将平台更改为 x64。由于 VC++ 不支持 64 位内联汇编,我必须将循环放在另一个 *.asm 文件中。但最后结果是一样的。
从这一点开始,我开始使用我的大脑 - loop 比 dec ecx, jnz start 慢 4 倍,它们之间的唯一区别,AFAIK,是 dec ecx 更改标志,而 loop 没有。为了模仿这个标志,我做了
第五次实验:
平台:Win32(以下我一直假设平台对结果没有影响)
模式:调试
begin = clock();
_asm
{
mov ecx, 07fffffffh
pushf
start:
popf
; do the loop here
pushf
dec ecx
jnz start
popf
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 22.134
这是可以理解的,因为pushf 和popf 必须玩内存。但是,例如,寄存器eax 不保留在循环的末尾(这可以通过更好地安排寄存器来实现),并且在循环中不需要标志OF (这简化了事情,因为OF不在flag的低8位中),那么我们可以使用lahf和sahf来保留标志,所以我做了
第六次实验:
平台:Win32
模式:调试
begin = clock();
_asm
{
mov ecx, 07fffffffh
lahf
start:
sahf
; do the loop here
lahf
dec ecx
jnz start
sahf
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 1.933
这还是比直接使用loop好很多吧?
我做的最后一个实验是尝试同时保留OF 标志。
第七次实验:
平台:Win32
模式:调试
begin = clock();
_asm
{
mov ecx, 07fffffffh
start:
inc al
sahf
; do the loop here
lahf
mov al, 0FFh
jo dec_ecx
mov al, 0
dec_ecx:
dec ecx
jnz start
}
end = clock();
cout<<"passed time: "<<double(end - begin)/CLOCKS_PER_SEC<<endl;
输出:passed time: 3.612
这个结果是最坏的情况,即OF 没有在每个循环中设置。而且和直接用loop差不多……
所以我的问题是:
我说的对吗,使用循环的唯一优点是它可以处理标志(实际上只有
dec对其中的 5 个标志有效)?是否有更长的
lahf和sahf也移动OF,这样我们就可以完全摆脱loop?
【问题讨论】:
-
因为 pushf 和 popf 必须使用内存。 是的,循环携带的依赖项包括从 pushf 到 popf 的存储转发,然后通过 EFLAGS 到下一个 pushf。但是这里最大的成本是
popf本身,它非常慢,因为它写入了所有的 EFLAGS,包括 IF 和其他机器状态标志,而不仅仅是条件代码。 (但如果您不尝试从用户空间更改它们,则不必出错)。例如,Sandybridge 上的popf是 9 微指令,每 18 个时钟吞吐量 1 (agner.org/optimize)
标签: assembly