gpt4 book ai didi

c++ - 如何提示 OpenMP Stride?

转载 作者:太空狗 更新时间:2023-10-29 21:24:18 31 4
gpt4 key购买 nike

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

我正在使用

Microsoft (R) C/C++ Optimizing Compiler Version 17.00.60315.1 for x64

使用 OpenMP:

info C5002: loop not vectorized due to reason '502'

没有 OpenMP:

info C5001: loop vectorized

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

Induction variable is stepped in some manner other than a simple +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);
}
}
}

最佳答案

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

为了避免代码膨胀和神秘的内在函数,我使用了 Agner Fog 的 vector 类。根据我的经验,它与使用内部函数一样快,并且它会根据您的编译方式自动利用 SSE2-AVX2(AVX2 在 Intel 模拟器上进行测试)。我已经使用适用于 SSE2 到 AVX2 的 vector 类编写了 GEMM 代码,当我在具有 AVX 的系统上运行时,我的代码已经比仅使用 SSE 的 Eigen 更快。这是带有 vector 类的函数(我没有尝试展开循环)。

#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 个更大的 float )如果需要是 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)。 vector 类支持 3 个选项。非 SIMD、AMD 的 LIBM 和英特尔的 SVML(我在上面的代码中使用了非 SIMD 选项)。 SIMD math libraries for SSE and AVX

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

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

关于c++ - 如何提示 OpenMP Stride?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16513709/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com