错误共享多个核心

时间:2018-10-02 16:05:44

标签: c++ parallel-processing openmp cpu-cache false-sharing

以下程序中会发生虚假共享吗?

内存

  • 将1个数组分为4个相等的区域:[A1, A2, B1, B2]
  • 整个数组可以放入实际程序的L1缓存中。
  • 每个区域被填充为64字节的倍数。

步骤

1. thread 1 write to region A1 and A2 while thread 2 write to region B1 and B2.
2. barrier
3. thread 1 read B1 and write to A1 while thread 2 read B2 and write to A2.
4. barrier
5. Go to step 1.

测试

#include <vector>
#include <iostream>
#include <stdint.h>
int main() {
    int N = 64;
    std::vector<std::int32_t> x(N, 0);
    #pragma omp parallel
    {
        for (int i = 0; i < 1000; ++i) {
            #pragma omp for
            for (int j = 0; j < 2; ++j) {
                for (int k = 0; k < (N / 2); ++k) {
                    x[j*N/2 + k] += 1;
                }
            }
            #pragma omp for
            for (int j = 0; j < 2; ++j) {
                for (int k = 0; k < (N/4); ++k) {
                    x[j*N/4 + k] += x[N/2 + j*N/4 + k] - 1;
                }
            }
        }
    }
    for (auto i : x ) std::cout << i << " ";
    std::cout << "\n";
}

结果

32 elements of 500500 (1000 * 1001 / 2)
32 elements of 1000

1 个答案:

答案 0 :(得分:3)

由于无法保证x与缓存行对齐,因此代码中存在一些错误共享。填充不一定足够。在您的示例中,N很小,可能是一个问题。请注意,在您的示例N中,最大的开销可能是工作共享和线程管理。如果N足够大,即array-size / number-of-threads >> cache-line-size,则错误的共享就不成问题了。

就缓存使用而言,交替从代码中的不同线程对A2进行写操作也不是最佳方法,但这不是一个错误的共享问题。

注意,您不需要拆分循环。如果您在一个循环中连续访问索引到内存,那么一个循环就好了,例如

#pragma omp for
for (int j = 0; j < N; ++j)
    x[j] += 1;

如果您非常小心,可以添加schedule(static),则可以保证单词分布均匀。

请记住,错误共享是性能问题,而不是正确性问题,并且仅在频繁发生时才相关。典型的错误模式是写入vector[my_thread_index]