performance - 为什么内存往返比不执行往返更快?

标签 performance assembly x86

我有一些简单的 32 位代码,用于计算 32 位整数数组的乘积。内部循环如下所示:

@@loop:
mov esi,[ebx]
mov [esp],esi
imul eax,[esp]
add ebx, 4
dec edx
jnz @@loop

我想理解的是为什么上面的代码比这两个版本的代码快 6%,这两个版本不执行冗余内存往返:
@@loop:
mov esi,[ebx]
imul eax,esi
add ebx, 4
dec edx
jnz @@loop


@@loop:
imul eax,[ebx]
add ebx, 4
dec edx
jnz @@loop

后两段代码几乎同时执行,正如前面提到的,两者都比第一段慢 6%(165 毫秒对 155 毫秒,2 亿个元素)。

我试过手动将跳转目标对齐到 16 字节的边界,但这没有区别。

我在 Intel i7 4770k、Windows 10 x64 上运行它。

注意:我知道可以通过进行各种优化来改进代码,但是我只对上述代码段之间的性能差异感兴趣。

最佳答案

我怀疑但不能确定您是否阻止了数据依赖项的停顿:

代码如下所示:

@@loop:
    mov esi,[ebx]    # (1)Load the memory location to esi reg
    (mov [esp],esi)  # (1)optionally store the location on the stack      
    imul eax,[esp]   # (3) Perform the multiplication
    add ebx, 4       # (1) Add 4
    dec edx          # (1)decrement counter
    jnz @@loop       # (0**) loop 

括号中的那些数字是指令的延迟……如果分支预测器正确猜测,则跳转为 0(因为它大部分时间都会循环)。

所以:当乘法仍在进行时(3 条指令),我们在 2 之后回到循环的顶部并尝试加载到内存中,但必须停止。或者我们可以做一个存储......我们可以在乘法的同时做,然后根本不会停顿。

你问的虚拟商店呢?为什么这样做?请注意,您正在存储我们用来乘以内存的临界值。因此处理器可以使用这个存储在内存中的值并破坏寄存器。

那么为什么处理器不能这样做呢?处理器不能产生比您要求的更多的内存访问,否则它可能会干扰多处理器程序(想象一下您正在写入的缓存线是共享的,并且您必须在每个循环中通过写入来使其在其他 CPU 上无效……哎哟!)。

所有这些都是纯粹的猜测,但它似乎与所有证据相符(您的代码和我对英特尔架构……和 x86 程序集的了解)。如果我有什么不对的地方,希望有人能指出。

关于performance - 为什么内存往返比不执行往返更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31869079/

相关文章:

performance - 如何优化打开和关闭Excel工作簿以提取数据以加快运行速度

java - 从 JSONObject 读取值的更好方法

assembly - nasm 英特尔 : Access items in the stack without using pop

assembly - 通过将 EFLAGS.VM 设置为 1 从 32 位保护模式切换到 v8086 模式时出现问题

c++ - 在 x86 SIMD vector 中查找最大元素的索引

django - 如何为可能的斜线打点 Django 做好准备?

c# - 显示和隐藏游戏对象的最有效技术?

c - 我的 (AT&T) 程序集 (x86-x64) 代码应该增加但不增加

assembly - 如何在 IA32 上将带符号的整数求和为更宽的和。 32 位有符号整数的 64 位和?

c++ - 有没有优化 x86 二进制代码的库?