【发布时间】:2018-09-16 19:10:49
【问题描述】:
我只是更仔细地研究 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 来实现呢?
感谢您的帮助! :)
【问题讨论】:
-
FP 数学不是关联的。如果没有
-ffast-math或允许它们以不同顺序求和的 OpenMP pragma,编译器无法自动矢量化 FP 缩减。 -
x86 具有对 SIMD sqrt 的硬件支持。
sqrtpd在大多数 CPU 上的吞吐量与sqrtsd一样好,但并行处理 2 个double平方根。 agner.org/optimize. -
过去,gcc 在 omp 并行 simd 的情况下会忽略 simd,因此可以合理地说并行禁用矢量化(至少在需要 simd 的地方)。上面的帖子暗示这在 gcc 7.1 中发生了变化。即使使用 icc,我的经验是需要显式嵌套循环来完成并行 simd。
标签: c++ openmp vectorization simd