4 memory variables optimization assembly
例如:
; Method 1
.data
val1 DWORD 10000h
.code
add eax,val1
Run Code Online (Sandbox Code Playgroud)
VS:
; Method 2
.code
add eax,10000h
Run Code Online (Sandbox Code Playgroud)
编译(汇编)后哪种方法执行速度更快?我认为方法2会产生更快的代码,因为在添加到eax寄存器之前,CPU不必从主存储器读取值.我的答案不太清楚,有人可以帮忙吗?
很可能,它将取决于情况,差异可能甚至不明显.
除非实际存在瓶颈,否则诸如乱序执行之类的因素可能会隐藏任何一种版本的固有"慢".
也就是说,如果我们必须选择哪个更快,那么你是正确的,第二种情况可能会更快.
如果我们查看所有当前x86处理器的Agner Fog表:
核心2:
add/sub r, r/i Latency = 1 , 1/Throughput = 0.33
add/sub r, m Latency = unknown , 1/Throughput = 1
Run Code Online (Sandbox Code Playgroud)
Nehalem处理器:
add/sub r, r/i Latency = 1 , 1/Throughput = 0.33
add/sub r, m Latency = unknown , 1/Throughput = 1
Run Code Online (Sandbox Code Playgroud)
珊迪大桥:
add/sub r, r/i Latency = 1 , 1/Throughput = 0.33
add/sub r, m Latency = unknown , 1/Throughput = 0.5
Run Code Online (Sandbox Code Playgroud)
K10:
add/sub r, r/i Latency = 1 , 1/Throughput = 0.33
add/sub r, m Latency = unknown , 1/Throughput = 0.5
Run Code Online (Sandbox Code Playgroud)
在所有情况下,内存操作数版本的吞吐量较低.在所有情况下,延迟都是未知的,但几乎肯定会超过1个周期.所有因素都更糟糕.
内存操作数版本使用与立即版本相同的所有执行端口+它还需要一个内存读取端口.这只会使情况变得更糟.事实上,这就是内存操作数的吞吐量较低的原因 - 内存端口只能维持1或2个读取/周期,而加法器可以维持一个完整的3 /周期.
此外,这假设数据在L1缓存中.如果不是,那么内存操作数版将是MUCH慢.
更进一步,我们可以检查编码指令的大小:
add eax,val1 -> 03 05 14 00 00 00
add eax,10000h -> 05 00 00 01 00
Run Code Online (Sandbox Code Playgroud)
第一个的编码可能会略有不同,具体取决于地址val1
.我在这里展示的例子来自我的特定测试用例.
因此,内存访问版本需要一个额外的字节进行编码 - 这意味着稍大的代码大小 - 并且可能更多的i-cache错过极端.
总而言之,如果版本之间存在性能差异,则立即可能会更快,因为:
无论如何,10000h 都将从存储器中读取 - 无论是从数据存储器中的位置,还是从指令存储器中的位置。对于较小的常数值,CPU 提供特殊指令,不需要额外的空间来添加值,但这取决于特定的体系结构。由于缓存,立即加法可能会更快:当指令被解码时,常量将在缓存中,并且加法将非常快。
小题外话:您的示例显示了优化 C 编译器生成比手写汇编更快的代码的情况:优化器可能不会添加 10000h,而是将上半字增加 1,并保留下半字 -词原样。