什么限制了这个简单的OpenMP程序的扩展?

Dou*_*ple 5 c performance multithreading openmp smp

我试图了解48核系统上的并行化限制(4xAMD Opteron 6348,2.8 Ghz,每个CPU 12个核心).我写了这个微小的OpenMP代码来测试加速,我认为这是最好的情况(任务是令人尴尬的并行):

// Compile with: gcc scaling.c -std=c99 -fopenmp -O3                                                                                               

#include <stdio.h>
#include <stdint.h>

int main(){

  const uint64_t umin=1;
  const uint64_t umax=10000000000LL;
  double sum=0.;
#pragma omp parallel for reduction(+:sum)
  for(uint64_t u=umin; u<umax; u++)
    sum+=1./u/u;
  printf("%e\n", sum);

}
Run Code Online (Sandbox Code Playgroud)

我惊讶地发现缩放是高度非线性的.使用48个线程运行代码需要大约2.9s,使用36个线程运行3.1s,使用24个线程运行3.7s,使用12个线程运行4.9s,使用1个线程运行代码需要57s.

不幸的是,我不得不说计算机上运行一个进程使用100%的一个核心,因此可能会影响它.这不是我的过程,所以我无法结束它来测试差异,但不知何故我怀疑这是在19到20倍的加速和理想的48倍加速之间产生差异.

为了确保它不是OpenMP问题,我同时运行了两个程序副本,每个程序有24个线程(一个用umin = 1,umax = 5000000000,另一个用umin = 5000000000,umax = 10000000000).在这种情况下,程序的两个副本在2.9s之后完成,因此它与使用单个程序实例运行48个线程完全相同.

什么阻止了这个简单程序的线性缩放?

Dou*_*ple 2

我终于有机会在完全卸载的系统上对代码进行基准测试: 在此输入图像描述

对于我使用的动态时间表schedule(dynamic,1000000)。对于静态计划,我使用默认值(在核心之间均匀分配)。对于线装订,我使用了export GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47".

此代码高度非线性缩放的主要原因是 AMD 所谓的“核心”实际上并不是独立核心。这是 redrum 答案的第 (1) 部分。从上图中 24 个线程的加速突然达到稳定状态可以清楚地看出这一点;通过动态调度,这一点非常明显。从我选择的线程绑定中也可以明显看出:事实证明我上面写的内容对于绑定来说是一个糟糕的选择,因为最终每个“模块”中有两个线程。

第二大减慢来自于具有大量线程的静态调度。最慢和最快的线程之间不可避免地存在不平衡,当使用默认的静态调度将迭代划分为大块时,会在运行时间中引入较大的波动。这部分答案来自 Hristo 的评论和 Salt 的回答。

我不知道为什么“Turbo Boost”的效果不那么明显(Redrum 答案的第二部分)。另外,我不能 100% 确定扩展的最后一点在哪里(大概是在开销中)丢失了(我们从模块数量的线性扩展中获得了 22 倍的性能,而不是预期的 24 倍)。但除此之外,这个问题已经得到了很好的回答。