Compilando C / C ++ no Apple M1





Intrigado com os benchmarks impressionantes do M1, peguei o mais recente Mac Mini para medir minha velocidade de compilação em C / C ++. Medimos o build2



local (sem um repositório de pacotes), que inclui principalmente código C ++ (611 unidades de tradução) com alguns blocos C (29) e links entre eles (19). Este benchmark requer apenas um compilador C ++ e está incluído no conjunto de testes Phoronix , portanto, pode ser comparado a um grande número de processadores.



O benchmark Phoronix atualmente usa build2 0.12.0, nós temos 0.13.0 (versão atual), aqui o build é cerca de 10% mais lento.


Depois de configurar o Mac OS e instalar as ferramentas de linha de comando para XCode 12.2, temos tudo o que precisamos:



$ clang++ --version
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: arm64-apple-darwin20.1.0
      
      





A julgar pelo arquivo de _LIBCPP_VERSION



título , esta versão do Clang Clang vanilla da Apple divergiu de algum lugar no processo de desenvolvimento 10.0.0.__version



libc++







Você também deve ter notado que o nome do processador no trio Apple Clang é diferente do padrão aarch64



. Na verdade, config.guess



mostra o seguinte:



$ ./config.guess
aarch64-apple-darwin20.1.0
      
      





Para evitar o uso de dois nomes para o mesmo, build2 canonicalizado arm64



em aarch64



, portanto buildfiles



, sempre vemos aarch64 nele.


Vamos verificar o número de threads de hardware em sysctl



:



$ sysctl -n hw.ncpu
8
      
      





Existem 8 threads aqui, estes são 4 núcleos produtivos e 4 núcleos de eficiência energética. Na primeira execução, usamos todos os núcleos. Obviamente, isso dá o melhor resultado:



$ time sh ./build2-install-0.13.0.sh --local --yes ~/install
163s
      
      





Foi uma surpresa agradável que o build2 0.13.0 funcionou sem problemas, embora tenha sido lançado antes do M1. Como o ARM tem ordenação de memória fraca, isso também serviu como um teste adicional para a implementação multithread de build2 e uso pesado de atomics.


Primeiro, vamos comparar o M1 à minha estação de trabalho em um Intel Xeon E-2288G de 8 núcleos (essencialmente um i9-9900K mais ECC). A mesma compilação no vanilla Clang leva 131 segundos. Embora este seja o melhor resultado, o desempenho do M1 ainda é impressionante. Especialmente quando você considera que durante a compilação, a estação de trabalho literalmente cospe ar quente e zumbe como um avião, e o M1 sussurra silenciosamente com um fluxo quase imperceptível de ar quente.



Um benchmark de thread único avalia o desempenho da CPU em compilações incrementais:



$ time sh. /build2-install-0.13.0.sh --local --yes-j 1 ~ / install
691s
      
      





O núcleo E-2288G leva 826 segundos. Portanto, o núcleo Xeon de 5 GHz é realmente mais lento do que o núcleo M1 de 3,2 GHz.



Outro resultado interessante é uma execução de quatro threads, que usa apenas os núcleos M1 eficientes:



$ time sh ./build2-install-0.13.0.sh --local --yes -j 4 ~/install
207s
      
      





Embora seja um pouco mais lento do que o teste de oito núcleos, ele usa menos memória. Portanto, esta opção faz sentido em sistemas com RAM insuficiente (como em todas as máquinas M1 modernas).



Aqui está um resumo de todos os resultados:



TEMPO DE NÚCLEOS / LINHAS DE CPU
-------------------------
E-2288G 8/16 131s
M1 4 + 4 163s
M1 4 207s
M1 1 691s
E-2288G 1 826s


É claro que em muitos aspectos esta é uma comparação de maçãs com laranjas (estação de trabalho versus dispositivo móvel, design antigo e tecnologia de processo versus moderna, etc.)



Agora vamos adicionar alguns resultados interessantes do benchmark Phoronix. Em particular, é apropriado levar os indicadores das últimas estações de trabalho e processadores móveis da Intel e AMD. Aqui está minha seleção (você pode fazer a sua própria, mas lembre-se de adicionar 10% a mais aos resultados do Phoronix; observe também que a maioria dos testes usa GCC em vez de Clang):



TEMPO DE NÚCLEOS / LINHAS DE CPU
------------------------------------------
AMD Threadripper 3990X 64/128 56s
AMD Ryzen 5950X 16/32 71s
Intel Xeon E-2288G 8/16 131s
Apple M1 4 + 4 163s
AMD   Ryzen        4900HS   8/16      176s*
Apple                 M1    4         207s
AMD   Ryzen        4700U    8/8       222s
Intel Core         1185G    4/8       281s*
Intel Core         1165G    4/8       295s

* .


Por favor, note que os resultados para os melhores móveis Intel (1185G) e AMD (4900HS) infelizmente ainda não estão disponíveis e os números citados são extrapolados com base em relógios e outros benchmarks.



É fácil ver na tabela acima que o Apple M1 é um processador impressionante, especialmente quando se considera o consumo de energia. Além disso, é o primeiro processador ARM padrão para desktop. Em comparação, a mesma construção em um Raspberry Pi 4B leva 1.724 segundos, mais de 10 vezes mais lento! Embora não possamos inicializar o Linux ou o Windows aqui, há algumas evidências de que eles são executados em máquinas virtuais com desempenho decente. Como resultado, o pipeline de construção contínua baseado em ARM pode se tornar padrão.



Tendo visto os benchmarks do M1, não podemos deixar de nos perguntar como a Apple fez isso. Embora haja muita especulação com alguns elementos de magia negra e bruxaria, mas este artigo sobre M1 no Anandtech (e outro ali pelo link) me pareceu uma boa fonte de informação técnica . Luzes:



TSMC 5

10 ( 11x5G, 14  E-2288G) 7  AMD/TSMC.



LPDDR4-4266 RAM

Intel AMD .



L1

M1 L1 .



L2

Intel AMD, L2 , L3, M1 L2.





M1 tem um kernel excepcionalmente amplo que executa várias instruções em paralelo e / ou fora de ordem. Especula-se que, devido ao pobre ordenamento de memória e codificação de instrução de tamanho fixo do ARM, a Apple foi capaz de fazer um kernel muito mais amplo.


Também seria interessante ver como a Apple pode dimensionar esse design para mais núcleos.



All Articles