【问题标题】:False sharing in OpenMP loop array accessOpenMP 循环阵列访问中的虚假共享
【发布时间】:2017-07-11 10:56:52
【问题描述】:

我想利用 OpenMP 使我的任务并行化。

我需要对数组的所有元素减去相同的数量,然后将结果写入另一个向量。两个数组都使用malloc 动态分配,第一个数组由文件中的值填充。每个元素的类型为uint64_t

#pragma omp parallel for
for (uint64_t i = 0; i < size; ++i) {
    new_vec[i] = vec[i] - shift;
}

其中shift 是我想从vec 的每个元素中删除的固定值。 sizevecnew_vec 的长度,大约是 200k。

我在 Arch Linux 上使用 g++ -fopenmp 编译代码。我在 Intel Core i7-6700HQ 上,我使用 8 个线程。当我使用 OpenMP 版本时,运行时间要高 5 到 6 倍。当我运行 OpenMP 版本时,我可以看到所有内核都在工作。

我认为这可能是由虚假共享问题引起的,但我找不到。

【问题讨论】:

  • 您的内存带宽有限,因为您尝试进行并行计算很简单,基本上只是在内存位置之间移动数据。添加线程将导致内存缓存未命中/抖动和预取失败。这样做的效果是代码运行速度较慢。现代 PC 上的内存总线大约有 1.5 个线程。
  • @RichardCritten 这不是真的。高端处理器具有设计的带宽上限,因此您需要使用多线程来使它们饱和。查看我的答案中的链接。
  • 如何衡量执行时间?
  • @HristoIliev 我使用perf stat -r200 来平均执行时间
  • 您能生成一个minimal reproducible example 吗?循环的绝对执行时间是多少秒?这是代码中唯一的 OpenMP 区域吗?它在单个程序运行中执行多少次?这可能是 OpenMP 开销。

标签: c++ c performance openmp false-sharing


【解决方案1】:

您应该调整迭代在线程之间的拆分方式。使用schedule(static,chunk_size),您可以这样做。

尽量使用64/sizeof(uint64_t)的倍数的chunk_size值来避免上述错误共享:

[ cache line n   ][ cache line n+1 ]
[ chuhk 0  ][ chunk 1  ][ chunk 2  ]

并实现这样的目标:

[ cache line n   ][ cache line n+1 ][ cache line n+2 ][...]
[ chunk 0                          ][ chunk 1             ]

您还应该以与缓存行对齐的方式分配向量。这样可以确保第一个块和后续块也正确对齐。

#define CACHE_LINE_SIZE sysconf(_SC_LEVEL1_DCACHE_LINESIZE) 
uint64_t *vec = aligned_alloc( CACHE_LINE_SIZE/*alignment*/, 200000 * sizeof(uint64_t)/*size*/);

您的问题与Stream Triad benchmark 所代表的问题非常相似。查看how to optimize that benchmark,您将能够几乎准确地映射代码上的优化。

【讨论】:

  • 除其他外,对 Stream 的深入讨论包括线程数量的选择及其在内核中的分布。每个内核的多个线程几乎肯定会减慢它的速度。设置 omp 并行时是否保持 simd 矢量化?
  • 您可以使用omp for simd 请求多线程和矢量化,这是您正在使用的和omp simd 的组合。检查reference for omp simd。编译器可以在没有任何提示的情况下对其进行矢量化,但鉴于您可以指定它,最好也放置该子句。
  • GCC 的默认循环调度是 static,因此在 ~25000 条缓存线中恰好有 7 条缓存线可以在线程之间共享,并且最多 8 次迭代,每次 ~25000 条中有错误共享线。问题很可能是使用clock()来测量Linux上的执行时间,这里有无数类似的问题。
  • 除了保持 simd 矢量化之外,为了获得高效的多线程执行,使用非临时存储也很重要。正如 Hristo 所说,如果你把所有线程的时间加起来,你肯定会看到它随着线程数的增加而增加。
猜你喜欢
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
  • 2019-03-07
  • 2012-01-10
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多