我需要每秒运行240000次矩阵向量乘法。矩阵是5x5并且始终相同,而向量在每次迭代时都会发生变化。数据类型是float。我正在考虑使用一些SSE(或类似的)指令。
1)我担心与所涉及的内存操作数相比,算术运算的数量太少。你认为我可以获得一些有形的(例如> 20%)改善吗?
2)我需要英特尔编译器吗?
3)你能指出一些参考文献吗?
谢谢大家!
答案 0 :(得分:9)
答案 1 :(得分:4)
如果您正在使用GCC,请注意-O3选项将启用自动矢量化,在许多情况下会自动生成SSE或AVX指令。一般来说,如果你只是把它写成一个简单的for循环,GCC会对它进行矢量化。有关详细信息,请参阅http://gcc.gnu.org/projects/tree-ssa/vectorization.html。
答案 2 :(得分:4)
原则上,SSE的加速比可为4倍(AVX为8倍)。让我解释一下。
我们称之为固定的5x5矩阵 M 。将5D向量的分量定义为(x,y,z,w,t)。现在从前四个向量形成一个5x4矩阵 U 。
U =
xxxx
yyyy
zzzz
wwww
tttt
接下来,做矩阵产品 MU = V 。矩阵 V 包含 M 和前四个向量的乘积。唯一的问题是,对于SSE我们需要在 U 行中读取,但在内存 U 存储为 xyzwtxyzwtxyzwtxyzwt ,所以我们必须转置它到 xxxxyyyyzzzzwwwwtttt 。这可以通过SSE中的shuffles / blend进行。一旦我们有这种格式,矩阵产品就非常有效。
不是采用标量码进行O(5x5x4)运算,而是仅需要O(5x5)运算,即4倍加速。使用AVX时,矩阵 U 将为5x8,因此不需要进行O(5x5x8)操作,而只需对O(5x5)征税,即加速8倍。
然而,矩阵 V 将采用 xxxxyyyyzzzzwwwwtttt 格式,因此根据应用程序,它可能必须转换为 xyzwtxyzwtxyzwtxyzwt 格式。
对接下来的四个向量(AVX为8)重复此操作,依此类推,直至完成。
如果你可以控制向量,例如你的应用程序动态生成向量,那么你可以用 xxxxyyyyzzzzwwwwtttt 格式生成它们,并避免数组的转置。在这种情况下,您应该使用SSE加速4倍,使用AVX加速8倍。如果将此与线程结合使用,例如OpenMP,你的加速应该接近16倍(假设有4个物理内核)和SSE。我认为这是你能用SSE做的最好的事情。
编辑:由于指令级并行性(ILP),您可以在加速时获得另一个因子2,因此SSE的加速可以是四个核心(64x AVX)的32倍,并且由于FMA3,再次使用Haswell的另一个因子为2。
答案 3 :(得分:3)
我建议使用英特尔IPP并提取自己对技术的依赖
答案 4 :(得分:2)
这应该很容易,特别是当你在Core 2或更高版本时:你需要5 * _mm_dp_ps,一个_mm_mul_ps,两个_mm_add_ps,一个普通的乘法,加上一些shuffle,加载和存储(如果矩阵是固定的,如果您不需要其他任何东西,您可以将其中的大部分保留在sse寄存器中。
至于内存带宽:当内存带宽为每秒一位数千兆字节时,我们讨论的是2,4兆字节的向量。
答案 5 :(得分:1)
对载体有何了解?由于矩阵是固定的,并且如果向量可以采用有限数量的值,那么我建议您预先计算计算并使用表查找来访问它们。
为循环交换内存的经典优化技术......
答案 6 :(得分:0)
我建议您查看优化的BLAS库,例如Intel MKL或AMD ACML。根据您的描述,我假设您将在SGEMV
2级矩阵向量例程之后进行y = A*x
样式操作。
如果你真的想自己实现一些东西,使用(可用的)SSE..SSE4
和AVX
指令集可以在某些情况下提供显着的性能改进,尽管这正是一个好的BLAS库将是这样做。您还需要考虑很多有关缓存友好的数据访问模式。
我不知道这是否适用于你的情况,但是你可以一次操作矢量的“块”吗?因此,您可以在y = A*x
块上操作,而不是重复执行[y1 y2 ... yn] = A * [x1 x2 ... xn]
样式操作。如果是这样,这意味着您可以使用优化的矩阵矩阵例程,例如SGEMM
。由于数据访问模式,这可能比重复调用SGEMV
更有效。如果是我,我会试着走这条路......
希望这有帮助。
答案 7 :(得分:0)
如果您事先知道向量(例如,一次完成所有240k),那么通过并行循环比通过SSE获得更好的加速。如果您已经采取了这一步骤,或者您不能立即了解它们,那么SSE可能是一个很大的好处。
如果内存是连续的,那么不要过多担心内存操作。如果你有链接列表或其他东西,那么你遇到了麻烦,但它应该能够跟上而没有太多问题。
5x5是一个有趣的大小,但你可以在一个SSE指令中至少执行4次触发,并尝试减少算术开销。你不需要英特尔编译器,但它可能会更好,我听说有关算术代码如何更好的传说。 Visual Studio具有处理SSE2的内在函数,我认为SSE4取决于您的需求。当然,你必须自己滚动它。抓住图书馆可能是明智之举。