作为数据评估程序的一部分,我在我的 MacBook Pro M1 Pro(10 核,32 GB RAM)上使用 Python 3.10.5 中的多个进程执行了 1'000'000 次蒙特卡罗模拟 ( concurrent. futures.ProcessPoolExecutor)
。执行时间为:
Apple MacBook Pro, M1 Pro 10 Core CPU
macOS Monterey 12.6.2
Python 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:07:06) [Clang 13.0.1 ] on darwin
without setting CPU affinity, single run
Cores Simulations Execution Time
10 1000 00:00:03.114602
10 10000 00:00:16.658438
10 100000 00:02:39.969048
10 1000000 00:26:23.064365
为了减少计算时间并减少主机的工作量,我决定在一台较旧的 Dual Xeon E5-2687Wv4 工作站上使用 20 个核心(停用超线程)执行计算:
DELL Precision T7810, 2x Xeon E5-2687W v4
Ubuntu 22.04.3 LTS
Python 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:06:46) [GCC 10.3.0] on linux
without setting CPU affinity, single run
Cores Simulations Execution Time
20 1000 00:00:03.913254
20 10000 00:00:16.684702
20 100000 00:02:31.481626
20 1000000 00:27:44.841615
根据上述数字,我没有看到任何明显的性能提升。但是,仅使用 24 个可用核心中的 20 个可能会产生一些开销,因为调度程序往往会切换处理器核心。为了调查这种潜在影响,我手动设置了每个进程的 CPU 亲和性并得到了以下结果:
DELL Precision T7810, 2x Xeon E5-2687W v4
Ubuntu 22.04.3 LTS
Python 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:06:46) [GCC 10.3.0] on linux
with setting CPU affinity, single run
Cores Simulations Execution Time
20 1000 00:00:03.855061
20 10000 00:00:17.721105
20 100000 00:02:39.870485
20 1000000 00:26:22.462597
同样,性能上没有明显差异。为了确保代码总体上可扩展,我在工作站上测试了 10、16 和 20 个核心的执行情况:
DELL Precision T7810, 2x Xeon E5-2687W v4
Ubuntu 22.04.3 LTS
Python 3.10.5 | packaged by conda-forge | (main, Jun 14 2022, 07:06:46) [GCC 10.3.0] on linux
with setting CPU affinity, single run
Cores Simulations Execution Time
10 1000 00:00:04.274913
10 10000 00:00:30.311358
10 100000 00:04:57.086862
10 1000000 00:50:58.328345
Cores Simulations Execution Time
16 1000 00:00:03.605890
16 10000 00:00:21.139773
16 100000 00:03:25.156981
16 1000000 00:35:11.151080
Cores Simulations Execution Time
20 1000 00:00:03.855061
20 10000 00:00:17.721105
20 100000 00:02:39.870485
20 1000000 00:26:22.462597
执行时间似乎与核心数量成一定线性关系(除了由于在较低数量的模拟中产生进程而产生的一些开销)。
根据 Apple M1 Pro 和 Dual Xeon E5-2687Wv4 之间的常见基准测试数据,例如
- M1 Pro 10 Core 的 PassMark
- 双 Xeon E5-2687Wv4 的 PassMark
- 使用 M1 Pro 和双 Xeon E5-2987Wv4 进行 OpenFOAM 基准测试
我预计性能会提升约 25...30%(如果我们认为这些基准不确定,则至少提升 15%)。但是,我的蒙特卡罗模拟在两个系统上的表现大致相同。
根据以上发现,我的问题是:
- 这仅仅是因为 Apple M1 Pro 采用了更现代的架构吗?
- 我在这里遗漏了什么(尽管 Python 本身相当慢)?
- 我如何才能更详细地调查这个扩展问题?
答案1
我预计性能会提高约 25...30%(如果我们认为这些基准不确定,则至少会提高 15%)。
随着
较旧的双 Xeon E5-2687Wv4 工作站采用 20 个核心(停用超线程)
不一定能很好地协同工作,尤其是与我下面强调的另一个问题一起。
单个 Xeon应该启用超线程时,性能优于 M1 Pro。
许多多核基准测试显示超线程可以将性能提高15%到30%。。有些极端情况超线程并没有任何好处,但更多的时候超线程允许独立线程使用 CPU 中未充分利用的部分,从而使 CPU 核心的多个部分能够更好地加载。
通过禁用超线程,您实际上会将 Xeon 的性能降低 0% 到 30%。
从 CPU 基准测试比较Apple M1 Pro 10 Core 3200 MHz vs 英特尔至强 E5-2687W v4 @ 3.00GHz
在单线程上,Apple M1 Pro 可能领先于 Xeon,但在多核 (CPU Mark) 基准测试中,Xeon应该获胜 25%,但是通过禁用超线程,您就剥夺了 Xeon 的优势。
就其本身而言,不应该放一个双重的Xeon 系统处于劣势,但双 Xeon 处理器的系统还存在其他潜在问题。
双 Xeon 架构导致同步问题。对于要在第二个 CPU 上运行的每个线程,数据必须通过两个处理器之间的 QPI 链路复制到第二个处理器的内存中,请参见下图了解架构。然后必须通过 QPI 链路将结果复制回主线程进行处理。这会导致系统出现瓶颈,尤其是当您的线程具有较小的数据集时。
将该瓶颈与禁用的超线程相结合意味着您的工作负载必须进行调整并了解系统。旧的双 CPU 系统实际上可能并不比已经具有显着优势的现代处理器更快(请注意 M1 Pro 的单核基准),并且没有NUMA 内存架构。我还注意到,可以改变性能的现代 Xeon 集群模式,但这些需要系统调整。
根据系统的任务和架构,具有明显更高单核性能的单 CPU 系统可能会胜过“更强大”的系统。
一段时间以来,英特尔和 AMD 都已将越来越多的内核装入单个封装中,由此产生的系统更加可预测,并且具有更一致的内存接口。