【问题标题】:C OpenMP - Reduction scalabilityC OpenMP - 减少可扩展性
【发布时间】:2015-08-18 01:56:15
【问题描述】:

我正在测试一些算法在使用 OpenMP 时的性能加速,其中之一是无法缩放。我做错了吗?

电脑详情:

  • 内存: 7.7 GiB
  • 处理器: Intel® Core™ i7-4770 CPU @ 3.40GHz × 8
  • 操作系统: Ubuntu 15.04 64 位
  • gcc: gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>

int main(int argc, char **argv) {
  int test_size, i;
  double *vector, mean, stddeviation, start_time, duration;

  if (argc != 2) {
    printf("Usage: %s <test_size>\n", argv[0]);
    return 1;
  }

  srand((int) omp_get_wtime());

  test_size = atoi(argv[1]);
  printf("Test Size: %d\n", test_size);

  vector = (double *) malloc(test_size * sizeof(double));
  for (i = 0; i < test_size; i++) {
    vector[i] = rand();
  }

  start_time = omp_get_wtime();
  mean = 0;
  stddeviation = 0;
#pragma omp parallel default(shared) private(i)
  {
#pragma omp for reduction(+:mean)
    for (i = 0; i < test_size; i++) {
      mean += vector[i];
    }
#pragma omp single
    mean /= test_size;

#pragma omp for reduction(+:stddeviation)
    for (i = 0; i < test_size; i++) {
      stddeviation += (vector[i] - mean)*(vector[i] - mean);
    }
  }
  stddeviation = sqrt(stddeviation / test_size);
  duration = omp_get_wtime() - start_time;

  printf("Std. Deviation = %lf\n", stddeviation);
  printf("Duration: %fms\n", duration*1000);

  return 0;
}

编译行

gcc -c -o main.o main.c -fopenmp -lm -O3
gcc -o dp main.o -fopenmp -lm -O3

结果

$ OMP_NUM_THREADS=1 ./dp 100000000
166.224199ms

$ OMP_NUM_THREADS=2 ./dp 100000000
157.924034ms

$ OMP_NUM_THREADS=4 ./dp 100000000
159.056189ms

【问题讨论】:

  • 是的,我想到了这个,然后我用 Go 重写了这段代码,得到了 167ms、84ms 和 31ms……你不认为 C 代码至少应该等于 Go 时间吗?
  • 基准测试是对大量数据进行单次传递,并且几乎不做任何工作。它可能完全受内存限制。
  • @Mysticial,我同意它受内存带宽限制,但这并不意味着它不应该从使用多个线程 stackoverflow.com/questions/25179738/… 中看到一些显着的好处。所以我有点惊讶 OP 基本上没有缩放。但我现在没有时间考虑这个。
  • 我无法重现您的结果。在 Ubuntu 15.04(和你一样)上用 gcc 4.8(和你一样)编译你的代码,取决于 CPU,2 个线程的加速在 1.13 到 1.83 之间——这大约是你对内存受限的期望像你这样的程序(循环展开和用纯内存访问替换浮点操作等实验证实它实际上是受内存限制的)。你 1.05 的加速似乎太低了,特别是考虑到我在与你最相似的系统上获得了最高加速。
  • 您是否确认您获得了请求的线程数?你在做OMP_NUM_THREADS=1 ./dp 100000000吗?还是你这样做是分开的?如果第二种情况你需要export OMP_NUM_THREADS=1 ./dp 100000000.

标签: c openmp


【解决方案1】:

我不会在 Ubuntu 14.04.2 LTS、gcc 4.8 和 2.3 GHz Intel Core i7 上重现您的结果。以下是我得到的结果:

$ OMP_NUM_THREADS=1 ./so30627170 100000000 测试规模:100000000 标准。偏差 = 619920018.463329 持续时间:206.301721ms $ OMP_NUM_THREADS=2 ./so30627170 100000000 测试规模:100000000 标准。偏差 = 619901821.463117 持续时间:110.381279ms $ OMP_NUM_THREADS=4 ./so30627170 100000000 测试规模:100000000 标准。偏差 = 619883614.594906 持续时间:78.241708ms

由于您问题的“结果”部分中列出的输出与所列代码的输出不匹配,您可能正在运行旧版本的代码。

我考虑过可能在并行 for 循环中使用 X86 内在函数,但检查汇编输出时,gcc 在这种情况下已经使用 SIMD 指令。没有行进选项,我看到 gcc 使用 SSE2 指令。使用-march=native-mavx 编译,gcc 将使用 AVX 指令。

编辑:运行你的程序的 Go 版本,我得到:

$ ./tcc-go-desvio-padrao -w 1 -n 15 -t 100000000 2015/06/07 08:26:43 工人:1 2015/06/07 08:26:43 测试:[100000000] 2015/06/07 08:26:43 每个测试的执行次数:15 2015/06/07 08:26:43 分配内存的时间:584.477µs 2015/06/07 08:26:43 ========================================= === 2015/06/07 08:26:43 当前测试规模:100000000 2015/06/07 08:27:05 填充数组的时间:1.322556083s 2015/06/07 08:27:05 计算时间:194.10728ms $ ./tcc-go-desvio-padrao -w 2 -n 15 -t 100000000 2015/06/07 08:27:10 工人:2 2015/06/07 08:27:10 测试:[100000000] 2015/06/07 08:27:10 每个测试的执行次数:15 2015/06/07 08:27:10 分配内存的时间:565.273µs 2015/06/07 08:27:10 ========================================= === 2015/06/07 08:27:10 当前测试规模:100000000 2015/06/07 08:27:22 填充数组的时间:677.755324ms 2015/06/07 08:27:22 计算时间:113.095753ms $ ./tcc-go-desvio-padrao -w 4 -n 15 -t 100000000 2015/06/07 08:27:28 工人:4 2015/06/07 08:27:28 测试:[100000000] 2015/06/07 08:27:28 每个测试的执行次数:15 2015/06/07 08:27:28 分配内存的时间:576.568µs 2015/06/07 08:27:28 ======================================== === 2015/06/07 08:27:28 当前测试规模:100000000 2015/06/07 08:27:34 填充数组的时间:353.646193ms 2015/06/07 08:27:34 计算时间:79.86221ms

时间显示与 OpenMP 版本大致相同。

【讨论】:

  • 感谢您的回答。在我的结果部分,我刚刚删除了不必要的内容以直接进入重点。我已经在我大学的机器上测试了代码,这与我的非常相似,并且得到了相同的结果。我在想,由于我的 CPU 已经非常快,并行化的开销可能会超过好处。这有意义吗?
  • @DiogoDoreto:我想可能是这样。不过,我想知道为什么该程序在用 Go 重写时表现出性能改进。你介意发布你的程序的 Go 版本吗?另外,你的记忆速度是多少?我正在使用两个 8 GiB DDR3 内存条 @ 1600 MHz。
  • 我有 1 个 8192MB @ 1600MHz。你可以在这里看到 Go 代码的相关部分:bitbucket.org/DiogoDoreto/tcc-go-desvio-padr-o/src/…
  • 嗨@DiogoDoreto。我已经用运行你的 Go 版本的时间更新了我的答案。我得到的时间与 OpenMP 版本大致相同。
  • 感谢您尝试帮助并在您身边运行代码。但我期望的答案是解释为什么会发生这种情况,因为我能够在其他系统上重现这种行为。
猜你喜欢
  • 2011-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-22
  • 2013-12-23
  • 2017-01-16
  • 1970-01-01
相关资源
最近更新 更多