我有这个简单的代码测试分配了更多内核的加速次数,但是我没有观察到线性加速。
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)慢,为什么?
答案 0 :(得分:2)
此代码主要受内存带宽限制,因为每个操作写入一个值。通常,所有内核并行使用的内存带宽较少。
对内存饱和度进行数学计算有点偏离规范。 您的系统可能有i5-5257U,在该配置中,它应具有25.6 GB / s的内存带宽。你只能写3.4 GB / s - 对于写入,你经常使用两次,因为每次写入首先需要从内存中读取缓存行。因此,在6.8 GB / s和理论带宽之间仍然有很大的进展,但这并非闻所未闻。我无法重现这一点,因为我没有相同的硬件。要进行更详细的分析,必须深入研究生成的指令和硬件性能计数器。
更多评论:
gcc
与clang
混淆,这可能会产生误导。a
做一些事情,以防止编译器对其进行优化。new ...
,因此您受到严重影响Amdal's law。考虑仅使用omp_get_wtime()
计算并行部分。所有这一切,你的处理器只有两个核心(四个线程),你不应该期望超过两个线程的加速。