矩阵乘法的自动向量化
Posted
技术标签:
【中文标题】矩阵乘法的自动向量化【英文标题】:Automatic vectorization of matrix multiplication 【发布时间】:2017-04-05 23:28:44 【问题描述】:我是 SIMD 的新手,想试试看能否让 GCC 为我矢量化一个简单的操作。
所以我查看了this post 并想做或多或少相同的事情。 (但在 Linux 64 位上使用 gcc 5.4.0,用于 KabyLake 处理器)
我基本上有这个功能:
/* m1 = N x M matrix, m2 = M x P matrix, m3 = N x P matrix & output */
void mmul(double **m1, double **m2, double **m3, int N, int M, int P)
for (i = 0; i < N; i++)
for (j = 0; j < P; j++)
double tmp = 0.0;
for (k = 0; k < M; k++)
tmp += m1[i][k] * m2[k][j];
tmp = m3[i][j];
return m3;
我使用 -O2 -ftree-vectorize -msse2 -ftree-vectorizer-verbose=5
编译,但是我没有看到任何表示矢量化已完成的消息。
如果有人可以帮助我,那将非常感激。
【问题讨论】:
-fopt-info-all-vec
(有关详细信息,请参阅文档)提供了更多信息。 -fopt-info-missed-vec
的输出中的一个关键元素是“减少:不安全的 fp 数学优化:tmp_40 = _16 + tmp_49;”这基本上意味着您需要 -ffast-math (或稍弱的东西)来矢量化。
【参考方案1】:
在你的命令中没有关于矢量化的消息!您可以使用-fopt-info-vec
打开矢量化报告。但是,不要依赖它。编译器有时会撒谎(他们矢量化并报告它但不使用它!)您可以检查改进!为此,您可以测量加速。首先,禁用矢量化并测量时间 t1。然后启用并测量时间 t2。如果它大于 1,则加速将为 t1/t2,如果 1 没有改进,则表示编译器改进,如果小于 1,则表示编译器自动矢量化器毁了你!另一种方法是将-S
添加到命令中,并在单独的.s
文件中查看汇编代码。
注意:如果您想查看自动矢量化功能,请添加 -march=native
并删除 -msse2
。
更新:当您使用 N
、M
等变量作为循环计数器时,您可能看不到矢量化。因此,您应该改用constants
。根据我的经验,矩阵-矩阵乘法可以使用gcc 4.8, 5.4 and 6.2
进行矢量化。其他编译器,例如 clang-LLVM
、ICC
和 MSVC
也将其向量化。如 cmets 中所述,如果您使用 double
或 float
数据类型,您可能需要使用 -ffast-math
这是 -Ofast
优化级别中的启用标志,表示您不需要高精度结果(没关系大部分的时间)。这是因为编译器对浮点运算更加谨慎。
【讨论】:
@WorkofArtiz 和 Martin:gcc -O3
启用 -ftree-vectorize
和其他一些东西。请注意,-Ofast
是 -O3 -ffast-math
,而不是 -O2
。无论如何,我建议比较 -O3 -ffast-math -march=native
和 O3 -ffast-math -march=native -fno-tree-vectorize
。
关于常量与变量循环计数的要点。只要在第一次迭代之前知道循环迭代计数,gcc 和 clang 通常可以向量化。 (但他们永远无法向量化像while(a[i++] != 2)
这样的搜索循环)。不过,您是对的,它们通常在编译时常量循环计数方面做得更好。以上是关于矩阵乘法的自动向量化的主要内容,如果未能解决你的问题,请参考以下文章
当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为
使用 openmp 并行化矩阵乘法并使用 avx2 进行矢量化