«Пятничная угадайка», удивляющая своей иррациональностью и величиной цифр.

Если увеличить число процессорных ядер в 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 на аналог хостовой не приносит никакого результата.

В сухом остатке:

  1. добавление второго 12 ядерника ускоряет сборку почти линейно.
  2. добавление второго 18 ядерника ускоряет сборку на ~10%.

Любые идеи и гипотезы приветствуются. Особенно которые легко проверить. Например, я бы с радостью проверил сборку няпрямую, без виртуалок, но свободного SSD хотя бы на 512Gb у меня просто нет. И систему с 2678 желательно не останавливать. (Т.е. вариант перетестировать с прямой загрузкой с HDD не подходит).

UPD: чтобы не вспоминали закон Амдалла приведу ещё такой пример. На 128/256 двухголовом EPYC (64 ядра каждый камень), 1Tb RAM, и NVMe RAID тот же AOSP собирается за 12 минут.

Комментарии (54)


  1. Helfi
    29.01.2022 12:11
    +2

    Запасаемся попкорном.


  1. Number7
    29.01.2022 12:17
    +1

    У вас чудо чудное только при сборке AOSP? Как я понял из поста, вы ничего другого не тестили. Попробуйте замерять время сборки, скажем linux kernel на 12ядрах и на 18ти.


    1. screwer Автор
      29.01.2022 12:31

      AOSP хорош исключительной стабильностью получаемых результатов. Ну и одна из функций сервера - сборка AOSP.


  1. napa3um
    29.01.2022 12:18
    +15

    Гипотезы:

    1. Ошибки в условиях тестирования или сбора результатов.

    2. Пределы масштабирования используемого ПО (издержки на согласование результатов работы всех ядер становятся выше полезного вклада отдельного ядра). Возможно, плохая масштабируемость многопоточности (для данного профиля нагрузки) затаилась прям в операционной системе или в ограничениях системы виртуализации.

    3. Троттлинг из-за перегрева более многоядерного процессора или его более жёсткое воздержание от турбобустов при загрузке всех ядер (во избежание перегрева).

    4. Злоумышленник, подделывающий результаты или намеренно замедляющий вашу гостевую систему на слишком жирных процессорах (может, продаёт ваши ядра на сторону или майнит на них что-нибудь).

    5. Случайное совпадение, радиоактивный фон, влияющий на вычисления, проклятие или наведённая порча.


    1. screwer Автор
      29.01.2022 12:25

      1. Исключено. Но можем провести другие тесты.

      2. масштабирование-согласование не обьясняет, почему 48 потоков на 18 ядрах работают намного хуже 48 потоков на 12 ядрах

      3. Серверный корпус, хороший обдув, холод в помещении. Температуры отличные.

      4. Хост система чистая, установленна с нуля сутки назад. Тестовую виртуалку могу выложить для ознакомления.

      5. Слишком хорошее воспроизведение ((


      1. napa3um
        29.01.2022 12:49
        +4

        Второй и третий пункт вы не опровергли.


        1. screwer Автор
          29.01.2022 13:25

          Второй большой очень. Про виртуализации мне нечего ответить.

          Третий опроверг. И за температурами наблюдал. Они в норме.


          1. napa3um
            29.01.2022 13:27

            Температура могла быть в норме именно из-за управления частотами ядер (сдерживания их турбобуста). Ну и устойчивость проклятия вы недооценили :).


            1. screwer Автор
              29.01.2022 13:39
              +1

              Турбобуст как раз не сдерживается. Он разлочен в UEFI сторонний утилитой. 12 ядерники бустятся до стабильных 3300 по всем ядрам, 18 ядерники до 3200-3600. Упор мог быть только в TDP. Но он выше у 18 ядерников, поэтому не объясняет их отставание


              1. napa3um
                29.01.2022 14:28
                +3

                Ну вы сами столько различий описали, а потом вдруг анулировали их совершенно беспредметным тезисом. Вот и померяйте, на каких частотах в итоге отработали ваши ядра, увеличение теплопакета не гарантирует более эффективного расхода этого пакета (при масштабировании физических устройств издержки синхронизации ядер выражаются в том числе и в лишнем тепле).


              1. funny_falcon
                29.01.2022 18:46

                Так нарисуйте график частоты ядер от времени. Думаю, вас ждёт сюрприз.

                Кроме того, процессор может тротлится и не снижая частоту, просто пропуская такты. Это тоже где-то можно обнаружить (в смысле, прочитать в /proc или /sys), но не помню где.


      1. polearnik
        29.01.2022 12:52
        +2

        а почему именно 48 потоков и там и там ? логичнее сделать на Xeon E5-2678v3 24 потоков а на Xeon E5-2696v3 - 36 потоков. иначе у вас получается что лишние потоки отнимают время на переключения


        1. screwer Автор
          29.01.2022 13:24

          Чтобы попытаться получить на 18 ядерниках хотя бы производительность 12 ядерникоа


      1. Psychosynthesis
        29.01.2022 13:03
        +1

        1. А мне кажется как раз неплохо объясняет... 48/18 = 2.6, как они там по ядрам в таком случае распределяются - вопрос к специалистам, а при 48/12 всё ровненько и раз процессы одинаковые, почему б им не занимать место в памяти оптимальнее?


        1. screwer Автор
          29.01.2022 13:26

          Загрузка всех потоков 100% основную часть времени. Хоть на 12, хоть на 18 ядерниках. Простоя ядер не видно.


          1. M_AJ
            29.01.2022 17:33

            Загрузка в мониторе мало о чем вообще говорит. Пока процесс по какой-то причине ждёт данных из памяти в мониторе будет отображается 100% загрузка.


        1. screwer Автор
          29.01.2022 13:31

          36/18 тоже ровненько. И 72/18. А результат странный.


          1. Miron
            30.01.2022 06:37

            Более того, 48/18 = 2,6666666666(6).... Мне кажется, что совокупность програмно-аппаратных средств при такой конфигурации представима в виде вычислителя который пытается разделить 2 на 3, с бесконечной точностью, что в принципе недостижимо. Видимо в процессе где-то есть переход который при переключении потока выполняет "код деления" и записывает виртуальные 6-ки в виртуальный результат :). Кстати угадайка вполне себе рациональна. Каким способом не делить 3 на 2, в итоге получишь полтора! Попробуйте поиграйтесь с кратностью потоков.


      1. mird
        29.01.2022 19:59

        1. 48 на 12 делится нацело, а на 18 нет, это может влиять.


    1. napa3um
      29.01.2022 14:07

      2.1 - предел масштабирования может быть и в IO, это и предельные ограничения многопоточного доступа к физическому устройству / файловой системе, и ограничения настроек на количество одновременно открываемых файлов.


      1. screwer Автор
        29.01.2022 16:18

        Версия с ограничением объяснила бы примерно равную производительность, но столь значительное падение.


        1. napa3um
          29.01.2022 16:28
          +1

          Почему же, падение тоже может объяснить, может даже и полную остановку объяснить :).


  1. chersun
    29.01.2022 12:22
    +4

    Похоже вы открыли тайну... добавление мощностей не приводит к линейному масштабированию. Это базовое правило, которое по-моему уже все давно учитывают при построении больших систем.

    Обусловливается как пределами масштабирования, так и накладными расходами на параллелизацию.


    1. screwer Автор
      29.01.2022 12:22

      Ладно бы добавление мощности не привело бы к ускорению. Деградация такая огромная - почему ?

      И см. апдейт в конце статьи.


      1. 1dash
        29.01.2022 12:55
        +3

        Увеличение числа ядер, увеличивает мощность как N, а накладные расходы, очень часто, растут как N^2 (и это если кэши не переполняются, а так намного хуже).


        1. napa3um
          29.01.2022 13:29
          +1

          И это если программист справился с масштабированием в принципе :).


      1. fougasse
        29.01.2022 15:09

        ІО проверили?


        1. screwer Автор
          29.01.2022 16:19

          Диск виртуалки на NVMe. Как с помощью Io объяснить просадку ?

          Кроме того, ожидание ИО вылилось бы в недогруз ядер. А они были загружены до упора практически все время.


          1. fougasse
            29.01.2022 18:24

            Прежде чем пытаться объяснять, обычно, проверяют.


  1. czz
    29.01.2022 13:18

    Например, я бы с радостью проверил сборку няпрямую, без виртуалок

    Было бы неплохо все же проверить на bare metal, дабы исключить влияние виртуализации.

    Я наблюдал такую ситуацию, что при распределении CPU/RAM-intensive нагрузки на большое количество ядер (один 64-ядерник EPYC) производительность на ядро падала вплоть до 2-х раз, но только в QEMU. На bare metal та же нагрузка масштабировалась нормально.


    1. screwer Автор
      29.01.2022 13:28
      +1

      Да, это самая вероятная причина. Плохая работа NUMA внутри виртуалки. Неистовая межсокетная пересылка все бы объяснила. Сделаю при первой же возможности.


  1. Sdima1357
    29.01.2022 13:30

    Попробуйте уменьшить число ядер для сборки. Например в 1.5 раза :)


    1. screwer Автор
      29.01.2022 13:42

      Уменьшал число потоков, параметром билд системы. Ядра в UEFI не блокировал. Могу заблокировать. Например из 18 ядерников можно сделать 12 ядерники, тогда они выдадут стабильные 3600 по всем ядрам.


      1. Sdima1357
        29.01.2022 14:27

        И как результат? У Вас явно processing power не узкое место.


        1. screwer Автор
          29.01.2022 16:20

          Процессоры в обоих случаях загружены до упора. Версию с ограничением ядер в UEFI протестирую вечером.


  1. 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

    В общем и целом, нужны графики нагрузки на каждое ядро, суммарная нагрузка на процессор, графики температуры и частоты ядер.


    1. screwer Автор
      29.01.2022 13:43

      Турбобуст разлочен в обоих случаях. Процессоры бустят все свои ядра до максимально возможной частоты (3300 и 3600 соотв.) пока не упрутся в ТДП. Турбобуст не сбрасывается - в стрессе молотят постоянно на буст частоте.


  1. ky0
    29.01.2022 13:44

    Вы всю интригу выдали тэгами :) Я так и подумал, что станет кратно дольше.


    1. screwer Автор
      29.01.2022 13:46

      Но я правда не знаю причину (((


  1. amarao
    29.01.2022 14:00
    +3

    Выглядит как лимит на глубину очереди блочного устройства. Возможно, спинлоки где-то в коде блочных устройств приводят к прпорциональному замедлению.

    Попробуйте собрать LVM в режиме interleave из нескольких виртуальных устройств. raid0 тоже можно, но у него есть некоторые проблемы своего рода в районе высокой производительности.


  1. 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/


  1. Nacreous1991
    29.01.2022 14:18
    +3

    Может ли быть ограничение в чтение данных с диска. Есть такой прикол, что файл в 1 ГБ копируется за минуту, а если 2 файла паралельно копировать то это займет 10 минут


  1. szt_1980
    29.01.2022 16:14
    +2

    >QEMU

    Ключевое слово здесь. Во-первых, является ли эта задача CPU-bound или IO-bound? Более вероятно второе - смотрите количество потоков, порождаемых этой поделкой, и потребление памяти. Если потоков слишком много, то это оно (там IO так сделан), и надо подбирать бэкэнд среди нескольких полурабочих


  1. permeakra
    29.01.2022 18:10
    +1

    1) скачать интеловскую утилиту мониторинга, посмотреть, что конкретно в процессоре загружено https://github.com/opcm/pcm .

    2) Посмотреть статистику локов в ядре (возможно, придется пересобирать ядро)

    3) Попробовать пересобрать с build_tree на tmpfs

    4) попробовать запустить в параллель две сборки на одной и разной файловых системах.

    5) сравнить kernel time/ user time.

    Гипотеза 1): где-то, например в драйвере файловой системы или устройства, есть мьютекс, в спин-локе которого и просирается время.

    Гипотеза 2): избыток ядер порождает избыток какого-то служебного трафика по процессорным шинам, например сообщений протокола когерентности кэша, который засирает какую-то критическую шину, например относительно узкий межпроцессорный линк QPI


    1. permeakra
      29.01.2022 18:27

      К слову, вспоминается аналогичная история, которая вроде как случилась на винде и была связана с мьютексом при освобождении дескриптора процесса. К сожалению, с ходу не нагугливается.


  1. DikSoft
    30.01.2022 00:10

    Поставить тот же опыт, использовав Hyper-V Core. Было бы интересно...


  1. 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 этого времени - генерация жирных образов прошивок (которые не часть аоспа).


    1. szt_1980
      30.01.2022 04:50

      >если какая-то несовместимость с системными либами - можно ведь докер взять

      Вообще не нужно. chroot, и все.


    1. screwer Автор
      30.01.2022 11:42

      Виртуалка - потому что сборка АОСП не единственная функция. Изоляция между VM намного надёжнее докера.

      Возьмите последний АОСП с сайта и соберите. Уверен, никаких 25 минут вы не получите.


      1. vvviperrr
        30.01.2022 11:54

        какой таргет?


      1. vvviperrr
        30.01.2022 17:54

        собрал дефолтный arm-eng.

        build completed successfully (36:20 (mm:ss))

        real 36m20.478s
        user 1043m34.827s
        sys 42m27.580s

        root@4720ed223c15:/work/aosp# du -sh out/
        65G out/

        не учел, что у нас выпилена куча стандартных пакетов + все же 9-й aops.


  1. onyxmaster
    30.01.2022 08:52

    А попробуйте отключить SMT в BIOS ради эксперимента, если ещё нет.


  1. moroz69off
    30.01.2022 22:53

    Я в компьютерах совсем не понимаю, но интуиция подсказывает - собака зарыта в кратности. Поскольку (постольку) я в компьютерах ничего не понимаю, то и пояснять не возьмусь. Но истина - где-то рядом (смотри комментарии, где упоминается кратность чисел и копай в сторону оптимизации (экономии вычислений), высосанной кожаным мешком из собственного пальца: 2*2 вседа равно 4, так и кладём большой прибор на 2*2, и просто пишем 4. Это не точно, это интуиция...


  1. alex319
    01.02.2022 04:13

    Я бы проверил для начала производительность процессоров в бенчмарках на других задачах. Может быть это вообще китайская подделка )). Я каноны брал с АлиЭкспресс только последнее время