Процессор Эльбрус — почему это тупик для развития отечественной линейки general-purpose CPU

в 9:31, , рубрики: Процессоры, Эльбрус
Процессор Эльбрус — почему это тупик для развития отечественной линейки general-purpose CPU - 1

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

Российское процессоростроение, в силу понятной специфики зарождения и функционирования последних лет в основном на военных и окологосударственных заказах, критически страдает от отсутствия сколь либо открытой и доступной общественности, и при этом профессиональной дискуссии. Безусловным прорывом в данном вопросе можно считать проведение Elbrus Tech Day:

Жаль, что это происходит с примерно 15-ти летним опозданием, но лучше поздно, чем никогда. Результатом такой закрытости является нагромождение мифов вокруг Эльбруса, где антагонисты утверждают, что Эльбрус это просто старые процессоры Итаниум с переклеенными шильдиками, а сторонники рассказывают о супер архитектуре и гениальных компиляторщиках, которых не смог переманить Интел, благодаря чему Эльбрус имеет ни с чем не сравнимую производительность. Правда лежит в параллельной реальности, поэтому сначала несколько тезисов в качестве ликбеза для широкой публики, не столь глубоко знакомой с темой процессоров.

  1. Микропроцессоры архитектуры Эльбрус (e2k) - это абсолютно аутентичная разработка компании МЦСТ, основанная на предыдущем опыте создания линейки Эльбрусов 1/2/3 ещё в СССР.

  2. Хотя архитектура Эльбрус является достаточно типичной VLIW-архитектурой (процессоров на базе которой было построено много, самые известные из которых это Intel Itanium и Transmeta), у неё есть некоторые особенности, которые нельзя обобщать на все VLIW процессоры. Но для простоты повествования в рамках статьи я буду говорить о VLIW именно в контексте Эльбрусовской реализации.

  3. Компания МЦСТ также разрабатывает линейку процессоров с архитектурой Sparc V9. В названии данные процессоры также имеют слово Эльбрус, что часто вызывает путаницу. Все дальнейшие рассуждения относятся именно к VLIW-архитектуре Эльбрус (e2k), а не к Sparc V9.

  4. Самые популярные в мире процессоры на данный момент от Intel и Arm - это представители CISC и RISC архитектуры.

  5. Создание процессора можно в первом приближении разделить на разработку процессора и производство. Компания, которая только разрабатывает процессор, но для производства использует чужие мощности, называется "фаблесс". МЦСТ - это фаблесс разработчик процессоров. Как и абсолютное большинство дизайн-центров в мире, включая Apple, Qualcomm, Nvidia, HiSilicon и т.д. и т.п.

  6. В России на данный момент нет заводов по производству процессоров, которые пригодны для производства сколь-либо современных процессоров топ-уровня. Кому интересно актуальное состояние данной отрасли, можно почитать здесь. Дальше все претензии и обсуждения на тему "а производят-то на Тайване!" здесь не принимаются. Статья касается только вопроса разработки процессоров.

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

  8. При обсуждении микропроцессоров крайне важно понимать различие между Архитектурой и Микроархитектурой. Говоря простыми словами, Архитектура процессора - это набор команд, который предоставляет аппаратура для использования софтом, иначе говоря интерфейс между миром ПО и миром железа. Микроархитектура - это то, как процессор устроен внутри, т.е. каким образом он реализует предоставленные Архитектурой интерфейсы. В современных процессорах именно микроархитектура является ключевым фактором достижения производительности. Именно из-за неё разные процессоры линейки x86 или Arm, реализующие одинаковую архитектуру, при схожих параметрах тактовой частоты могут в разы отличаться по производительности.

Так в чём же проблема Эльбруса? Если не углубляться в кучу технических и не очень нюансов, их две основных:

Собственная архитектура

Интересно, что руководство МЦСТ всячески пиарит данный пункт, выставляя его в качестве преимущества. Парадокс в том, что это большой недостаток. Проблема в том, что своя архитектура означает портирование всего стэка софта, необходимого пользователям. А это колоссальные затраты, тем более для VLIW-архитектуры (об этом ниже). В МЦСТ это прекрасно понимают (несмотря на публичные заявления о собственной архитектуре как о достоинстве) и именно поэтому в Эльбрусе на аппаратном уровне сделана поддержка бинарной трансляции из x86, что означает потенциальную возможность запускать привычные пользователю программы без какого-либо портирования. Но это стоит транзисторов, перформанса и всё равно имеет много ограничений для применения в реальности. В итоге можно сказать, что создание процессора с собственной архитектурой должно иметь крайне веские обоснования, иначе это получение колоссального геморроя на ровно месте. Да, к сожалению мы не можем делать аналог x86. Да, с лицензированием Arm есть потенциальные угрозы. Но любая лицензионно чистая открытая RISC/CISC архитектура здесь будет лучше, потому что увеличивает коммьюнити, занимающееся портированием софта.

VLIW-архитектура

Главная техническая проблема. Дело в том, что VLIW-архитектура принципиально уступает по производительности современным RISC/CISC процессорам с Out-of-Order (OoO) исполнением.

Тут требуется немного технического погружения. Основная идея VLIW заключается в том, что компилятор должен создать максимально оптимальный код, который железо просто исполнит, неукоснительно следуя тому, как компилятор создал широкие команды. Широкими команды как раз называются потому, что компилятор помечает операции, которые можно исполнить независимо, и планирует их в одну команду, которую процессор может исполнить за такт. Например, вот так:

  {
    addd,0    %r0, %r5, %r5
    addd,1    %r0, %r6, %r6
    addd,2    %r0, %r7, %r7
  }

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

Идея VLIW на первый взгляд выглядит красиво, но она разбивается о реальность. В реальной жизни невозможно статически проанализировать код настолько, чтобы максимально плотно упаковать широкие команды. Пришедший указатель или сложная работа с памятью - и вы не можете спланировать Load выше операции Store (и наоборот). Если в горячем цикле есть вызов функции - его надо обязательно заинлайнить, иначе мимо него нельзя будет ничего поднять вверх и тем более применить критически важную оптимизацию конвейеризации цикла. Но при компиляции без профиля установить какие циклы горячие невозможно. Да и наличие профиля плохо помогает в случае динамической линковки, динамических вызовов, отсутствия ярко выраженного горячего кода. Опять-таки, сколь-либо сложное управление в цикле препятствует его накрутке.

В то же время классические RISC/CISC архитектуры с OoO автоматически оптимизируют и конвейеризируют любой исполняемый код. И хотя это стоит определённых транзисторов и мощности, на выходе такой подход оказывается более эффективным.

Например, чтобы получить некоторую интуицию проблемы с инлайном, не погружаясь сильно глубоко в сложные технические детали, давайте рассмотрим простейший синтетический код:

int get_inc_val () { return 3; };
...
int a=0;
while (a < 10000)
{
   a+=get_inc_val();
}
...

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

Если в данном цикле вызов функции get_int_val по какой-то причине не заинлайнится компилятором, то для RISC/CISC архитектуры с OoO итерация цикла будет занимать ~1 такт, не отличаясь принципиально от случая, если инлайн сработал.

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

Чтобы хоть как-то решать возникающие проблемы во VLIW архитектуру приходится добавлять различные, иногда достаточно нетривиальные архитектурные фичи. Нужно иметь много архитектурных регистров, т.к. требуется хранить большое количество промежуточных результатов вычислений. Как следствие, аппаратура получается сложной (а от этого как раз хотели уйти) и в итоге падают частоты, на которых VLIW-процессор может работатать. Вот сравнение самых топовых решений процессоров на базе VLIW-архитектур от Intel и МЦСТ с их RISC/CISC аналогами:

CPU model

Year

Architecture

nm

Freq, GHz

Cores

TDP,W

transistors, billion

Intel​ Itanium​ Processor 9760

2017

VLIW

32

2,66

8

170

3,1

Intel​ Xeon​ Processor E5-2687W

2012

CISC

32

3,1-3,8

8(16)

150

2,27

Intel​ Itanium​ Processor 9750

2017

VLIW

32

2,53

4

170

?

Intel​ Xeon​ Processor E3-1290

2011

CISC

32

3,6-4,0

4(8)

95

1,16

Эльбрус-8СВ

2020

VLIW

28

1,5

8

90

3,5

Эльбрус-R2000

2019

RISC

28

2,0

8

36

0,5

Как видно, VLIW-процессоры на тех же нанометрах, имеют меньшие тактовые частоты, при этом имеют более высокое тепловыделение и больше транзисторов.

В итоге VLIW процессоры проигрывают не только по микроархитектурной скорости в пересчёте на Герцы, но и по самим частотам. Кстати, данная таблица чётко демонстрирует, что декларируемая "энергоэффективность VLIW" - это миф.

Собственно говоря, именно с вышеуказанными проблемами связаны те многочисленные истории, когда пользователи Эльбруса, получив возможность скомпилировать и запустить своё ПО на данном железе, часто с первого раза получают удручающие результаты. Потому что если на небольших бенчмарках или тем более Spec2006/2017 (которые вылизывали 20+ лет) компилятор худо-бедно справляется и может сгенерировать близкий к оптимальному код, то на реальных проектах он уже не справляется, а т.к. аппартура тут подстраховать не может, то производительность падает в разы. И начинается долгая история про то "как правильно переписать код проекта, чтобы lcc смог скомпилировать оптимальный код".

Кстати, именно с этой проблемой связана достаточно странная политика МЦСТ, когда получить Эльбрус можно только написав официальный запрос на имя генерального директора. Ведь казалось бы, если вы хотите продавать свои процессоры, надо их максимально пиарить и первые партии раздавать чуть ли не бесплатно. А тут такие бюрократические препоны. Дело в том, что руководство МЦСТ в общем-то прекрасно понимает недостатки Эльбруса и максимально пытается избежать негативной огласки. Поэтому оно старается фильтровать потенциальных клиентов, чтобы в случае возникновения перформанс проблем привлечь своих специалистов, которые могут разобраться в проблемах и с помощью правильных опций, допилок компилятора или переписывания горячего кода "под Эльбрус" улучшить производительность пользовательских задач. Но масштабируемость такого подхода, думаю, всем понятна.

Отсюда следует ещё один, крайне важный вывод - процессор на базе VLIW архитектуры существенно более требователен к квалификации программистов, компилирующих программы под данную платформу. Т.е. это своеобразный дополнительный налог, который взымает архитектура с разработчиков, и чем она шире используется, тем этот налог выше. Что тоже не добавляет плюсов Эльбрусу.

Вот пример далеко не самой сложной ШК из Эльбруса:

  {
     loop_mode
     alc  alcf=1, alct=1
     abn       abnf=1, abnt=1
     ct        %ctpr1 ? %NOT_LOOP_END
     muls,0,sm %g17, %b[10], %b[1]
     addd,1,sm 0x4, %b[15], %b[13]
     adds,2,sm %b[8], 0x3, %g17
     ldw,3,sm  %r0, %b[17], %b[0] ? %pcnt12
     adds,4,sm %b[22], %b[13], %g16
     staaw,5   %g16, %aad0[ %aasti1 ]
     incr,5    %aaincr0
  }

Разобраться в логике данного кода непросто, даже имея опыт и необходимую квалификацию. А теперь представьте, это будут делать программисты в мире, где простой x86-ой ассемблер хоть как-то понимают хорошо если 1 из 100. А тут надо будет не только разобраться в коде, но ещё и понять, а что же компилятор "сделал не так" и что исправить в коде, чтобы решить проблему.

Собственно, как следствия, вполне понятны вытекающие из вышесказанного дальнейшие недостатки VLIW :

  • "Жирный" код, ведущий к повышенным кэш-миссам кода

  • Дополнительная нагрузка на кэш данных в следствие спекулятивного исполнения кода

  • Фактическая непереносимость кода между версиями процессора (если были какие-то изменения в архитектуре, то надо перекомпилировать код, чтобы получить преимущества новой версии)

  • Сложность развития микроархитектуры, т.к. в случае VLIW это почти всегда влечёт за собой изменение в архитектуре

  • Сложность оптимизации кода, сложность обработки прерываний и т.д.

Резюмируя - процессорная платформа, которая претендует стать массовой и конкуретной на рынке десктопных и серверных процессоров, не может быть VLIW архитектурой, т.к. это заведомо проигрышный путь. Дело не в конкретной имплементации или профессионализме разработчиков Эльбруса ( в МЦСТ есть специалисты, безусловно, мирового уровня в своих сферах). Проблема именно в самой архитектуре Эльбрус, которая принципиально менее производительна, чем RISC/CISC архитектуры с современными реализациями микроархитектур с OoO исполнением.

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

Автор: Максим Маслов

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js