【发布时间】:2014-03-11 14:19:58
【问题描述】:
我有一个 OpenMP 程序(数千行,无法在此处重现),其工作方式如下:
它由工作线程和任务队列组成。
一个任务由一个卷积组成;每次工作线程从工作队列中弹出任务时,它都会执行所需的卷积,并可选择将更多卷积推入队列。
(没有特定的“主”线程;所有工作人员都是平等的。)
当我在自己的机器(4-core HT non-NUMA Core i7)上运行这个程序时,我得到的运行时间是:
(#threads: running time)
1: 5374 ms
2: 2830 ms
3: 2147 ms
4: 1723 ms
5: 1379 ms
6: 1281 ms
7: 1217 ms
8: 1179 ms
这是有道理的。
但是,当我在 NUMA 48 核 AMD Opteron 6168 机器上运行它时,我得到了以下运行时间:
1: 9252 ms
2: 5101 ms
3: 3651 ms
4: 2821 ms
5: 2364 ms
6: 2062 ms
7: 1954 ms
8: 1725 ms
9: 1564 ms
10: 1513 ms
11: 1508 ms
12: 1796 ms <------ why did it get worse?
13: 1718 ms
14: 1765 ms
15: 2799 ms <------ why did it get *so much* worse?
16: 2189 ms
17: 3661 ms
18: 3967 ms
19: 4415 ms
20: 3089 ms
21: 5102 ms
22: 3761 ms
23: 5795 ms
24: 4202 ms
这些结果非常一致,这不是机器负载造成的。
所以我不明白:
什么会导致 12 核后性能下降这么多?
我会理解性能是否在某种程度上饱和(我可以将其归咎于有限的内存带宽),但我不明白它如何从 1508下降通过添加 更多 个线程将 ms 增加到 5795 ms。
这怎么可能?
【问题讨论】:
-
我首先要检查的是任务队列的争用情况。但是很多事情都会弄乱并行程序,你可能需要打开一个并行分析器,比如 Tau 或 Scalasca。
-
@RamanShah:但是,竞争是否会突然/戏剧性地增加时间?
-
Hmya,这就是 NUMA 中的“NU”的意思。一旦您越过了最佳位置,您就可以看到处理器互连的成本。将它们视为通过网络连接的独立机器非常重要。不要让他们解决同样的问题。
-
@HansPassant:我明白了。不幸的是,我看不出如何阻止它们解决相同的问题,因为卷积具有任意的相互依赖性(想想 DAG),因此缓冲区必须共享并可供所有线程使用。我无法在“正确”节点上分配内存,因为一旦我这样做并且不同的节点需要读取数据,它将位于错误的节点上(存在相互依赖的 DAG)。那我可以在这里做什么?
-
好吧,在这一点上,您正在进入一个必须付费(在代码行数、复杂性和可移植性方面)以扩展性能的世界。它可能涉及诸如主进程之类的东西,该进程分解您的 DAG 依赖项,以将正确的数据以最小的串扰获取到地址空间的正确部分。
标签: c++ multithreading performance parallel-processing