[Перевод] Компиляция C/C++ на Apple M1
Заинтригованный впечатляющими бенчмарками M1, я достал последний Mac Mini, чтобы замерить скорость компиляции на C/C++.
Измеряем локальный build2 (без репозитория пакетов), который включает преимущественно код на C++ (611 единиц трансляции) с некоторыми блоками на C (29) и связками между ними (19). Такой бенчмарк требует только компилятора C++ и входит в тестовый набор Phoronix, поэтому можно сравниться с большим количеством процессоров.
Бенчмарк Phoronix в настоящее время использует build2 0.12.0, у нас 0.13.0 (текущий релиз), здесь сборка выполняется примерно на 10% медленнее.
После настройки Mac OS и установки инструментов командной строки для XCode 12.2 у нас есть всё необходимое:
$ clang++ --version
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: arm64-apple-darwin20.1.0
Судя по _LIBCPP_VERSION
в заголовке __version
файла libc++
, эта версия Apple Clang ответвилась от ванильного Clang где-то в процессе разработки 10.0.0.
Возможно, вы также заметили, что название процессора в триплете Apple Clang отличается от стандартногоaarch64
. На самом делеconfig.guess
показывает следующее:$ ./config.guess aarch64-apple-darwin20.1.0
Чтобы не использовать два названия для одного и того же, build2 канонизировалarm64
вaarch64
, поэтому вbuildfiles
мы всегда видим aarch64.
Проверим количество аппаратных потоков в sysctl
:
$ sysctl -n hw.ncpu
8
Здесь 8 потоков, это 4 производительных ядра и 4 энергоэффективных. В первом прогоне задействуем все ядра. Очевидно, это даёт наилучший результат:
$ time sh ./build2-install-0.13.0.sh --local --yes ~/install
163s
Приятным сюрпризом оказалось то, что build2 0.13.0 заработал без особых проблем, хотя он вышел раньше M1. Поскольку в ARM слабое упорядочение памяти, это также послужило дополнительной проверкой многопоточной реализации build2 и интенсивного использования атомиков.
Для начала сравним M1 с моей рабочей станцией на 8-ядерном Intel Xeon E-2288G (по сути, i9–9900K плюс ECC). Та же сборка на ванильном Clang занимает 131 с. Хотя это лучший результат, но производительность M1 всё равно впечатляет. Особенно если учесть, что во время компиляции рабочая станция буквально изрыгает горячий воздух и гудит как самолёт, а М1 тихо шуршит с едва заметным потоком тёплого воздуха.
Однопоточный бенчмарк оценивает производительность CPU в инкрементальных билдах:
$ time sh. /build2-install-0.13.0.sh --local --yes-j 1 ~ / install
691s
Ядро E-2288G справляется за 826 секунд. Таким образом, ядро Xeon на 5 ГГц на самом деле медленнее, чем ядро M1 на 3,2 ГГц.
Еще один интересный результат — четырёхпоточный прогон, который использует только производительные ядра М1:
$ time sh ./build2-install-0.13.0.sh --local --yes -j 4 ~/install
207s
Хотя он несколько медленнее восьмиядерного теста, но зато использует меньше памяти. Таким образом, такой вариант имеет смысл на системах с недостатком оперативной памяти (как на всех современных машинах M1).
Вот краткое изложение всех результатов:
CPU CORES/THREADS TIME ------------------------- E-2288G 8/16 131s M1 4+4 163s M1 4 207s M1 1 691s E-2288G 1 826s
Понятно, что во многих отношениях это сравнение яблок с апельсинами (рабочая станция против мобильного устройства, старый дизайн и техпроцесс против самого современного и т. д.)
Теперь добавим несколько интересных результатов из бенчмарка Phoronix. В частности, уместно взять показатели новейших рабочих станций и мобильных процессоров Intel и AMD. Вот моя подборка (можете составить собственную, только не забудьте добавить дополнительные 10% к результатам Phoronix; также обратите внимание, что в большинстве тестов используется GCC вместо Clang):
CPU CORES/THREADS TIME ------------------------------------------ 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 * Экстраполяция.
Обратите внимание, что результаты для лучших мобильных Intel (1185G) и AMD (4900HS), к сожалению, ещё не доступны, и приведённые цифры экстраполированы на основе частоты и других бенчмарков.
Из приведённой выше таблицы легко понять, что Apple M1 — впечатляющий процессор, особенно с учётом энергопотребления. Более того, это первый общедоступный ARM-процессор настольного класса. Для сравнения, та же сборка на Raspberry Pi 4B занимает 1724 секунды, то есть более чем в 10 раз медленнее! Хотя мы не можем тут загрузить Linux или Windows, но есть некоторые свидетельства, что они работают на виртуальных машинах с приличной производительностью. В итоге, конвейер непрерывной сборки на базе ARM может стать стандартным.
Увидев бенчмарки M1, невольно задаёшься вопросом, как Apple такое удалось. Хотя есть много спекуляций с некоторыми элементами чёрной магии и колдовства, но вполне хорошим источником технической информации мне показалась эта статья о M1 на Anandtech (и ещё одна там по ссылке). Основные моменты:
Процесс TSMC 5 нм
По сравнению с интеловскими 10 нм (для 11×5G, 14 нм для E-2288G) и 7 нм у AMD/TSMC.LPDDR4–4266 RAM
Только новейшие мобильные процессоры от Intel и AMD работают с такой быстрой памятью.Большой кэш L1
У M1 необычно большой кэш L1 для команд и данных.Большой и быстрый общий кэш L2
В отличие от процессоров Intel и AMD, которые используют отдельные кэши L2 меньшего объёма и большой, но более медленный общий кэш L3, в процессоре M1 реализован быстрый и большой общий кэш L2.Широкое ядро
У M1 необычайно «широкое» ядро, которое выполняет несколько инструкций параллельно и/или не по порядку. Есть предположение, что из-за слабого упорядочения памяти ARM и кодирования команд фиксированного размера, Apple смогла сделать гораздо более широкое ядро.
Было бы также интересно посмотреть, как Apple сможет масштабировать эту конструкцию на большее количество ядер.