矩阵乘法的自动向量化

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

更新:当您使用 NM 等变量作为循环计数器时,您可能看不到矢量化。因此,您应该改用constants。根据我的经验,矩阵-矩阵乘法可以使用gcc 4.8, 5.4 and 6.2 进行矢量化。其他编译器,例如 clang-LLVMICCMSVC 也将其向量化。如 cmets 中所述,如果您使用 doublefloat 数据类型,您可能需要使用 -ffast-math 这是 -Ofast 优化级别中的启用标志,表示您不需要高精度结果(没关系大部分的时间)。这是因为编译器对浮点运算更加谨慎。

【讨论】:

@WorkofArtiz 和 Martin:gcc -O3 启用 -ftree-vectorize 和其他一些东西。请注意,-Ofast-O3 -ffast-math,而不是 -O2。无论如何,我建议比较 -O3 -ffast-math -march=nativeO3 -ffast-math -march=native -fno-tree-vectorize 关于常量与变量循环计数的要点。只要在第一次迭代之前知道循环迭代计数,gcc 和 clang 通常可以向量化。 (但他们永远无法向量化像while(a[i++] != 2) 这样的搜索循环)。不过,您是对的,它们通常在编译时常量循环计数方面做得更好。

以上是关于矩阵乘法的自动向量化的主要内容,如果未能解决你的问题,请参考以下文章

当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为

使用矢量化 C++ 的矩阵乘法

使用 openmp 并行化矩阵乘法并使用 avx2 进行矢量化

任务是使用 p 线程并行化矩阵乘法并使用英特尔 ISPC 编译器进行矢量化

如何进行快速的多维矩阵向量乘法?

Matlab 矩阵乘法以及矩阵点乘的规则区别