我们刚刚购买了32核Opteron机器,但获得的加速却令人失望:超过24个线程之后,我们根本看不到加速(实际上总体上变慢了),经过6个线程后,它显着地变成了次线性。

我们的应用程序非常线程友好:我们的工作分解为大约170,000个小任务,每个小任务可以分别执行,每个过程需要5到10秒。它们都从大小约为4Gb的同一内存映射文件中读取。他们偶尔会对其进行写入,但每次写入可能会读取10,000次-我们在170,000个任务的每个末端都只写入了一点数据。写入受锁保护。分析表明,锁不是问题。线程在非共享对象中各自使用大量的JVM内存,并且它们对共享的JVM对象的访问非常少,其中只有很少一部分访问涉及写入。

我们在启用NUMA的Linux上用Java编程。我们有128Gb RAM。我们有2个Opteron CPU(型号6274),每个都有16个内核。每个CPU有2个NUMA节点。在Intel四核(即8核)上运行的同一作业几乎线性扩展至8个线程。

我们已尝试将只读数据复制为每个线程一个,以希望大多数查找都可以在NUMA节点本地进行,但是我们发现此操作不会加快速度。

在32个线程中,“top”显示CPU的74%“us”(用户)和大约23%的“id”(idle)。但是没有 sleep ,几乎没有磁盘I/O。使用24个线程,我们可以获得83%的CPU使用率。我不确定如何解释“空闲”状态-这是否意味着“正在等待内存 Controller ”?

我们尝试打开和关闭NUMA(我指的是需要重新引导的Linux级别设置),但没有发现任何区别。启用NUMA时,“numastat”仅显示“分配和访问未命中”的大约5%(95%的缓存未命中是NUMA节点本地的)。 [编辑:]但是,将“-XX:+ useNUMA”添加为java命令行标志可以使我们提高10%。

我们有一种理论是,我们要最大化内存 Controller ,因为我们的应用程序使用大量RAM,并且我们认为有很多高速缓存未命中。

我们怎么办?(a)加速程序以实现线性可伸缩性,或(b)诊断正在发生的事情?

另外:(c)如何解释“最高”结果-“空闲”是否意味着“在存储 Controller 上被阻塞”? (d)Opteron与Xeon的特性有何不同?

最佳答案

我也有一台32核Opteron机器,带有8个NUMA节点(4x6128处理器,Mangy Cours,而不是Bulldozer),并且遇到了类似的问题。

我认为您的问题的答案在顶部显示了2.3%的“sys”时间。以我的经验,这个sys时间是系统在内核中等待锁定所花费的时间。当线程无法获得锁时,它将处于空闲状态,直到进行下一次尝试。 sys和空闲时间都是锁争用的直接结果。您说您的探查器未显示锁定是问题所在。我的猜测是,由于某种原因,导致问题锁的代码未包含在配置文件结果中。

就我而言,锁争用的一个重要原因不是我实际执行的处理,而是将工作分配给每个线程的工作调度程序。该代码使用锁来跟踪哪个线程正在执行哪个工作。我对这个问题的解决方案是重写我的工作计划程序,以避免互斥体,我已经读过它不能扩展到超过8-12个核,而使用gcc内置原子(我在Linux上用C编程)。原子操作实际上是一种非常细粒度的锁,可以在高内核数的情况下更好地扩展。在您的情况下,如果您的工作包裹确实确实需要5到10秒钟,这似乎对您来说就不那么重要了。

我还遇到了malloc的问题,在高内核数情况下,malloc遇到了可怕的锁定问题,但是我无法记住,这是否还会导致sys和idle数字出现,或者它是否刚刚出现使用Mike Dunlavey的调试器性能分析方法(How can I profile C++ code running in Linux?)。我怀疑它确实会导致系统和空闲问题,但是我在研究所有旧注释时发现了一条线:)我确实知道我现在尽可能避免运行时malloc。

我最好的猜测是,您正在使用的某些库代码在您不知情的情况下实现了锁,没有包含在性能分析结果中,并且无法很好地扩展到高内核数的情况。当心内存分配器!

关于parallel-processing - 多核CPU的: Programming techniques to avoid disappointing scalability,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13465425/

10-16 02:17