IT в России и мире в реалиях мирового кризиса
1,282,312 7,813
 

  _taras_ ( Слушатель )
29 янв 2022 14:09:15

Об "Эльбрусе" и стиле программирования

новая дискуссия Дискуссия  889

На Хабре выложен отчет о тестировании инженерного образца Эльбрус-16С с предыдущим поколением и интеловским процем (Core i7-2600).

 Вкратце... Несмотря на технические проблемы с процем и не отлаженность компилятора, Эльбрус-16С показывает увеличение производительности на  33% чем у Эльбрус-8СВ. Но по некоторым задачам всё так же печально...
 А в Этой статье рассмотрено нюансы создания кода для Эльбрус-ов. Читается как хороший детектив.
  • +0.12 / 7
  • АУ
ОТВЕТЫ (29)
 
 
  mrt789 ( Слушатель )
05 фев 2022 00:18:39

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

for (int i = start_i; i domain_n + 2) + j;
       double wij  = src[idx];
       double wipj = src[(i + 1) * (run_config-domain_n + 2) + j];
       double wimj = src[(i - 1) * (run_config-domain_n + 2) + j];
       double wijp = src[i       * (run_config-domain_n + 2) + j + 1];
       double wijm = src[i       * (run_config-domain_n + 2) + j - 1];
       double x = (run_config-start_i + i - 1) * run_config-h1;
       double y = (run_config-start_j + j - 1) * run_config-h2;
       double laplacian = (wipj + wimj - 2 * wij) * run_config-sqinv_h1 + (wijp + wijm - 2 * wij) * run_config-sqinv_h2;
       dst[idx] = q(x, y) * wij - laplacian - alpha * F(x, y);
   }
}



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

Отсюда "атомная" производительность на реальном ПО где дажмп на джампе сидит (но да, 16 ядер - это все-таки 16 ядер, оно быстрее чемКрутой. И это не потому, что код индусский - ОНО ВСЕ ТАКОЕ, построенное на передаче управления туда-сюда, иногда еще и в зависимости от действий пользователя.
Но это уже прогресс: в 22 году начали открываться детали и начали задаваться вопросы. И главный вопрос все тот же: способен ли МЦСТ в принципе сделать суперскаляр с конвейером и предсказанием переходов, чтобы непотребством из статьи занимался сам ЦПУ хотя бы на средненьком уровне набивая свою широкую команду?
------
Это не значит, что им нельзя пользоваться - эльбрус просто не то, чем его пытаются представить, вопя про аналговнонет и сравнивая со вполне бытовым i7. Был у PS3, в свое время, такой мега крутой и прогрессивный процессор Cell, в теории, а потом практика внесла свои коррективы.
  • +0.03 / 2
  • АУ
 
 
  adolfus ( Слушатель )
08 фев 2022 11:30:37

По первому выделению:
В отношении ветвления программы бывают очень разные. Где-то много циклов, как в вычислительных алгоритмах, и данные тут, в основном, с плавающей запятой, где-то циклов мало, зато куча условных переходов. И в каждом случае требуется разная стратегия оптимизации и параллелизации, если это возможно. Вряд ли в кремнии можно реализовать то, что можно реализовать на уровне компиляции – банально площади не хватит. Горизонт планирования у кремния крайне мал, а вот программист, что касается циклов, знает еще на этапе программирования, где у него что, как и сколько будет крутиться, даже в случае алгоритмов с выходом из цикла по результату, а не по счетчику. Просто необходимо дать ему возможность сообщать компилятору об этом. Если речь идет о C, то стандарт предусматривает механизм такого общения – прагмы (если речь идет об уровне процессора, то, например в случае x86_64, предусмотрены префиксы, которыми программист может влиять на предсказание вероятности переходов).
И еще – если передача параметров в процедуры идет мимо памяти, т.е через регистры, потерь на вызовы можно избежать, имея два кеша инструкций, инструкции по заполнению которых генерируются компилятором, а не кремнием.
А если еще предусмотреть совместную компиляцию как циклов, так и процедур, которые в них крутятся, то даже объявлять их встраиваемыми (inline) не потребуется – компилятор просто встроит код в тело наиболее оптимальным образом. Кремний этого не сможет никогда.
В идеале нужно использовать несколько специализированных процессоров, код на которые будет раскладывать компилятор.

По второму выделению:
С библиотеками в программах-числодробилках линковка обычно идет как раз статическая, что дает прирост в производительности иногда до 30%, а в ряде случаев и в разы (собственный опыт в отношении использования libm). Динамическая линковка катастрофически отнимает у программы память – даже если вы используете всего одну функцию из динамической библиотеки, динамический компоновщик отобразит в ваше адресное пространство всю библиотеку целиком – он не умеет "выдирать" только тот код, который нужен программе, поскольку ничего не знает об этом и нет механизмов об этом ему сообщить. А в случае статической  компоновки в вашем адресном пространстве окажется только та часть библиотеки, которая будет реально использоваться.
  • +0.05 / 3
  • АУ
 
 
 
  mrt789 ( Слушатель )
08 фев 2022 19:18:12

1. У кремния есть уникальная абсолютно недостижимая для компилятора особенность - он всегда видит текущее состояние в рантайме. Причем исключительно на своем уровня, где уже нет никаких делений, и где инструкции прикладного ПО ничем не отличаются от инструкций системного.
2. Я не спорю с числодробилками, это всегда пожалуйста. Но как был сказано "программирование начинается там, где заканчивается память" - любой ввод/ввыод (сетевой, файловой, пользовательский), это системный вызовы ядра, ты мимо них не прыгнешь. И ядро статически не слинкуешь со своим софтом (дядя Торвальдс проклянет), соответственно никакой компилятор не залезет внутрь "man 2 read/write/open", которые через цать прокладок приземляются на тот или иной произвольный драйвер. Это база, с махровых времен, когда выделилась ОС и произошло разделение на системное и прикладное ПО.
  • +0.00 / 0
  • АУ
 
 
 
 
  adolfus ( Слушатель )
08 фев 2022 22:28:43

Это так, однако видит он совсем немного и только то, что "уже случилось". Что случится, он не видит и надеется только на подсказку со стороны программиста, если он предоставляет программисту такую возможность (x86_64 таки представляет, но на уровне конкретного префиксирования инструкций, но не факт, что компилятор это может сделать сам без участия программиста).
Что касается предсказания "будущего", то у кремния все ветви равновероятны, и только программист и компилятор могут здесь что-то улучшить.
Например, если известно, что компилятор в случае 
if (!cc)
    ex1  // это прямо
else
    ex2  // а тут переход jсс ex2
пускает ex1 прямо, а ex2 через jсс (gcc), то программист может просто на уровне стандартного синтаксиса управлять поведением кремния. А если еще у копмпилятора будет прагма, которая управляет генерацией переходов, то никакой кремний никогда не сравнится с программистом (компилятором).
  • +0.02 / 1
  • АУ
 
 
 
 
  adolfus ( Слушатель )
08 фев 2022 22:49:28

Ввод/вывод – это отдельная пестня и вряд ли прикладной программист на что-то тут может влиять, даже если он работает на уровне системных вызовов. С другой стороны у нас есть неблокирующие вызовы на сей счет и даже мультипоточность.
Работа с данными, она выдвигает особые требования. Это та поляна где идет борьба между SQL и ISAM. Тот же оракле, когда подгреб BerkeleyDB, писал  в руководствах, что если схема статична, то использование SQL оправдано только для макетирования – софт с использование bdb будет производительнее в разы и вести себя более предсказуемо, поскольку управление такими ограниченными ресурсами, как память и пропускная способность сетей и каналов ввода/вывода ложатся полность на программиста, который всегда знает больше и детальнее, нежели SQL-компилятор. К сожалению, их клиентура словно в последний раз живет – кроме как быстро выпустить и срубить бабки, в том числе и на распиле, не заинтересована.
  • +0.01 / 1
  • АУ
 
 
 
 
 
  Поверонов ( Слушатель )
08 фев 2022 23:52:21

Извините эффективность порядка вложения циклов при SQL запросе определяется не столько схемой сколько статистикой распределения данных по находящимся в распоряжении индексам ( execution plan ) А статистика вещь сугубо динамическая изменяющаяся во времени - то что было оптимально месяц назад сегодня может стать уже по-другому в зависимости от накопленных за это время данных в базе. Программист не должен каждый месяц переделывать порядок циклов в запросе ( вообще говоря - во всех запросах ) если конечно ему больше нечем заняться
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
  adolfus ( Слушатель )
12 фев 2022 01:02:45

Я не о "порядке вложения циклов при SQL запросе" пытался сказать, а о том, что (оракле считает точно так же), в случае статической схемы данных и в отсутствие крысиных гонок за рынком имеет смысл программить не в SQL, а прямо в ISAM. Именно по этой причине они и купили BerkeleyDB, которая тогда и сегодня является одной из лучших реализаций ISAM.
Во всех реализациях SQL всегда  транслируется в т\у или иную группу примитивов ISAM. Альтернативы тут нет – SQL построен поверх ISAM. Типа, как бейсик поверх ассемблера.
  • +0.00 / 0
  • АУ
 
 
 
 
 
  mrt789 ( Слушатель )
09 фев 2022 01:08:21

И точно также ничего не может сделать никакой компилятор. Мир с точки зрения ЦПУ сводится к набору его регистров и шинам данных/адреса. Ничего больше для него не существует. Зато он видит все на живую и может химичить с исполнением инструкций, как угодно может химичить - для него они все едины. Пусть и на очень маленьком отрезке, зато постоянно.
Если же подняться на несколько уровней выше, то у того же МЦСТшного компилятора, при компиляции любого реального софта возникнут ситуации, которые он не может оптимизировать от слов никак и никогда - это системные вызовы (ядро не инлайнится, придется делать переход) и поведение зависящее от ввода/вывода (то есть от тех же системных вызовов), которое никак нельзя предсказать.  А ЦПУ на своем микроуровне будет пытаться химичить и здесь, с каким-то успехом.
Где-то чего-то компилятор оптимизирует, из того что увидит, но в целом результат всегда будет как у 486-переростка при прочих равных. Вот и вся ситуация с эльбрусом. Удваивание количество ядер и снижение техпроцесса здесь ничего принципиально не меняют, только помогают замести ситуацию под ковер.

----

Простыми словами: если во внутренний фор из статьи добавить банальный вывод в консоль, то широкой команде и аппаратным циклам придет пушной зверек, потому что это 100% системный вызов, который еще неизвестно чего будет делать и куда выводить. Сначала да, там будет printf, который можно заинлайнить, но дальше уже будет write.

"Бздынь!" - сказала пила.


И да, основная масса нечислодробильного софта ("все в памяти, в одном массиве") примерно этим же и занята - сеть, файлы, обслуживание пользователя.
  • +0.02 / 2
  • АУ
 
 
 
 
 
 
  adolfus ( Слушатель )
12 фев 2022 01:28:41

Никто во внутрений ("вычислительный") for никогда не вставляет ни одной функции, которая может быть прервана сигналом, отличным от сигнала, безусловно завершающего процесс (TERM или KILL, например). Мало того, если нужно во "внутреннем" for (я так понимаю, что это, типа "реалтайм" for?) что-то попросить у системы, то это всегда асинхронное и внутри for результаты этого вызова не нужны. А если вдруг оказывется. что таки нужны, имеет смысл пересмотреть постановку задачи.
На самом деле во "внутренние" for в приложениях, которые взаимодействуют с пользователями, никто никогда даже не вставляет функций, которые не могут быть реально inline, т.е. определены в отдельно компилируемых единицах трансляции. Все, что выполняется внутри Вашего for, должно пристутствовать в Вашем исходном модуле, либо оно должно быть функцией из стандартной библиотеки с (не c++, а именно c), а библиотека должна линковаться статически.
  • +0.01 / 1
  • АУ
 
 
 
 
 
 
 
  mrt789 ( Слушатель )
12 фев 2022 16:53:20

Не спорю, просто на всем, что не укладывается в это, эльбрус с вливом будет демонстрировать производительность в десятки процентов от заявленной.
Что он и делает. Без возможности частично выправить ситуацию за счет "суперскалярности" с предсказанием и спекулятивным исполнением.

Цитата"внутреннем" for (я так понимаю, что это, типа "реалтайм" for?)


это из  исходной статьи, там был код с двумя вложенными циклами
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
  Поверонов ( Слушатель )
12 фев 2022 18:05:13

Вообще-то непонятно почему поток инструкций процессору должен оптимизировать сам процессор, а не компилятор, который имеет достаточную информацию о ветвлении логики команд. Или это эффект мультизадачности где последовательность команд процессору определяется не программной логикой, а случайно переключаемым контекстом процессов ? Но хотя бы внутри отдельного процесса можно постараться оптимизировать поток инструкций на стадии компиляции
  • +0.01 / 1
  • АУ
 
 
 
 
 
 
 
 
 
  mrt789 ( Слушатель )
12 фев 2022 18:51:25

Велком ту зе реал ворлд, Нео.
Потому что на самом деле компилятор не имеет этой информации. По нескольким причинам:
1. Компилятор видит только, что собирает. Это следствие деления на прикладное ПО и системное, в экзешнике который вы скомпилируете, не будет кусков ядра ОС, на работу с которым он рассчитан. И при этом у вас получится исполняемый файл, который будет запускаться и работать с сетью на десятке разных машин с разным железом.
2. Ну и наконец, ветвление может зависеть от какого-то условия, которое будет или не будет только рантайме - ввод/вывод, сеть, etc. Это нельзя предсказать на этапе компиляции.

Цитатаэффект мультизадачности


Частично да, потому что мультизадачность подразумевает ОС в которую время от время надо передавать управление, чтобы что-то сделать, но только я бы сказал что это в целом деление на прикладное и системное ПО. Причем прикладное ПО может быть самым разным от и до каких-нибудь виртуальных машин / JIT комипялторов. Все должно оптимизировать под влив? Ну это фантастика.

Вот поэтому и не взлетело, в случае с тем же итаником. Реальное ПО на уровне потока инструкций к ЦПУ представляет собой полную кашу и мешанину из всего вышеперечисленного, и именно ЦПУ (и только он) имеет возможность как-то это все оптимизировать в целом, пусть и на масштабе в десяток команд.
----
Это может быть неправильно, не оптимально и ваще фу-фу-фу, вот только квака 1 почему-то гораздо лучше бегала на первом пентиуме, с меньшей частотой по сравнению с 486DX100. А кваку вряд ли можно назвать неоптимально написанным ПО - Кармак и Ко всегда выжимали максимум и по коду и по структурам данных.
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
  DimonT ( Слушатель )
12 фев 2022 21:36:08

Народ в "исторических" ветках всяких ретроигровых и ретрокомпьютерных форумов всегда говорил что Квака была ОЧЕНЬ сильно оптимизирован ИМЕННО и КОНКРЕТНО под Пентиум с его мощным FPU ("а других и не было" c OOE в момент разработки, К5 вышел когда квака уже к релизу готовилась), почему даже на К5/K6 (тоже с out-of-order execution, но своими) - работал "несколько медленней" (там fpu другие и тормозные), хотя в "прикладном ПО" без плавающей точки большинство согласны что К5 был быстрее per clock (откуда и "печально знаменитый" PR который pentium rating, нифига не отражавший на некоторых задачах).
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
  adolfus ( Слушатель )
20 фев 2022 02:06:51

Компилятор ничего не собирает – он из исходного кода тупо производит объектный. А исполняемый модуль собирает компоновщик.
Что касается ввода-вывода, в том числе и в сеть, то не об этом идет речь, а о неблокирующем исполнении. Т.е. задача либо работает, либо находится в состоянии готовности после истечению выделенного ей кванта времени. На тесты производительности переключение задач практически не влияет, поскольку время, в течение которого задача выполняется, меряет не человек секундомером, а таймер, причем он меряет именно время в состоянии исполнения, а не время в состоянии ожидания.

Цитата2. Ну и наконец, ветвление может зависеть от какого-то условия, которое будет или не будет только рантайме - ввод/вывод, сеть, etc. Это нельзя предсказать на этапе компиляции.

Ветвлений от внешних событий в прикладных программах настолько мало встречается, что их вообще никто не учитывает. Фактически можно считать, что  их нет – код, проверяющий возврат из библиотечных функций (и системных вызовов), выполняется линейно инструкция за инструкцией, при этом кеш остается валидным. Переход происходит только в случае неуспешного завершения, что на на призводительность собственно пользовательского кода никак ен влияет. Все ветвления имеют место в коде файловой системы и ниже – в драйверах. Кремний же ничего наперед не знает, если ему лично программист не сообщит, какая из ветвей более вероятна, причем совершенно не важно, спекулятивное там будет исполнение или нет – все ветви для кремния равновероятны. Собственно, они  равновероятны уже на стадии объектного модуля, если программист не озаботился расстановкой соответсвующих префиксов или что там в байкалах для этого используется.
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
  udaf ( Слушатель )
23 фев 2022 17:40:31

Привед, всем! А если собирать статистику run-time и использовать при повторном выполнении кода. Эдакое автоматическое профилирование онлайн в помощь планировщику, а может и компилятору…
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
 
  Поверонов ( Слушатель )
23 фев 2022 19:52:22

L1,L2 кэши в процессоре что-то такое и делают
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
  udaf ( Слушатель )
23 фев 2022 20:17:52

это про текущее выполнение (ну и про данные, а не инструкции процессора), а я про статистику которая собирается  в процессе работы программы и сохраняется по окончании,  при следующем запуске  процессор может получать информацию о вероятности переходов в условиях, кол-во циклов и т.д.
Процессор запускает программу каждый раз, как в первый раз...), а тут  статистика как оно было ранее
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
  gvf ( Слушатель )
23 фев 2022 20:26:45

Все давным давно придумано до вас.
Дело кончилось уязвимостями типа spectre.
  • +0.07 / 3
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  udaf ( Слушатель )
24 фев 2022 07:36:38

1 Все давным давно придумано до вас. - Не спорю может и придумано, можете показать где?
2. Мимо...),  Meltdown, Spectre - это про время выполнение  и использования общих структур процессора с последующим анализом кэш, а так я с Вами полностью  согласен компьютеры поработят человекоff... пора выкидывать всю электронику и шапочку на лоб из фольги...
Если Эльбрус подвержен эти уязвимостям  то данная технология не увеличивает/уменьшает риски,  она не про это)
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
  Senya ( Слушатель )
23 фев 2022 20:30:14

Процессор, который самостоятельно собирает информацию о всех запускаемых программах и имеет низкоуровневый доступ к долговременным накопителям будет посильнее Фауста Гёте процессора, выключаемого сигналом со спутника. Веселый
А если серьёзно - не представляю подобную вещь без поддержки со стороны операционной системы и компилятора. И без вопиющего нарушения многочисленных требований по изоляции памяти и безопасности выполнения. Т.е. для специальных изолированных систем.
  • +0.11 / 9
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  udaf ( Слушатель )
24 фев 2022 07:58:38

1.Я могу сказать больше без поддержки самим процессором такая технология не возможна)
2.А где Вы увидели нарушение изоляции, этим грешат процессоры подверженные  Meltdown, Spectre,  я предлагаю использовать статистику конкретно по данной программе.
3.Видели фильм "День сурка"  там герой выполняет одну задачу много раз и добивается успеха, то что сейчас делают процессоры это  50 первых поцелуев 
4.Ваши страхи мне понятны, система модифицируется без участия человека, может и не туда зайти..
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  mse ( Слушатель )
24 фев 2022 10:53:25

Ну это кагбы известный закон имени известного человека: "если что-то может пойти не так, то именно так оно и пойдёт"
  • +0.03 / 2
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  qurvax ( Слушатель )
24 фев 2022 13:58:15

И следствие из него "если что-то не может пойти не так, оно все равно пойдет".
  • -0.01 / 1
  • АУ
 
 
 
 
 
 
 
 
 
 
 
 
  adolfus ( Слушатель )
27 фев 2022 00:37:42

Ну, это если алгоритм LRU статистикой назвать.
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
  kerosene ( Слушатель )
13 фев 2022 19:10:51

К слову сказать, спекулятивное исполнение у Эльбруса есть.
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
  kerosene ( Слушатель )
13 фев 2022 19:07:35

Практически весь системный софт содержит кучу системных вызовов внутри for или while. Пример - утилита печати содержимого каталогов ls и т.д.
В Линуксе любые демоны это всегда цикл с кучей системных вызовов внутри.
  • +0.00 / 0
  • АУ
 
 
 
 
 
 
 
 
  adolfus ( Слушатель )
20 фев 2022 02:51:53

Насколько я понял, речь идет о производительности пользоватеских программ, причем именно того кода, который в выводе утилиты time маркируется, как user. А системные вызовы -- это отдельная песня.
Есть ряд рекомендаций, которых, к сожалению, приктически никто не придерживается, но соблюдение которых позволяет катастрофически повысить производительность кода в пользовательском пространстве.
Первая и самая простая – отказаться от использования .so (.dll) и использовать только статическую компоновку.
Вторая, более сложная – уменьшить гранулярность исходников. Т.е вместо сотни маленьких файлов использовать несколько больших. Это, с одной стороны, увеличивает время компиляции, но с другой позволяет компилятору выпустить более оптимизированный код.
Третья и самая сложная – отказатся от вызовов в циклах функций, определенных вне той единицы трансляции, где она вызывается. Это касается в том числе и библиотечных функций. Чаще всего это функции из libm. В этом случае дейстовать следует следующим образом – в отладочном режиме используется библиотека, а в режиме выпуска исходники библиотеки подключаются как static через #include в каждом исходном файле, где используются функции из этой библиотеки. В этом случае компилятор может выполнить сквозную оптимизацию и вынести инварианты за пределы циклов, что в ряде случаев увеличивает производительность в разы и более.
  • +0.00 / 0
  • АУ
 
 
 
  AndreyK-AV ( Слушатель )
08 фев 2022 22:51:14

Улыбающийся
Дональд Кнут  "Искусство программирования", на сегодня уже 4 тома....
Гениальная книга, вроде об программировании как искусстве, но в итоге ведёт программирование в категорию высокотехнологичных инженерных дисциплин....
  • +0.01 / 1
  • АУ
 
 
 
 
  adolfus ( Слушатель )
12 фев 2022 00:32:19

Очень хорошая. Особенно второй том, получисленные алгоритмы.
Человек, который полностью (по факту на всю просматриваемую перспективу) закрыл проблему верстки естественно-научной, и не только, литературы.
  • +0.02 / 1
  • АУ