代码之家  ›  专栏  ›  技术社区  ›  Brett

汇编/SSE乘法帮助

  •  2
  • Brett  · 技术社区  · 15 年前

    我一直在努力找出如何在非常关键的几行代码中获得一些改进:

    float x = a*b;
    float y = c*d;
    float z = e*f;
    float w = g*h;
    

    所有的A,B,C…是漂浮物。

    我决定研究使用SSE,但似乎没有发现任何改进,事实上它的速度是原来的两倍。我的SSE代码是:

    Vector4 abcd, efgh, result;
    abcd = [float a, float b, float c, float d];
    efgh = [float e, float f, float g, float h];
    _asm {
    movups xmm1, abcd
    movups xmm2, efgh
    mulps xmm1, xmm2
    movups result, xmm1
    }
    

    我还尝试使用标准的内联程序集,但似乎我不能像使用SSE那样将寄存器打包为四个浮点。

    任何评论,或帮助将非常感谢,我主要需要理解为什么我的计算使用SSE慢于串行C++代码?

    我正在WindowsXP上的Visual Studio2005中编译,使用带有HT的Pentium4,如果它提供了任何附加信息可供辅助。

    事先谢谢!

    5 回复  |  直到 12 年前
        1
  •  3
  •   Skizz    15 年前

    正如您所发现的,仅仅用SSE替换两个指令是行不通的,因为您需要在内存中来回移动数据,以便正确地加载SSE寄存器,而在内存中来回移动数据(构造数组的位)会破坏您的性能,因为内存非常慢(硬盘除外,内存I这些天都是瓶颈。

    此外,在SSE和FPU/ALU之间,如果不使用写入RAM和读取,就无法移动数据。现代的IA32芯片可以很好地处理这种特殊的模式(先写后读),但仍然会使某些具有连锁反应的缓存失效。

    为了充分利用SSE,您需要查看整个算法和算法使用的数据。A、B、C和D以及E、F、G和H的值需要永久性地存在于这些数组中,以便在加载SSE寄存器之前内存中没有移动数据。这并不简单,可能需要对代码和数据进行大量的修改(您可能需要在磁盘上以不同的方式存储数据)。

    同样值得指出的是,SSE只有32位(如果使用double,则为64位),而FPU是80位(不考虑float或double),因此在使用SSE时,与使用FPU相比,会得到稍微不同的结果。只有你知道这是否会成为一个问题。

        2
  •  3
  •   Anycorn    15 年前

    您使用的是未对齐的指令,速度非常慢。 您可能需要尝试正确对齐数据、16字节边界和使用movaps。 更好的选择是使用内部函数,而不是程序集,因为编译器可以自由地按需要排序指令。

        3
  •  1
  •   Puppy    15 年前

    您可以在较新的VS版本和可能在2005年的程序选项中启用SSE和SSE2。使用Express版本编译?

    此外,SSE中的代码可能比较慢,因为当编译串行C++时,编译器是聪明的,并且在使它非常快的方面做得非常好——例如,在正确的时间自动将它们放在正确的寄存器中。例如,如果操作是串行的,编译器可以减少缓存和分页的影响。但是,内联汇编程序最多只能进行很差的优化,应该尽可能避免。

    此外,您必须为SSE/2执行大量工作,才能带来显著的好处。

        4
  •  1
  •   Stéphane Perras    13 年前

    这是一条旧线,但我注意到您的示例中有一个错误。如果要执行此操作:

    float x = a*b;
    float y = c*d;
    float z = e*f;
    float w = g*h;
    

    那么代码应该是这样的:

    Vector4 aceg, bdfh, result;  // xyzw
    abcd = [float a, float c, float e, float g];
    efgh = [float b, float d, float f, float h];
    _asm {
    movups xmm1, abcd
    movups xmm2, efgh
    mulps xmm1, xmm2
    movups result, xmm1
    }
    

    为了获得更高的速度,我建议您不要对“结果”使用单独的寄存器。

    对于初学者来说,并不是所有的算法都有利于在SSE中重写。数据驱动的算法(如查找表驱动的算法)不能很好地转化为SSE,因为大量的时间会丢失打包和将数据解包成向量以便SSE操作。

    希望这仍然有帮助。

        5
  •  0
  •   gens    12 年前

    首先,当您将128位(16字节)对齐时,您应该使用movaps,因为它可能更快。 编译器通常应该为您提供16字节的对齐,即使在32位系统上也是如此。

    你的C/C++行和你的SSE代码不一样。

    一个xmm寄存器中的四个浮点与另一个寄存器中的四个浮点相乘。 给你:

    float x = a*e;
    float y = b*f;
    float z = c*g;
    float w = d*h;
    

    在SSE1中,在乘法之前必须使用SHUFP对两个寄存器中的浮点进行重新排序。

    此外,对于处理比CPU缓存更大的数据,可以使用非时间存储(movntps)来减少缓存污染。 注意,在其他情况下,非时间存储速度要慢得多。