Samara Portal Technology, Computers

Самарский портал "Технологии, компьютеры"

Галопом по вычислительным Европам. Часть 2. Пути повышения IPC.

Статическая оптимизация и «бег в ширину»

Другой вариант оптимизации исполнения называется «явный параллелизм» или «статическая оптимизация». Предполагается, что на этапе компиляции будут заранее выявлены все возможности распараллеливания и сформирован абсолютно идеальный код, заполняющий все функциональные устройства процессора в каждом такте. Никакого динамического анализа кода не нужно (соответственно, не нужно сложной схемотехники организации спекулятивного исполнения, занимающей заметную часто кристалла), все заранее готово и можно не глядя запускать на исполнение готовые «упаковки» команд, заполняющие все ФУ. Красиво? Безусловно. Универсально? Нет, конечно. Во-первых — см. выше про последовательную природу большинства алгоритмов. Во-вторых — не все зависимости хорошо ложатся на конкретные архитектуры процессоров.

В результате имеем то, что имеем: EPIC/VLIW процессоры остались нишевыми устройствами для DSP, некоторых видеоадаптеров (распараллеливание в этих задачах почти идеальное) и пытаются влезть в нишу платформ для гиперскейлеров, а все попытки сделать из них универсальные процессоры после мощного старта постепенно проиграли конкуренцию совершенствующимся системам с динамической оптимизацией исполнения (как это случилось с линейкой PA-RISCIntel Itanium).

Появление линейки Intel Itanium тем более удивительно, что у Intel уже был опыт неудачи с EPIC в качестве CPU общего назначения. Процессор i860 (32/64-разрядный), который тоже запускали с большой помпой, а потом оказалось, что его практически достижимая производительность на произвольном алгоритме едва-едва дотягивает до 10-15% от теоретически возможной (при том, что на некоторых алгоритмах и в частных применениях i860 был для своего времени просто великолепен), я даже написал про этот эпизод отдельную статью с иллюстрациями. Собственно, IA64 – это тот же i860, только полностью 64-разрядный, двухпоточный и несколько допиленный архитектурно. Результат оказался абсолютно таким же, что и у i860. Зачем всё это было?

В случае же упорства в заблуждениях и доведении идеи до абсурда, усилия чипмейкеров привели к появлению таких уродливых(sic!) реализаций, как процессоры «Эльбрус». В них, из-за доведения идеи сверхширокого командного слова до абсурда (25(!) параллельных исполнительных устройств, в каждое из которых в каждом такте теоретически можно отправить команду) - вместо повышения КПД транзисторов получилось понижение КПД до уровня, при котором конкурировать по производительности они могут только с процессорами пятнадцатилетней, как минимум, давности, но и это у них получается не всегда. Причина очевидная и простая: заполнить все 25 исполнительных устройств в каждом такте на произвольно взятом алгоритме невозможно. Как правило, из 25 «букв» в среднем используется 4-6 (и именно такую степень параллельности мы видим во всех успешных универсальных вычислителях архитектуры VLIW, и именно столько же исполнительных устройств в «обычных» процессорах, которые «суперскалярные+SMT»). И это не случайное совпадение — именно таков реально достижимый уровень параллелизма исполнения.

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

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

В общем, повторюсь: статическая оптимизация и сверхширокое командное слово — идеи интересные, но (а) не универсальные и (б) требующие очень аккуратного подхода к реализации.

Что же мы имеем сегодня в итоге в самых высокопроизводительных и универсальных процессорах? Сочетание этих подходов: компиляторы, которые делают что могут, максимально оптимизируя код под архитектуру — и, одновременно, очень продвинутые аппаратные модули по анализу и переупорядочиванию кода в процессорах, которые работают вместе. С ядрами разобрались? А как понять, сколько ядер нам надо?

Количество против качества, или «как изменяется произведение от перемены мест сомножителей».

Про коммутативность умножения мы знаем с начальной школы, да? 4x2=8 и 2х4=8, верно? В целом это верно, но есть нюанс: когда мы говорим о производительности вычислительной техники, это правило не работает, точнее, работает не всегда. Как так?

А вот так... Фокус в том, что большинство алгоритмов вычислений — последовательные, как я и говорил выше. Нет, конечно, что-то удается распараллелить, но эффективно (равномерно) это получается не всегда. Поэтому, в локальном применении, процессоры равной общей производительности, но имеющие мало быстрых ядер, оказываются быстрее, чем имеющие много медленных. Потому что «главная задача» выполняется на одном отдельно взятом быстром ядре быстрее, чем на медленном (что логично).

Да, конечно, в современных операционных системах одновременно выполняются сотни и тысячи потоков команд, так что занятие найдется для всех, но большинство этих потоков не требуют каких-то предельных на сегодня темпов обработки. Что из этого следует? Для домашнего компьютера, для офисной работы или локального сервера нет смысла гоняться за количеством ядер, лучше обратить внимание на IPC, частоты, и другие детали архитектуры, такие как структура кэшей и частоты памяти. Например, процессор AMD Ryzen 5 1600X (6 ядер/12 потоков) с частотами 3,6/4,0 GHz в большинстве деловых применений окажется медленнее, чем процессор AMD Ryzen 3 3100 (4 ядра/8 потоков) с частотами 3,6/3,9 GHz. Как так? А вот так: во-первых, из-за того, что IPC у архитектуры Zen где-то на 10-15% меньше, чем у Zen 2, во-вторых, из-за медленной памяти (2400 против 3200), и в-третьих из-за того, что L3 у него состоит из двух частей по 8 мегабайт. Получается так, что «главная задача» оперирует с хорошей скоростью только восемью мегабайтами данных против шестнадцати, а потом в дело вступает и меньшая ПСП.

В результате при том, что формально общая производительность всех ядер Ryzen 5 1600X больше почти в полтора раза — при работе, например, в очень популярной программе 1С, которая работает в один поток, разница в производительности достигает 20-25% в пользу Ryzen 3 3100. Казалось бы, должно быть наоборот. Но нет.

Галопом по вычислительным Европам. Часть 3. Оптимизация. Статья Ильи Вайцмана. 20.01.2023 г.

А в современных играх, например, практически паритет (Ryzen 5 1600X имеет небольшое преимущество, нивелируемое тем, что он из-за большего энергопотребления быстрее откатывается из авторазгона к базовой частоте при равном охлаждении). Они достаточно неплохо умеют использовать многопоточность, так что старый процессор вытягивает за счет большего количества потоков.

Однако все идет по спирали, и если мы рассмотрим другую пару, процессоры Ryzen 7 3800XT и Ryzen 7 5800X, которые по формальным параметрам, вроде бы одинаковые по ядрам/потокам, частотам и размерам кэшей — то увидим интересное, но уже знакомое: помимо разницы в архитектуре ядра поколений Zen 2 и Zen 3 – у них по-разному устроен кэш третьего уровня. Ryzen 7 3800XT имеет два «полукэша» по 16 мегабайт, в то время, как 5800X располагает единым кэшем размером 32 мегабайта. Почему так? Развитие технологий, конечно. Огромные регулярные структуры с множеством портов доступа дело сложное и дорогое, так что до моноблочного L3 размером 32 мегабайта еще нужно было дорасти.

Если же пойти дальше и посмотреть на 16-ядерный AMD Ryzen 9 5950X, то увидим, что внутри он состоит, фактически, из двух Ryzen 7 5800X, а его 64-мегабайтовый кэш состоит из двух 32-мегабайтовых половинок. Дальше — больше: четыре таких чиплета станут 32-ядерным процессором, а там и 64-ядерный серверный процессор не за горами. Но — с сегментированным кэшем, да.

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

Галопом по вычислительным Европам. Часть 3. Оптимизация. Статья Ильи Вайцмана. 20.01.2023 г.

Теперь я задам резонный вопрос: а всегда ли нужны на рабочем месте мощные ядра в таком количестве? Если у нас полным-полно задач, которые требуют небольших вычислительных мощностей, но довольно сильно мешают «главной задаче» вынуждая процессор в рамках многозадачности менять исполняемый контент (а это десятки тысяч тактов и ненужные вытеснения из кэшей) — не разумнее ли выделить им простые (дешевые и холодные) ядра, и пусть они там себе крутятся?

По-моему, это разумно, как минимум.

Поэтому логичным представляется подход компании Intel по созданию асимметричных процессоров (начиная с 12-го поколения с кодовым наименованием Alder Lake), в которых высокопроизводительные SMT ядра для «главной задачи» сочетаются с энергоэффективными однопоточными ядрами для всего остального. КПД таких процессоров в пересчете «на транзистор» оказывается гораздо выше. «Главную задачу» выполняем на уменьшенном количестве (но большего «качества») производительных ядер, а остальные задачи сливаем на экономичные (обратите внимание, у них даже частота ниже), чтобы не мешались (у однопоточных E-ядер Gracemont еще и кэш L2 больше, чем у P-ядер Golden Cove, чтобы они реже мешали «главной задаче» работать с памятью). Такое сочетание позволяет эффективно использовать все транзисторы на кристалле.

Конечно, это потребовало появления в процессоре специального аналитического блока, оценивающего каждую задачу по ее потреблению ресурсов и рапортующую операционной системе о желательном для нее ядре. И, конечно, операционная система должна уметь понимать эти сигналы. На сегодня среди десктопных OS пока это только Windows 11, но я думаю, что и остальные довольно быстро подтянутся, потому что идея очень рациональная.

Галопом по вычислительным Европам. Часть 3. Оптимизация. Статья Ильи Вайцмана. 20.01.2023 г.

Зачем же тогда появляются процессоры с десятками и сотнями мощных вычислительных ядер, такие как AMD EPYC Genoa или Intel Sapphire Rapids? А кому нужны многосотядерные процессоры сравнительно небольшой мощности отдельно взятого ядра, такие как 128-ядерные ARM процессоры Ampere Altra Max, Huawei Kunpeng 920, Alibaba Yitian 710 и им подобные?

Ответ очевиден при взгляде на место их установки — это же огромные «облачные» ЦОДы. Там, сколько бы ядер в процессоре ни было — одновременных пользователей и их задач «на всю мощность» все равно гораздо больше, чем ядер. Ситуация такая же, как с использованием кэшей. Нагрузка равномерная и полная, эффективная производительность равна (в первом приближении) суммарной производительности ядер — и на первое место выходит уже не производительность ядра, как такового, а более хитрые штуки, такие, как производительность на ватт, на сокет и на юнит в стойке. И в разных ситуациях весомость разных факторов может быть разной. Кому-то нужна производительность на юнит любой ценой и они покупают AMD EPYC Genoa, а кто-то предпочитает пускай не максимальную, но гарантированную производительность для миллионов потоков при минимальном энергопотреблении и делает систему на огромном количестве небыстрых RISC-V (и покупает ноут на ARM или RISC-V, потому что разработчик, пишущий под эту платформу или выездной технический специалист, которому важна максимальная автономность ноутбука).

Сегодня есть выбор, и это хорошо.

От чего же, в конце концов, зависит реальный IPC у процессоров разных типов? От внутренней архитектуры, конечно, как мы сейчас выяснили — но и не только. Способность ядра процессора исполнять команды много и быстро — хорошо, но ведь эти команды (программы, как последовательности команд) не существуют сами по себе, они должны еще как-то попасть в процессор, а попав в него — обрабатывать какие-то данные, верно?

Но ведь их — и сами программы, и те данные, которые они должны обработать — еще надо исполнительным устройствам процессора как-то предоставить, загрузить их туда, а потом оттуда результаты обработки выгрузить, чтобы ими как-то воспользоваться. И вот об этом сложнейшем процессе управления данными мы сейчас поговорим подробнее.

Продолжение следует…

----

Галопом по вычислительным Европам. Часть 2. Пути повышения IPC.

Галопом по вычислительным Европам. Часть 3. Оптимизация.

Галопом по вычислительным Европам. Часть 3. Оптимизация. Статья Ильи Вайцмана. 20.01.2023 г.

Галопом по вычислительным Европам. Часть 4. Как накормить процессор.

Галопом по вычислительным Европам. Часть 4. Как накормить процессор. Статья Ильи Вайцмана. 25.01.2023 г.

Blood, Sweat & Tears, или Кровь, пот и слёзы – часть третья, объединительная

Про верных русланов и их потомков

Про верных русланов и их потомков. Статья Владислава Боярова. 11.05.2022 г..