使用openMP simd进行以下循环是否安全?

时间:2018-04-06 17:29:04

标签: c++ openmp vectorization simd

我只是更仔细地研究OpenMP simd构造,并且有三个循环看起来似乎没有被gcc(简短的性能测试)矢量化,但我认为他们可以。所以我想知道,添加simd pragma是否安全以及为什么gcc没有对它们进行矢量化。

首先是矩阵乘法,其值存储为单个数组:

#pragma omp parallel for
    for(size_t row = 0; row < 100; ++row){
    {#pragma omp simd}
        for(size_t col = 0; col < 100; ++col){              
            float sum = c[row * 100 + col];
            for(size_t k = 0; k < 100; k++){
                sum += a[rows * 100 + k] * b[k * 100 + col];
            }
            c[row * 100 + col] = sum;
        }

我知道b没有转置,这会影响性能。通过添加simd pragma,代码变得更快。由于内循环,自动矢量化是不可能的吗?

对于第二个例子,我正在尝试OpenMP的自定义缩减声明功能,这实际上并不需要。

#pragma omp declare reduction(sum : double : omp_out += omp_in) initializer(omp_priv = omp_orig)
double red_result = 0;
#pragma omp parallel for {simd} reduction(sum:red_result)
    for(size_t i = 0; i < 100; ++i){            
        red_result = red_result + a[i];
    }

减少会阻止矢量化吗?因为我认为它应该可以正常工作?

最后一个例子是一个复杂的循环,带有另一个内部循环和函数调用。简化它看起来像这样:

#pragma omp parallel for {simd}
for(size_t i = 0; i < 100; ++i){
  [..]
  for(size_t j = 0; j < 100; j++){
    if(j != i){
      float k2 = a[i] - b[j];
       k = std::sqrt(k2);           
    }
  }
  [do more with k]
}

所以这里的问题可能是sqrt调用,无法进行矢量化?但是,如果使用simd pragma,性能会更好吗?一些简短的测试表明情况就是这样,但是如果由于std :: sqrt而无法实现自动矢量化,为什么pragma可以实现?

感谢您的帮助! :)

1 个答案:

答案 0 :(得分:3)

对于math.h中的数学函数,编译器需要实现数学函数的矢量化版本。 GCC使用libmvec执行此操作,ICC使用SVML执行此操作。据我所知,Clang对矢量化数学函数没有原生支持。

让我们考虑以下代码:

void foo(float * __restrict a, float * __restrict b) {    
    a = (float*)__builtin_assume_aligned(a, 16);
    b = (float*)__builtin_assume_aligned(b, 16);          
    for(int i = 0; i < 100; ++i) {
        b[i] = sqrtf(a[i]);
    }
}

void foo2(float * __restrict a, float * __restrict b) {    
    a = (float*)__builtin_assume_aligned(a, 16);
    b = (float*)__builtin_assume_aligned(b, 16);          
    for(int i = 0; i < 100; ++i) {
        b[i] = sinf(a[i]);
    }
}

GCC,ICC和Clang vectorize sqrtf(使用牛顿方法的一次迭代)。 GCC和ICC分别使用libmvec(sinf)和SVML(_ZGVbN4v_sinf)向量__svml_sinf4。 Clang没有矢量化sinf。见godboltsqrt是一种特殊情况(因为x86指令集具有向量化的sqrt指令),可以在没有向量化数学库的情况下进行内联。