Size: a a a

Compiler Development

2020 May 02

A

Alex in Compiler Development
Ага. А уж появления оптимизации "reroll", откатывающей ручной "unroll"...
источник

CC

Chris Calvin in Compiler Development
Alex
Я так скажу - под конкретную микроархитектуру - либо в целевых докладах, либо в исходниках. Но тут надо понимать что "машинноНЕзависимых" оптимизаций гораздо меньше чем принято считать. Тот же самый inline невероятно сильно зависит от целевой машины (не просто архитектуры, а именно машины). Как и большинство других оптимизаций. Поэтому у меня и возник вопрос "про что конкретно Вы спрашиваете". Кроме того, могут быть машиннозависимые оптимизации для "немейнстримных" архитектур, там вообще свой мир будет
> либо в целевых докладах, либо в исходниках.
Ну как-то так я изначально и предполагал. Видимо, тема очень обширная, и как правильно заметили выше слабо формализованная и специфичная. Нужно плясать от конкретики и смотреть/читать исходники и статьи/блоги/доклады по конкретным железякам.
источник

PS

Peter Sovietov in Compiler Development
Alex
Ага. А уж появления оптимизации "reroll", откатывающей ручной "unroll"...
Вот, кстати, если есть такой модуль-монолит заднего плана, который делает разные умные и сложные вещи, а результат все равно далек от идеала, то нужно со стороны этого модуля как можно больше предоставлять разных параметров для пользователя. Что-нибудь более детальное, чем традиционные опции оптимизации. А далее — машинное обучение с учетом профилей :) Собственно, есть уже достаточно много работ в этом духе, но авторы страдают из-за того, что крутилок-вертелок модуль заднего плана предоставляет слишком мало :)
источник

A

Alex in Compiler Development
Chris Calvin
> либо в целевых докладах, либо в исходниках.
Ну как-то так я изначально и предполагал. Видимо, тема очень обширная, и как правильно заметили выше слабо формализованная и специфичная. Нужно плясать от конкретики и смотреть/читать исходники и статьи/блоги/доклады по конкретным железякам.
Смотрите, для кругозора предложенной литературы более чем достаточно. В конкретных же железках будет разная подсистема памяти, разное количество регистров, разная стоимость операций и другие факторы. Там уже оптимальность будет доводиться эвристиками. Для конкретной железки могут быть какие-нибудь специфичные векторные инструкции и т.п., это нужно в железку смотреть. Могут быть более экзотические вещи типа "условного исполнения", тут уже будет проще искать информацию т.к. её не так много
источник

A

Alex in Compiler Development
Peter Sovietov
Вот, кстати, если есть такой модуль-монолит заднего плана, который делает разные умные и сложные вещи, а результат все равно далек от идеала, то нужно со стороны этого модуля как можно больше предоставлять разных параметров для пользователя. Что-нибудь более детальное, чем традиционные опции оптимизации. А далее — машинное обучение с учетом профилей :) Собственно, есть уже достаточно много работ в этом духе, но авторы страдают из-за того, что крутилок-вертелок модуль заднего плана предоставляет слишком мало :)
Тут на самом деле есть опасность что пользователь отстрелит себе ногу. Например, в ядре очень любят ставить какой-нибудь force-inline, а в итоге размер процедуры после выполнения цепочки таких подстановок разбухнет до неимоверных размеров и станет только хуже. Тоже самое и с другими параметрами. Особенно плохо если под конкретную машину пользователь установил оптимальные эвристики, а для другой не поменял Makefile. Так что это палка о двух концах
источник

PS

Peter Sovietov in Compiler Development
Alex
Тут на самом деле есть опасность что пользователь отстрелит себе ногу. Например, в ядре очень любят ставить какой-нибудь force-inline, а в итоге размер процедуры после выполнения цепочки таких подстановок разбухнет до неимоверных размеров и станет только хуже. Тоже самое и с другими параметрами. Особенно плохо если под конкретную машину пользователь установил оптимальные эвристики, а для другой не поменял Makefile. Так что это палка о двух концах
Но я под пользователем подразумевал разработчика компилятора, который перенацеливает готовый модуль заднего плана на новую архитектуру. Для конечного пользователя должно быть доступно всего несколько конфигураций, заранее синтезированных (в течение часов или даже дней self-tuning'а).
источник

A

Alex in Compiler Development
Peter Sovietov
Но я под пользователем подразумевал разработчика компилятора, который перенацеливает готовый модуль заднего плана на новую архитектуру. Для конечного пользователя должно быть доступно всего несколько конфигураций, заранее синтезированных (в течение часов или даже дней self-tuning'а).
А, в этом смысле - да, для портирования придётся попотеть и понаписать ifdef'ов или понаделать своих ручек. Тут как бы понятно что человек, который пишет заднюю часть под одну машину не может предвидеть что потребуется поменять в другой машине. В плане задней (да и передней тоже) части для целевых машин - либо универсальный компилятор, либо быстрый код на выходе
источник

KR

K R in Compiler Development
Alex
Тут на самом деле есть опасность что пользователь отстрелит себе ногу. Например, в ядре очень любят ставить какой-нибудь force-inline, а в итоге размер процедуры после выполнения цепочки таких подстановок разбухнет до неимоверных размеров и станет только хуже. Тоже самое и с другими параметрами. Особенно плохо если под конкретную машину пользователь установил оптимальные эвристики, а для другой не поменял Makefile. Так что это палка о двух концах
Правильно ли я понимаю, что тут работает такой эффект:

1. Мы выполняем процедуру А, в которую собратно всё на свете, плюс, в ней есть некоторое количество ветвлений.

2. "Мёртвый в данный момент" код, который не будет выполнен на этом вызове, прокачивается через кэш, и вымывает рабочий код/данные (в зависимости от типа кэша)

Соответсвенно, если бы вместо inline остались бы вызовы, то этот "мёртвый в данный момент" код не был бы подгружен и не портил кэш?
источник

A

Alex in Compiler Development
K R
Правильно ли я понимаю, что тут работает такой эффект:

1. Мы выполняем процедуру А, в которую собратно всё на свете, плюс, в ней есть некоторое количество ветвлений.

2. "Мёртвый в данный момент" код, который не будет выполнен на этом вызове, прокачивается через кэш, и вымывает рабочий код/данные (в зависимости от типа кэша)

Соответсвенно, если бы вместо inline остались бы вызовы, то этот "мёртвый в данный момент" код не был бы подгружен и не портил кэш?
Как вариант. Может быть (даже чаще) сценарий вида: у нас в процедуре после всех подстановок гнездо циклов глубиной >30, в процедуре 100К операций, оптимизации просто не могут провести анализ и что-либо сделать.
источник

A

Alex in Compiler Development
Ещё вариант - компилятор сам делал бы подстановку по-другому с учётом того какие оптимизации будут применяться в будущем и достиг бы более оптимального кода. Но пользователь решил по-другому и получил упущенную производительность
источник

VM

Victor Miasnikov in Compiler Development
MaxGraey
Кстати а о каком Обероне идет речь? Об Oberon-07 (которому всего то 13 лет а то и меньше). Или Oberon-2?
Дм.Дагаев на OS Day 2019 о своих планах подробно рассказывал. На Хабре была статья.

О его компиляторах "из первых рук" можно почитать на forum.oberoncore.ru
источник

KR

K R in Compiler Development
Alex
Как вариант. Может быть (даже чаще) сценарий вида: у нас в процедуре после всех подстановок гнездо циклов глубиной >30, в процедуре 100К операций, оптимизации просто не могут провести анализ и что-либо сделать.
То есть, получается три варианта:

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

2. Сложное взаимодействией с внутренней логикой оптимизатора (это мне не очень понятно, как происходит).

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

Похоже?

Просто от агрессивного inline очень многие предостерегают. И мне, как человеку, который часто ocaml код компилирует с -inline 1000, хотелось бы разобраться, почему.
источник

AN

Alexander Nasonov in Compiler Development
K R
Правильно ли я понимаю, что тут работает такой эффект:

1. Мы выполняем процедуру А, в которую собратно всё на свете, плюс, в ней есть некоторое количество ветвлений.

2. "Мёртвый в данный момент" код, который не будет выполнен на этом вызове, прокачивается через кэш, и вымывает рабочий код/данные (в зависимости от типа кэша)

Соответсвенно, если бы вместо inline остались бы вызовы, то этот "мёртвый в данный момент" код не был бы подгружен и не портил кэш?
Тут я думаю, как минимум два эффекта: 1) мертвый код погружается частичными кешлайнами или префетчится немного, 2) весь код не помещается в маленькое количество страниц и увеличивает нагрузку на TLB.
источник

M

MaxGraey in Compiler Development
Victor Miasnikov
Дм.Дагаев на OS Day 2019 о своих планах подробно рассказывал. На Хабре была статья.

О его компиляторах "из первых рук" можно почитать на forum.oberoncore.ru
Я все равно не понию зачем выбирать Оберон? Какие у него преимущества по сравнению с современными ЯП? Цикл Дейкстры? Простой компилятор?
источник

M

MaxGraey in Compiler Development
При том что он весьма нишевой и стало быть информации мало, комьюнити небольшое, библиотек не много. Взять тот же непопулярный Dlang. Так там хотя бы есть нормальная интеграция со всеми современными БД, фреймворками и вообще более не менее нормальный FFI
источник

KR

K R in Compiler Development
Alexander Nasonov
Тут я думаю, как минимум два эффекта: 1) мертвый код погружается частичными кешлайнами или префетчится немного, 2) весь код не помещается в маленькое количество страниц и увеличивает нагрузку на TLB.
1) Это мы можем проверить, рассматривая эффект размера кэша.

2) А это - просто размер программы? (без отладочных символов)
источник

AN

Alexander Nasonov in Compiler Development
Ну да. 2) это размер не мёртвой части программы (то, что рантайм линковщик загружает как text).
источник

A

Alex in Compiler Development
K R
То есть, получается три варианта:

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

2. Сложное взаимодействией с внутренней логикой оптимизатора (это мне не очень понятно, как происходит).

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

Похоже?

Просто от агрессивного inline очень многие предостерегают. И мне, как человеку, который часто ocaml код компилирует с -inline 1000, хотелось бы разобраться, почему.
Да, похоже. Откопал тут публикацию по inline'у: https://ispranproceedings.elpub.ru/jour/article/view/922.

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

AN

Alexander Nasonov in Compiler Development
Ещё есть нетривиальный эффект на branch predictor. С одной стороны, инлайнинг множит бранчи и увеличивает нагрузку на branch predictor, а с другой стороны, каждое такое ветвление обычно проще, чем когда все идёт через вызов одной не инлайн функции.
источник

A

Alex in Compiler Development
> Просто от агрессивного inline очень многие предостерегают.

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