我有这个简单的代码来测试分配了更多内核的加速次数,但是我没有观察到线性加速。
int main() {
using u64_t = unsigned long long;
u64_t n = 1e9;
u64_t* a = new u64_t[n];
#pragma omp parallel for
for (u64_t i=0; i<n; ++i) {
a[i] = i;
}
}
编译成'g++ -fopenmp -O3 test.cpp
',然后
export OMP_NUM_THREADS=1 # time cost = 4.485s
export OMP_NUM_THREADS=2 # time cost = 2.916s
export OMP_NUM_THREADS=3 # time cost = 2.571s
export OMP_NUM_THREADS=4 # time cost = 2.347s
为什么没有线性加速?
更新
系统环境如下
此外,htop
给了我 4 个线程,我怀疑如果启用了超线程,可能只有 2 个物理内核。
我使用 time ./a.out
测量速度,使用 gnu g++-7
编译。
跟进
现在我稍微改了一下代码,如下
int main() {
using u64_t = unsigned long long;
u64_t n = 1e9;
u64_t a[7];
#pragma omp parallel for
for (u64_t i=0; i<n; ++i) {
a[i%7] = i; // a is an array, I know there might be data race here
}
cout << a[0] << "," << a[6];
}
我测试了上面的代码,但是现在omp
版本(2.1s)比串行版本(1.2s)慢,为什么?
最佳答案
此代码主要受内存带宽的限制,因为您为每个操作写入一个值。通常,内存带宽小于所有内核并行使用的带宽。
对内存饱和度进行数学计算有点偏离规范。 你的系统可能有一个 i5-5257U在这种配置下,它应该有 25.6 GB/s 的内存带宽。您只能写入 3.4 GB/s - 对于写入,您实际上经常使用两倍,因为每次写入都首先需要从内存中读取缓存行。所以在 6.8 GB/s 和理论带宽之间还有很大的进步,但这并非闻所未闻。我无法重现这个,因为我没有相同的硬件。要进行更详细的分析,必须深入研究生成的指令和硬件性能计数器。
一些补充说明:
- 我听说 apple 有时会将
gcc
别名化为clang
,这可能会产生误导。 - 您应该在循环之后对
a
做一些事情,以防止编译器优化它。 - 您的时间测量包括应用非并行设置和
新...
,因此您受到严重影响Amdal's law .考虑使用omp_get_wtime()
仅对并行部分进行计时。
总而言之,您的处理器只有两个内核(四个硬件线程),无论如何您都不应该期望超过两个线程的加速。
关于c++ - OpenMP 线性加速,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49607021/