【问题标题】:OpenMP: How to improve the efficiency by parallelism?OpenMP:如何通过并行提高效率?
【发布时间】:2021-10-24 17:30:36
【问题描述】:

我想使用 OpenMP 并行执行以下 C++ 循环以提高效率。 (array2d 中每个元素的值可以是 0 或 1 或 2。array2d 的值对效率并不重要,所以我只是从 0、1 和 2 中随机设置每个值。count 中的值是初始化为 0。)

int array2d[100][10000];
int count[3][3][3];

//omp_set_num_threads(2);
//#pragma omp parallel for
for (int i = 0; i < 10000; ++i) {
    int x = array2d[10][i];
    int y = array2d[40][i];
    int z = array2d[78][I];
//#pragma omp atomic
    count[z][x][y]++;
}

但如果我使用 2、4 或 8 个线程来并行循环 #pragma omp parallel for,我将无法获得改进。并行版本的执行时间大于顺序版本。我很好奇这个循环是否可以通过 OpenMP 并行性来改进?如果是,我怎样才能缩短执行时间?

【问题讨论】:

  • 迭代次数非常少,而且每次迭代中的工作量都非常小,以获得任何合理的并行加速。通常,您至少需要一些适度的工作来分摊与线程相关的开销(例如创建线程)。
  • 此外,count 数组元素的原子增量可能会导致严重的缓存争用,这会使事情变得更糟。在您的情况下,几乎可以保证,因为这个数组非常小——它只占用两三个缓存行。最好为每个线程创建 count 的线程本地副本,并在最后 reduce 它们。

标签: c++ performance parallel-processing openmp


【解决方案1】:

如果您关心的是效率,那么在尝试 OMP 之前还有其他事情要做。

您的代码对缓存不友好:100 ints 的行是 400 字节,而缓存行只有 64。由于值限制为 0..2,单字节 (uint8_t) 将工作得更好。我什至会将其中的四个打包到每个字节中。

【讨论】:

    【解决方案2】:

    有 3 种影响会导致您的代码并行变慢(但我不知道在您的情况下哪一种最不重要):

    1. 此代码受内存限制,取决于您的硬件使用更多线程可能无法提高内存访问速度,因此整体速度不会提高。

    2. 正如@Daniel 所说,工作负载非常小,因此与工作负载相比并行开销很大,因此会增加运行时间。

    3. 正如@Daniel count 所强调的,数组很小,它只有 27 个元素。其元素的不断增加会导致错误共享,这可能会显着降低效率。您可以使用归约来更改它(注意,在这种情况下您不需要原子操作,因此删除该行):

    #pragma omp parallel for reduction(+:count[:3][:3][:3])

    如果速度不会提高,很遗憾这段代码不值得在您的硬件上并行化。尝试并行化程序的更大部分。

    【讨论】:

    • 谢谢拉奇。我想知道如何通过计算一些指标或仅仅通过一些简单的判断来确定这段代码是否受内存限制?
    • 分析您的程序(例如,使用英特尔的 VTune。)它将为您提供大量信息。
    猜你喜欢
    • 2016-01-22
    • 1970-01-01
    • 2012-06-27
    • 1970-01-01
    • 2017-03-05
    • 2019-04-27
    • 1970-01-01
    • 2017-04-03
    • 2013-07-03
    相关资源
    最近更新 更多