我有一个 OpenMP 程序(数千行,无法在这里重现),其工作原理如下:
它由工作线程和任务队列组成。
一个任务由一个卷积组成;每次工作线程从工作队列中弹出任务时,它都会执行所需的卷积,并可选择将更多卷积推送到队列中。
(没有特定的“主”线程;所有工作线程都是平等的。)
当我在自己的机器上运行这个程序时(4 核 HT 非 NUMA Core i7 http://ark.intel.com/products/75117),我得到的运行时间是:
(#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核之后性能下降这么多?
我会理解如果性能饱和的在某种程度上(我可以将其归咎于有限的内存带宽),但我不明白它是如何做到的drop通过添加从 1508 毫秒到 5795 毫秒more线程。
这怎么可能?
这类情况可能很难弄清楚。关键是查看内存位置。如果没有看到您的代码,就不可能确切地说出了问题所在,但我们可以讨论一些“多线程不太好”的事情:
在所有 NUMA 系统中,当内存位于处理器 X 且代码在处理器 Y 上运行时(其中 X 和 Y 不是同一处理器),每次内存访问都会影响性能。因此,在正确的 NUMA 节点上分配内存肯定会有所帮助。 (这可能需要一些特殊的代码,例如设置关联掩码并至少向操作系统/运行时系统暗示您想要 Numa 感知的分配)。至少,确保您不只是简单地处理由“第一个线程,然后启动更多线程”分配的一个大数组。
另一件更糟糕的事情是共享或错误共享内存 - 因此,如果两个或更多处理器使用相同的缓存行,您将在这两个处理器之间进行乒乓比赛,其中每个处理器都会执行“我想要内存”在地址A”,获取内存内容,更新它,然后下一个处理器将做同样的事情。
事实上,仅在 12 个线程时结果就变差,这似乎表明这与“套接字”有关 - 要么您正在共享数据,要么数据位于“错误的节点上”。在 12 个线程时,您可能开始使用第二个套接字(更多),这将使此类问题更加明显。
为了获得最佳性能,您需要在本地节点上分配内存,不共享也不锁定。您的第一组结果看起来也并不“理想”。我有一些(绝对非共享)代码,可以使处理器数量精确n倍,直到我用完处理器(不幸的是,我的机器只有4个核心,所以它并没有好多少,但仍然好4倍)比 1 核,如果我拿到了 48 或 64 核机器,它在计算“奇怪的数字”时会产生 48 或 64 更好的结果)。
Edit:
“套接字问题”有两件事:
内存局部性:基本上,内存附加到每个套接字,因此如果内存是从属于“前一个”套接字的区域分配的,那么读取内存会产生额外的延迟。
缓存/共享:在处理器内,存在用于共享数据的“快速”链接(通常是“底层共享缓存”,例如 L3 缓存),这允许套接字内的内核比套接字中的内核更有效地共享数据。一个不同的插座。
所有这些都相当于维修汽车的工作,但你没有自己的工具箱,所以每次你需要工具时,你都必须向旁边的同事要螺丝刀、15毫米扳手或任何你需要的东西。当您的工作区域有点满时,请将工具归还给您。这不是一种非常有效的工作方式...如果您有自己的工具(至少是最常见的工具 - 每月只使用一次的特殊扳手不是一个大问题),那就更好了,但当然是常见的 10、12 和 15 毫米扳手和几把螺丝刀)。当然,如果有四个机械师共享同一个工具箱,情况会变得更糟。在这种情况下,在四套接字系统中“所有内存都分配在一个节点上”。
现在想象一下,你有一个“一盒扳手”,并且只有一个机械师可以使用这盒扳手,所以如果你需要一把 12 毫米的扳手,你必须等待你旁边的家伙使用完 15 毫米的扳手。如果你有“错误的缓存共享”,就会发生这种情况 - 处理器实际上并没有使用相同的值,但因为缓存行中有多个“东西”,所以处理器正在共享缓存行(扳手盒) 。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)