Если увеличить число процессорных ядер в 1,5 раза, не трогая ничего остального — как изменится время сборки проекта?
… оно тоже увеличится в 1,5 раза!
Не верите? И я не поверил. Предупреждаю сразу — ответа у меня всё ещё нет…
Дано:
- Платформа 2011-3, двухсокетная, чипсет C612.
- Хост ОС Ubuntu 20.04, виртуализация QEMU/KVM. «mitigations=off»
- Гостевая ОС Ubuntu 18.04 или 20.04. Не имеет значения. «mitigations=off»
- Памяти 256Gb, виртуальной машине выделено 96Gb.
- Собираемый проект AOSP.
- Процессоры (A) Xeon E5-2678v3: 12 ядер, 3300Mhz, 30mb cache, TDP 120w
- Процессоры (B) Xeon E5-2696v3: 18 ядер, 3600Mhz, 45mb cache, TDP 145w
Процессоры — OEM, их «официальные» аналоги 2680v3 и 2699v3. Единственное отличие — OEM умеют работать с DDR3. В остальном они близнецы-сёстры. Лок турбобуста отключен. Процессоры бустят все ядра, пока не упрутся в TDP (18 ядерник может единственное ядро аж до 3.8 добустить, но сейчас это не важно)
Сборка идёт в виртуалке. При этом не важно, на passthrough SSD SATA диске, или же cow2 образе, лежащем на SSD M2. Разница незаметна.
12 ядерники собирают примерно за час (real 66m, user 2705m, sys 126m)
18 ядерники собирают примерно за 1,5 часа (real 92m, user 5528m, sys 310m)
И это не поддаётся никакому объяснению, ведь 18 ядерники ничем не хуже!
Может быть билд-система не умеет использовать столько ядер? Но тогда время было бы примерно равно 12 ядерникам, только часть ресурсов бы простаивала. На всякий случай проверим. Будем уменьшать число потоков, доступных билд системе:
- 72: 92m26s
- 48: 93m15s
- 36: 92m46s
- 18: 112m23s
Может один из 18 ядерных процессоров дефектный? Вынимаем по очереди один, и второй. Получаем время сборки около 100m. Т.е. процессоры в порядке.
Изначально машина была одна. На которой и столкнулся с ситуацией, заменив только процессоры. Собрал вторую машину, на 18 ядерниках. Ситуация прекрасно воспроизвелась опять. У этой второй машины нет пользователей, и она более-менее свободна для тестов.
NUMA выглядит правдоподобным объяснением. Но изменение топологии в QEMU/KVM на аналог хостовой не приносит никакого результата.
В сухом остатке:
- добавление второго 12 ядерника ускоряет сборку почти линейно.
- добавление второго 18 ядерника ускоряет сборку на ~10%.
Любые идеи и гипотезы приветствуются. Особенно которые легко проверить. Например, я бы с радостью проверил сборку няпрямую, без виртуалок, но свободного SSD хотя бы на 512Gb у меня просто нет. И систему с 2678 желательно не останавливать. (Т.е. вариант перетестировать с прямой загрузкой с HDD не подходит).
UPD: чтобы не вспоминали закон Амдалла приведу ещё такой пример. На 128/256 двухголовом EPYC (64 ядра каждый камень), 1Tb RAM, и NVMe RAID тот же AOSP собирается за 12 минут.
Комментарии (54)
Number7
29.01.2022 12:17+1У вас чудо чудное только при сборке AOSP? Как я понял из поста, вы ничего другого не тестили. Попробуйте замерять время сборки, скажем linux kernel на 12ядрах и на 18ти.
screwer Автор
29.01.2022 12:31AOSP хорош исключительной стабильностью получаемых результатов. Ну и одна из функций сервера - сборка AOSP.
napa3um
29.01.2022 12:18+15Гипотезы:
Ошибки в условиях тестирования или сбора результатов.
Пределы масштабирования используемого ПО (издержки на согласование результатов работы всех ядер становятся выше полезного вклада отдельного ядра). Возможно, плохая масштабируемость многопоточности (для данного профиля нагрузки) затаилась прям в операционной системе или в ограничениях системы виртуализации.
Троттлинг из-за перегрева более многоядерного процессора или его более жёсткое воздержание от турбобустов при загрузке всех ядер (во избежание перегрева).
Злоумышленник, подделывающий результаты или намеренно замедляющий вашу гостевую систему на слишком жирных процессорах (может, продаёт ваши ядра на сторону или майнит на них что-нибудь).
Случайное совпадение, радиоактивный фон, влияющий на вычисления, проклятие или наведённая порча.
screwer Автор
29.01.2022 12:25Исключено. Но можем провести другие тесты.
масштабирование-согласование не обьясняет, почему 48 потоков на 18 ядрах работают намного хуже 48 потоков на 12 ядрах
Серверный корпус, хороший обдув, холод в помещении. Температуры отличные.
Хост система чистая, установленна с нуля сутки назад. Тестовую виртуалку могу выложить для ознакомления.
Слишком хорошее воспроизведение ((
napa3um
29.01.2022 12:49+4Второй и третий пункт вы не опровергли.
screwer Автор
29.01.2022 13:25Второй большой очень. Про виртуализации мне нечего ответить.
Третий опроверг. И за температурами наблюдал. Они в норме.
napa3um
29.01.2022 13:27Температура могла быть в норме именно из-за управления частотами ядер (сдерживания их турбобуста). Ну и устойчивость проклятия вы недооценили :).
screwer Автор
29.01.2022 13:39+1Турбобуст как раз не сдерживается. Он разлочен в UEFI сторонний утилитой. 12 ядерники бустятся до стабильных 3300 по всем ядрам, 18 ядерники до 3200-3600. Упор мог быть только в TDP. Но он выше у 18 ядерников, поэтому не объясняет их отставание
napa3um
29.01.2022 14:28+3Ну вы сами столько различий описали, а потом вдруг анулировали их совершенно беспредметным тезисом. Вот и померяйте, на каких частотах в итоге отработали ваши ядра, увеличение теплопакета не гарантирует более эффективного расхода этого пакета (при масштабировании физических устройств издержки синхронизации ядер выражаются в том числе и в лишнем тепле).
funny_falcon
29.01.2022 18:46Так нарисуйте график частоты ядер от времени. Думаю, вас ждёт сюрприз.
Кроме того, процессор может тротлится и не снижая частоту, просто пропуская такты. Это тоже где-то можно обнаружить (в смысле, прочитать в /proc или /sys), но не помню где.
polearnik
29.01.2022 12:52+2а почему именно 48 потоков и там и там ? логичнее сделать на Xeon E5-2678v3 24 потоков а на Xeon E5-2696v3 - 36 потоков. иначе у вас получается что лишние потоки отнимают время на переключения
screwer Автор
29.01.2022 13:24Чтобы попытаться получить на 18 ядерниках хотя бы производительность 12 ядерникоа
Psychosynthesis
29.01.2022 13:03+1А мне кажется как раз неплохо объясняет... 48/18 = 2.6, как они там по ядрам в таком случае распределяются - вопрос к специалистам, а при 48/12 всё ровненько и раз процессы одинаковые, почему б им не занимать место в памяти оптимальнее?
screwer Автор
29.01.2022 13:26Загрузка всех потоков 100% основную часть времени. Хоть на 12, хоть на 18 ядерниках. Простоя ядер не видно.
M_AJ
29.01.2022 17:33Загрузка в мониторе мало о чем вообще говорит. Пока процесс по какой-то причине ждёт данных из памяти в мониторе будет отображается 100% загрузка.
screwer Автор
29.01.2022 13:3136/18 тоже ровненько. И 72/18. А результат странный.
Miron
30.01.2022 06:37Более того, 48/18 = 2,6666666666(6).... Мне кажется, что совокупность програмно-аппаратных средств при такой конфигурации представима в виде вычислителя который пытается разделить 2 на 3, с бесконечной точностью, что в принципе недостижимо. Видимо в процессе где-то есть переход который при переключении потока выполняет "код деления" и записывает виртуальные 6-ки в виртуальный результат :). Кстати угадайка вполне себе рациональна. Каким способом не делить 3 на 2, в итоге получишь полтора! Попробуйте поиграйтесь с кратностью потоков.
napa3um
29.01.2022 14:072.1 - предел масштабирования может быть и в IO, это и предельные ограничения многопоточного доступа к физическому устройству / файловой системе, и ограничения настроек на количество одновременно открываемых файлов.
chersun
29.01.2022 12:22+4Похоже вы открыли тайну... добавление мощностей не приводит к линейному масштабированию. Это базовое правило, которое по-моему уже все давно учитывают при построении больших систем.
Обусловливается как пределами масштабирования, так и накладными расходами на параллелизацию.
czz
29.01.2022 13:18Например, я бы с радостью проверил сборку няпрямую, без виртуалок
Было бы неплохо все же проверить на bare metal, дабы исключить влияние виртуализации.
Я наблюдал такую ситуацию, что при распределении CPU/RAM-intensive нагрузки на большое количество ядер (один 64-ядерник EPYC) производительность на ядро падала вплоть до 2-х раз, но только в QEMU. На bare metal та же нагрузка масштабировалась нормально.screwer Автор
29.01.2022 13:28+1Да, это самая вероятная причина. Плохая работа NUMA внутри виртуалки. Неистовая межсокетная пересылка все бы объяснила. Сделаю при первой же возможности.
Sdima1357
29.01.2022 13:30Попробуйте уменьшить число ядер для сборки. Например в 1.5 раза :)
screwer Автор
29.01.2022 13:42Уменьшал число потоков, параметром билд системы. Ядра в UEFI не блокировал. Могу заблокировать. Например из 18 ядерников можно сделать 12 ядерники, тогда они выдадут стабильные 3600 по всем ядрам.
myz0ne
29.01.2022 13:39+1И это не поддаётся никакому обьяснению, ведь 18 ядерники ничем не хуже!
у 12-ядерника базовая частота выше. 2.3 Ghz vs 2.5 Ghz
Tcase у 12-ядерника выше 84.5 vs 76.4. Не до конца понимаю этот параметр, но допускаю что 12 может дольше работать в режиме Turbo Boost.
https://ark.intel.com/content/www/ru/ru/ark/compare.html?productIds=81908,81061
Т.е. причина может быть в том что 12 ядерник дольше работает в turbo boost, но даже когда буст выключается и проц работает на базовой частоте, он все равно быстрее в расчете на ядро.
---
upd
В общем и целом, нужны графики нагрузки на каждое ядро, суммарная нагрузка на процессор, графики температуры и частоты ядер.
screwer Автор
29.01.2022 13:43Турбобуст разлочен в обоих случаях. Процессоры бустят все свои ядра до максимально возможной частоты (3300 и 3600 соотв.) пока не упрутся в ТДП. Турбобуст не сбрасывается - в стрессе молотят постоянно на буст частоте.
amarao
29.01.2022 14:00+3Выглядит как лимит на глубину очереди блочного устройства. Возможно, спинлоки где-то в коде блочных устройств приводят к прпорциональному замедлению.
Попробуйте собрать LVM в режиме interleave из нескольких виртуальных устройств. raid0 тоже можно, но у него есть некоторые проблемы своего рода в районе высокой производительности.
AelDeyr
29.01.2022 14:06+4По спецификации у процессоров, кажется, есть отличие: поддержка Transactional Synchronization Extensions 12-ти ядерным процессором, которой на первый взгляд нет у 18-ти ядерного. Для сборки это потенциально как раз порядка 30% за счёт ускорения межпоточной синхронизации
Можно попробовать отключить флагами компилятора (пересобрать сам компилятор без поддержки TSE), или лучше аппаратно флагами ядра и проверить
upd: https://www.cpu-world.com/Compare_CPUs/Intel_CM8064401610101,Intel_CM8064401967500/
Nacreous1991
29.01.2022 14:18+3Может ли быть ограничение в чтение данных с диска. Есть такой прикол, что файл в 1 ГБ копируется за минуту, а если 2 файла паралельно копировать то это займет 10 минут
szt_1980
29.01.2022 16:14+2>QEMU
Ключевое слово здесь. Во-первых, является ли эта задача CPU-bound или IO-bound? Более вероятно второе - смотрите количество потоков, порождаемых этой поделкой, и потребление памяти. Если потоков слишком много, то это оно (там IO так сделан), и надо подбирать бэкэнд среди нескольких полурабочих
permeakra
29.01.2022 18:10+11) скачать интеловскую утилиту мониторинга, посмотреть, что конкретно в процессоре загружено https://github.com/opcm/pcm .
2) Посмотреть статистику локов в ядре (возможно, придется пересобирать ядро)
3) Попробовать пересобрать с build_tree на tmpfs
4) попробовать запустить в параллель две сборки на одной и разной файловых системах.
5) сравнить kernel time/ user time.
Гипотеза 1): где-то, например в драйвере файловой системы или устройства, есть мьютекс, в спин-локе которого и просирается время.
Гипотеза 2): избыток ядер порождает избыток какого-то служебного трафика по процессорным шинам, например сообщений протокола когерентности кэша, который засирает какую-то критическую шину, например относительно узкий межпроцессорный линк QPI
permeakra
29.01.2022 18:27К слову, вспоминается аналогичная история, которая вроде как случилась на винде и была связана с мьютексом при освобождении дескриптора процесса. К сожалению, с ходу не нагугливается.
vvviperrr
30.01.2022 01:46во-первых, зачем собирать под виртуалкой, пусть даже с kvm? скорей всего в ней и проблема. если какая-то несовместимость с системными либами - можно ведь докер взять.
во-вторых, аосп аоспу рознь, но
12 ядерники собирают примерно за час (real 66m, user 2705m, sys 126m)
18 ядерники собирают примерно за 1,5 часа (real 92m, user 5528m, sys 310m)мой домашне-рабочий пк на 5950x, 64gb ram собирает наш аосп за 25 минут. процентов 10-15 этого времени - генерация жирных образов прошивок (которые не часть аоспа).
szt_1980
30.01.2022 04:50>если какая-то несовместимость с системными либами - можно ведь докер взять
Вообще не нужно. chroot, и все.
screwer Автор
30.01.2022 11:42Виртуалка - потому что сборка АОСП не единственная функция. Изоляция между VM намного надёжнее докера.
Возьмите последний АОСП с сайта и соберите. Уверен, никаких 25 минут вы не получите.
vvviperrr
30.01.2022 17:54собрал дефолтный arm-eng.
build completed successfully (36:20 (mm:ss))
real 36m20.478s
user 1043m34.827s
sys 42m27.580sroot@4720ed223c15:/work/aosp# du -sh out/
65G out/не учел, что у нас выпилена куча стандартных пакетов + все же 9-й aops.
moroz69off
30.01.2022 22:53Я в компьютерах совсем не понимаю, но интуиция подсказывает - собака зарыта в кратности. Поскольку (постольку) я в компьютерах ничего не понимаю, то и пояснять не возьмусь. Но истина - где-то рядом (смотри комментарии, где упоминается кратность чисел и копай в сторону оптимизации (экономии вычислений), высосанной кожаным мешком из собственного пальца: 2*2 вседа равно 4, так и кладём большой прибор на 2*2, и просто пишем 4. Это не точно, это интуиция...
alex319
01.02.2022 04:13Я бы проверил для начала производительность процессоров в бенчмарках на других задачах. Может быть это вообще китайская подделка )). Я каноны брал с АлиЭкспресс только последнее время
Helfi
Запасаемся попкорном.