Como parte da minha rotina de avaliação de dados, estou realizando 1.000.000 de simulações de Monte-Carlo em meu MacBook Pro M1 Pro (10 Core, 32 GB de RAM) usando vários processos em Python 3.10.5 (. Os tempos de execução são 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
Tentando diminuir o tempo de cálculo e carregar o trabalho da minha máquina principal, decidi realizar o cálculo em uma estação de trabalho Dual Xeon E5-2687Wv4 mais antiga utilizando 20 núcleos (hyper-threading desativado):
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
De acordo com os números acima, não consegui ver nenhum aumento perceptível no desempenho. No entanto, usar apenas 20 dos 24 núcleos disponíveis pode produzir alguma sobrecarga, pois o escalonador tende a trocar os núcleos do processador. Para investigar esse efeito potencial, configurei manualmente a afinidade da CPU de cada processo e obtive os seguintes resultados:
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
Novamente, nenhuma diferença no desempenho foi perceptível. Para garantir que o código seja dimensionado em geral, testei a execução com 10, 16 e 20 núcleos na estação de trabalho:
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
Os tempos de execução parecem escalar linearmente com o número de núcleos (exceto por alguma sobrecarga devido à geração dos processos em um número menor de simulações).
Com base em números de benchmark comuns entre o M1 Pro da Apple e o Dual Xeon E5-2687Wv4 como
- PassMark para M1 Pro 10 Core
- PassMark para Dual Xeon E5-2687Wv4
- Benchmark OpenFOAM com M1 Pro e Dual Xeon E5-2987Wv4
Eu esperava um aumento de desempenho de cerca de 25...30% (ou pelo menos 15% se considerarmos estes benchmarks como incertos). No entanto, minhas simulações de Monte-Carlo apresentam desempenho aproximadamente equivalente em ambos os sistemas.
Com base nas descobertas acima, minhas perguntas são:
- Isso se deve apenas à arquitetura mais moderna do M1 Pro da Apple?
- O que estou perdendo aqui (apesar de o próprio Python ser bastante lento)?
- Como eu poderia investigar esse problema de dimensionamento com mais detalhes?