使用OpenMP进行线性加速

时间:2018-04-02 07:25:00

标签: c++ openmp

我有这个简单的代码测试分配了更多内核的加速次数,但是我没有观察到线性加速。

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

为什么没有线性加速?

更新

系统环境如下

enter image description here

另外,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)慢,为什么?

1 个答案:

答案 0 :(得分:2)

此代码主要受内存带宽限制,因为每个操作写入一个值。通常,所有内核并行使用的内存带宽较少。

对内存饱和度进行数学计算有点偏离规范。 您的系统可能有i5-5257U,在该配置中,它应具有25.6 GB / s的内存带宽。你只能写3.4 GB / s - 对于写入,你经常使用两次,因为每次写入首先需要从内存中读取缓存行。因此,在6.8 GB / s和理论带宽之间仍然有很大的进展,但这并非闻所未闻。我无法重现这一点,因为我没有相同的硬件。要进行更详细的分析,必须深入研究生成的指令和硬件性能计数器。

更多评论:

  • 我听说苹果有时会gccclang混淆,这可能会产生误导。
  • 你应该在循环之后对a做一些事情,以防止编译器对其进行优化。
  • 您的时间测量包括应用非并行设置和new ...,因此您受到严重影响Amdal's law。考虑仅使用omp_get_wtime()计算并行部分。

所有这一切,你的处理器只有两个核心(四个线程),你不应该期望超过两个线程的加速。