【问题标题】:How to hint OpenMP Stride?如何提示 OpenMP Stride?
【发布时间】:2013-05-06 23:52:04
【问题描述】:

我试图了解 OpenMP 打破循环矢量化的概念原因。此外,任何解决此问题的建议都会有所帮助。我正在考虑手动并行化它来解决这个问题,但这肯定不会很优雅并且会导致大量的代码膨胀,因为我的代码包含几个适合矢量化和并行化的部分。

我正在使用

Microsoft (R) C/C++ 优化编译器版本 17.00.60315.1 for x64

使用 OpenMP:

信息 C5002:由于原因“502”,循环未矢量化

没有 OpenMP:

info C5001:循环矢量化

VS vectorization page 说这个错误发生在:

归纳变量以不同于简单 +1 的方式步进

我可以强制它跨步 1 吗?

循环

#pragma omp parallel for
for (int j = 0; j < H*W; j++)//A,B,C,D,IN are __restricted
{
    float Gs = D[j]-B[j];
    float Gc = A[j]-C[j];
    in[j]=atan2f(Gs,Gc);
}

尽力而为(?)

#pragma omp parallel
{// This seems to vectorize, but it still requires quite a lot of boiler code
    int middle = H*W/2;
    #pragma omp sections nowait
    {
        #pragma omp section
        for (int j = 0; j < middle; j++)
        {
            float Gs = D[j]-B[j];
            float Gc = A[j]-C[j];
            in[j]=atan2f(Gs,Gc);
        }
        #pragma omp section
        for (int j = middle; j < H*W; j++)
        {
            float Gs = D[j]-B[j];
            float Gc = A[j]-C[j];
            in[j]=atan2f(Gs,Gc);
        }
    }
}

【问题讨论】:

  • 我很惊讶 Visual Studio 由于 atan2f 函数而将其向量化。我还没有尝试使用 Visual Studio 编译它,但使用 GCC 它不会矢量化(有或没有 OpenMP)。根据我的经验,GCC 的自动矢量化比 Visual Studio 更好。如果您使用 GCC,您最近提出的赏金问题就不会那么有趣了,因为 GCC 使用短裤矢量化循环没有问题。但也许这是 Visual Studio 的自动矢量化更好的一个例子。
  • 我在 Visual Studio 中试过这个。它像你说的那样矢量化。我对此感到非常惊讶。我没有测试过性能。我想知道 Visual Studio 为 atan2f 函数做了什么。它真的有 SSE/AVX atan2f 功能吗?

标签: c++ visual-studio-2012 openmp sse vectorization


【解决方案1】:

您可以尝试循环展开而不是 sections:

#pragma omp parallel for
for (int j = 0; j < H*W; j += outer_stride)//A,B,C,D,IN are __restricted
{
  for (int ii = 0; ii < outer_stride; ii++) {
    float Gs = D[j+ii]-B[j+ii];
    float Gc = A[j+ii]-C[j+ii];
    in[j+ii] = atan2f(Gs,Gc);
  }
}

其中outer_stride 是您的SIMD 行的合适倍数。此外,您可能会发现这个answer 很有用。

【讨论】:

  • 我喜欢你的建议。我在 GCC 中尝试过,但由于 atan2f 函数,它根本没有矢量化。我很惊讶 GCC 没有矢量化而 Visual Studio 做到了。我用“g++ foo.cpp -o foo -O3 -fopenmp -ftree-vectorizer-verbose=2 -ffast-math”编译
  • 我认为循环展开会导致与原始循环相同的问题。具体来说,VS 不确定步幅,从性能来看,循环似乎没有矢量化。
  • 我也在 VS 中尝试过你的建议,但它没有矢量化。实际上,我很惊讶原始循环矢量化。如果 Visual Studio 有 atan2f 的 SSE/AVX 版本,我会感到非常惊讶。
【解决方案2】:

我建议您手动进行矢量化。一个原因是自动矢量化似乎不能很好地处理循环依赖(循环展开)。

为了避免代码臃肿和晦涩难懂的内在函数,我使用了 Agner Fog 的矢量类。根据我的经验,它与使用内在函数一样快,并且它会根据您的编译方式自动利用 SSE2-AVX2(AVX2 在英特尔仿真器上测试)。我已经使用可在 SSE2 到 AVX2 上运行的向量类编写了 GEMM 代码,当我在带有 AVX 的系统上运行时,我的代码已经比仅使用 SSE 的 Eigen 更快。这是带有矢量类的函数(我没有尝试展开循环)。

#include "omp.h"
#include "math.h"

#include "vectorclass.h"
#include "vectormath.h"

void loop(const int H, const int W, const int outer_stride, float *A, float *B, float *C, float *D, float* in) {
    #pragma omp parallel for
    for (int j = 0; j < H*W; j+=8)//A,B,C,D,IN are __restricted, W*H must be a multiple of 8
    {
        Vec8f Gs = Vec8f().load(&D[j]) - Vec8f().load(&B[j]);
        Vec8f Gc = Vec8f().load(&A[j]) - Vec8f().load(&C[j]);
        Vec8f invec = atan(Gs, Gc);
        invec.store(&in[j]);
    }

}

当您自己进行矢量化时,您必须小心数组边界。在上面的函数中,HW 需要是 8 的倍数。有几种解决方案,但最简单和最有效的解决方案是使数组 (A,B,C,D,in) 稍大一点(最大 7 浮动更大)如果需要是 8 的倍数。但是,另一种解决方案是使用以下代码,它不需要 WH 是 8 的倍数,但它并不那么漂亮。

#define ROUND_DOWN(x, s) ((x) & ~((s)-1))
void loop_fix(const int H, const int W, const int outer_stride, float *A, float *B, float *C, float *D, float* in) {
    #pragma omp parallel for
    for (int j = 0; j < ROUND_DOWN(H*W,8); j+=8)//A,B,C,D,IN are __restricted
    {
        Vec8f Gs = Vec8f().load(&D[j]) - Vec8f().load(&B[j]);
        Vec8f Gc = Vec8f().load(&A[j]) - Vec8f().load(&C[j]);
        Vec8f invec = atan(Gs, Gc);
        invec.store(&in[j]);
    }
    for(int j=ROUND_DOWN(H*W,8); j<H*W; j++) {
        float Gs = D[j]-B[j];
        float Gc = A[j]-C[j];
        in[j]=atan2f(Gs,Gc);
    }

}

自己进行矢量化的一个挑战是找到一个 SIMD 数学库(例如用于 atan2f)。矢量类支持 3 个选项。非 SIMD、AMD 的 LIBM 和英特尔的 SVML(我在上面的代码中使用了非 SIMD 选项)。 SIMD math libraries for SSE and AVX

您可能要考虑的最后一些 cmet。 Visual Studio 具有自动并行化(默认关闭)和自动矢量化(默认开启,至少在发布模式下)。你可以试试这个而不是 OpenMP 来减少代码膨胀。 http://msdn.microsoft.com/en-us/library/hh872235.aspx

此外,Microsoft 拥有并行模式库。由于 Microsoft 的 OpenMP 支持有限,因此值得研究。它几乎和 OpenMP 一样容易使用。这些选项之一可能更适合自动矢量化(尽管我对此表示怀疑)。就像我说的,我会使用矢量类手动进行矢量化。

【讨论】:

    猜你喜欢
    • 2017-11-24
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 2021-10-24
    • 2019-02-23
    • 2022-11-18
    • 1970-01-01
    相关资源
    最近更新 更多