【发布时间】:2021-08-28 10:15:39
【问题描述】:
我有一个可重复性最低的样本,如下所示 -
#include <iostream>
#include <chrono>
#include <immintrin.h>
#include <vector>
#include <numeric>
template<typename type>
void AddMatrixOpenMP(type* matA, type* matB, type* result, size_t size){
for(size_t i=0; i < size * size; i++){
result[i] = matA[i] + matB[i];
}
}
int main(){
size_t size = 8192;
//std::cout<<sizeof(double) * 8<<std::endl;
auto matA = (float*) aligned_alloc(sizeof(float), size * size * sizeof(float));
auto matB = (float*) aligned_alloc(sizeof(float), size * size * sizeof(float));
auto result = (float*) aligned_alloc(sizeof(float), size * size * sizeof(float));
for(int i = 0; i < size * size; i++){
*(matA + i) = i;
*(matB + i) = i;
}
auto start = std::chrono::high_resolution_clock::now();
for(int j=0; j<500; j++){
AddMatrixOpenMP<float>(matA, matB, result, size);
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
std::cout<<"Average Time is = "<<duration/500<<std::endl;
std::cout<<*(result + 100)<<" "<<*(result + 1343)<<std::endl;
}
我进行如下实验 - 我使用 #pragma omp for simd 指令为 AddMatrixOpenMP 函数中的循环计时代码,然后在没有指令的情况下对其计时。我编译代码如下 -
g++ -O3 -fopenmp example.cpp
在检查程序集时,两种变体都会生成向量指令,但当明确指定 OpenMP pragma 时,代码运行速度会慢 3 倍。
我不明白为什么会这样。
编辑 - 我正在运行 GCC 9.3 和 OpenMP 4.5。这是在 Ubuntu 20.04 上的 i7 9750h 6C/12T 上运行的。我确保没有主要进程在后台运行。在两个版本的运行期间,CPU 频率或多或少保持不变(从 4.0 到 4.1 的微小变化)
TIA
【问题讨论】:
-
如果将
#pragma omp for simd替换为#pragma omp parallel for会发生什么? -
@Brannon:请注意,
gcc -O2 -fopenmp默认情况下不进行自动矢量化,仅用于使用omp simd的循环。但是gcc -O3启用了-ftree-vectorize,它试图向量化任何/所有循环。但是,对于这个简单的纯垂直 SIMD 循环,我预计 OpenMP 向量化器的性能至少与普通向量化器算法一样好。不明白什么可以解释慢 3 倍。 -
感谢您回复@jjramsey,使用#pragma parallel 确实可以并行化到我所有的12 个线程。有趣的是你买了它,我记得使用
#pragma omp parallel for simd,它比 simd 花费了更多时间,尽管我认为这可以归因于线程过载 -
您在什么硬件上进行了测试? (以及什么操作系统,以防万一)?我假设您控制了 CPU 频率等“热身”效果?您在第一次通过之前不要触摸
results,因此它会在定时区域内遭受页面错误,但这对于两个版本应该是相同的,除非您添加另一个定时区域以重用同一程序中的数据。 (如果你这样做了,请参阅Idiomatic way of performance evaluation?) -
我打算测试它,但它无法编译。您似乎从minimal reproducible example 中遗漏了
#includes。修复该问题并添加缺少的#pragma omp simd,是的,在 i7-6700k Skylake(3.9GHz 和 DDR4-2666)上使用 GCC 10.2 -O3(没有-march=native或-fopenmp),我得到 18266,但使用-O3 -fopenmp我得到平均时间 39772。
标签: c++ gcc openmp vectorization simd