-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Недостаточная глубина оптимизации при поочерёдном выполнении прогонки и специализации #263
Comments
Первый вариант решения с повторной специализацией специализируемых функций — некрасивый по сравнению с двумя последующими. Поэтому он отбрасывается. Остальные два похожие, разница только в том, где будет располагаться цикл. Ориентироваться будем сначала на второй вариант (оба цикла в На верхнем уровне оптимизации дерева ( Проходы специализации заменяют вызовы на другие вызовы, причём порядок вызовов в своих аргументах они не меняют. А значит, они «невидимы» для прогонщика. Действительно, вызов Поэтому все проходы специализации можно передвинуть в самый конец. Далее — все специализируемые вызовы функции могут оптимизироваться за один проход, достаточно синтаксическое дерево обойти один раз. Поэтому и предлагается такая схема: несколько проходов прогонки, один проход специализации. «Температура» функций нужна только прогонщику. Если в предложении есть несколько прогоняемых вызовов, разделяющих общие переменные, то прогонка одного может повлиять на аргументы другого вызова, а значит, его тоже нужно будет повторно прогнать. Именно это и обуславливает необходимость нескольких проходов прогонки: нужно помечать вызовы, которые оптимизировать уже не надо, но «подогревать», если у них поменялся аргумент. Специализатору «температура» по этой причине не нужна. Если вызов не удалось специализировать, на повторных проходах он уже не изменится. Достаточно просто обойти все вызовы в дереве снизу вверх — если это вызов специализируемой функции, оптимизировать, если нет — не трогать. Поэтому «температуру» нужно перенести в проход прогонки. Из специализатора логику температуры можно просто выкинуть. Вообще, разметка вызовов в Вместо «температуры» вызовов потребуется другая логика. После необходимого числа вызовов прогонки и вызова специализации функция уже не может измениться. Ни прогонка, ни специализация ни к одному из таких вызовов применима не будет. Следовательно, для ускорения работы можно помечать «холодными» такие функции целиком. Пометка будет осуществляться в специализаторе, учитываться и в специализаторе, и в прогонщике. |
Собственно, пример из issue теперь оптимизируется правильно. Однако, корректировка внесена минимальными правками, обеспечивающими новое поведение. Осталась масса костылей, вроде холодных вызовов в специализаторе. Удаление костылей будет вынесено в отдельные коммиты, дабы упростить понимание истории. Специализатор теперь оптимизирует дерево за один проход снизу вверх. Однако, «холодные» определения функций пока не поддерживаются.
ПроизводительностьБыли сделаны три замера производительности: до первого коммита по этой заявке (96fb33e), после предпоследнего коммита (8e38460) и после последнего (a5b0b5b). Замер выполнялся стандартным бенчмарком, с ключами компиляции Результаты: |
Задача блокирует задачи #260, #252, #253.
Проблема
Рассмотрим следующую программу:
Функция
S
может специализироваться по первому и последнему терму. ФункцияD
сужает переменнуюs.X
, которая входит в аргументS
. Рассмотрим построенное оптимизированное дерево:Функция
S
могла бы быть проспециализирована по символамA
иB
, в которые обращаетсяs.X
в ходе прогонки.Уберём вызов
<I>
из функцииTest
:Оптимизированное дерево:
Вызов
S
проспециализирован полностью. Почему так вышло?Потому что прогонка и специализация выполняются поочерёдно. Причём прогонка за один проход оптимизирует по одному вызову в каждом предложении.
(Примечание: специализация за один проход обрабатывает все пригодные вызовы функций — вызовы функций с холодными аргументами.)
В первом случае проход прогонки встроил
<I>
, затем проход специализации инстанцировалS@1
для сигнатурыs.X
←t.X
,1
←t.Z
, затем выполнилась прогонка<D s.X>
. ФункцияS@1
не специализируемая, уточнение её аргумента никак не помогло.Во втором случае сначала выполнилась прогонка
<D s.X>
, потом специализация вызоваS
, что дало три оптимизированных экземпляраS@1
,S@2
,S@3
.Решение
Повторно специализировать функции
Func@N
Этот вариант напоминает повторную прогонку
Func*N
.При построении
Func@N
компилятор помечает новую функцию как специализируемую, статическими параметрами становятся переменные из статических параметров функцииFunc
.Преимущество:
OptTree.ref
, достаточно правок внутриOptTree-Spec.ref
. Благодаря этому задача не конфликтует с задачей рефакторинга оптимизации Рефакторинг архитектуры древесного оптимизатора #259.Недостаток:
Выполнять специализацию для неподвижной точки прогонки
Имеется ввиду следующее: выполнять проходы прогонки до неподвижной точки, затем проход специализации, затем снова прогонку до неподвижной точки и т.д. Сам внешний цикл также крутится до неподвижной точки.
Иначе говоря, оптимизацию можно описать примерно таким псевдокодом:
Преимущества:
OptTree-Drive.ref
иOptTree-Spec.ref
.Можно заметить, что после проходов прогонки до неподвижной точки и прохода специализации функция уже не может измениться. А значит, после специализации можно выполнять прогонку только вновь инстанцированных функций. Это снизит сложность оптимизации с квадратичной до линейной.Если не менять подход к разморозке, то функция может измениться. Рассмотрим выражение
<I1 <S2 <I3 …>>>
. ВызовI1
блокирован тёплым вызовом функцииS2
, поэтому неподвижная точка прогонки будет лишь раскрытием вызоваI3
. Затем, после специализацииS2
аргументI1
станет холодным, что разрешит её встраивание.Но специализация заменяет вызов на вызов, причём она не меняет порядок вложенных вызовов в аргументе. Поэтому на стадии прогонки можно вообще забыть о специализируемых функциях — считать непрогоняемые функции по умолчанию холодными. Но вообще, это тема рефакторинга Рефакторинг архитектуры древесного оптимизатора #259.
Недостаток:
Проход прогонки сам возвращает неподвижную точку
Вариант аналогичен предыдущему с той лишь разницей, что внутренний цикл переносится в
OptTree-Drive.ref
.Преимущества:
OptTree-Spec.ref
.Недостатки:
OptTree.ref
. Так что изменения не будут локализованы в одном файле.Что же выбрать?
Первый вариант выглядит корявее других. Два других противоречат задаче рефакторинга древесной оптимизации #259. А это значит, что рефакторинг нужно будет делать каким-то иным путём (но делать нужно).
The text was updated successfully, but these errors were encountered: