Skip to content
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

Глобальная оптимизация #255

Closed
Mazdaywik opened this issue Aug 6, 2019 · 2 comments
Closed

Глобальная оптимизация #255

Mazdaywik opened this issue Aug 6, 2019 · 2 comments
Assignees
Labels

Comments

@Mazdaywik
Copy link
Member

Mazdaywik commented Aug 6, 2019

Мотивация

Глубокая оптимизация программ на классическом Рефале-5. Точка.

В Рефале-5λ, чтобы задействовать оптимизируемую функцию в нескольких единицах трансляции, её нужно вынести в заголовочный файл и подключать его в каждый исходник (#92).

В классическом Рефале-5 такого механизма нет. Поэтому, при условии реализации #252, компилятор сможет оптимизировать только функции внутри одной единицы трансляции.

Реализация

Оптимизация должна включаться опцией -OG.

Принцип работы: синтаксические деревья различных единиц трансляции (до или после обессахаривания) объединяются в одну кучу и падают на оптимизатор дерева. Для избежания конфликтов между локальными функциями предлагается использовать декорирование имён: к локальным функциям первой единицы трансляции добавляется ~1, второй — ~2 и т.д. Это актуально для Рефала-5λ, поскольку многие модули содержат $INCLUDE "LibraryEx";

Детали:

  • Единицы трансляции с нативными вставками в глобальной оптимизации для простоты не участвуют. Потому что в них может находиться код на Си, который ожидает, что он транслируется отдельно. Обходные пути придумать, конечно, можно, но базовый вариант — такие файлы транслируются отдельно.
  • Функция Mu должна быть локальной для каждой единицы трансляции и при поиске имени не учитывать суффикс ~N. Надо перепроектировать Mu для этой цели (Новая реализация метафункций (Mu, Residue, Up, Ev-met) #254).
  • Рефал-5λ активно использует $INCLUDE "LibraryEx";, соответственно, будут повторяющиеся функции. Стоит ли выявлять и устранять дубликаты? Хотя дублироваться будут функции, которые и так оптимизируются (встраиваются/специализируются). Заметим, что при реализации Использовать Mu в функциях высших порядков в LibraryEx #181 функции, вызывающие Apply дублироваться не будут, поскольку они будут вызывать разные Mu.
  • (добавлено) При конкатенации синтаксических деревьев возможно выявление ошибки дублирования entry-функций. Без конкатенации эта ошибка выявляется только при загрузке (Компоновщик должен сообщать о дублировании entry-функций #265), а так она будет выявляться при компиляции. Чтобы выдавать адекватное сообщение об ошибке во время компиляции, объединение деревьев нужно выполнять до рассахаривания.
@Mazdaywik Mazdaywik added the task label Aug 6, 2019
@Mazdaywik Mazdaywik self-assigned this Aug 6, 2019
Mazdaywik added a commit that referenced this issue May 5, 2020
Имена функций с меткой (Spec …) в дереве могут иметь суффиксы. На данный
момент это совершенно нейтральное изменение, никакими входными данными его
выявить невозможно, поэтому с полным основанием оно является рефакторингом.

Но это исправление нужно сразу нескольким задачам:

• Вложенные функции (включая присваивания и блоки) неявно преобразуются
  в обычные глобальные функции с суффиксами. Задача #160 требует
  их специализировать.
• В задаче #252 предлагается автоматически размечать функции, пригодные
  для оптимизации (включая специализацию). Размечатель будет работать
  как с входным деревом до оптимизации, так и с оптимизированным деревом
  после оптимизаций. Пригодными для оптимизации могут быть и функции
  с суффиксами.
• При глобальной оптимизации (#255) синтаксические деревья разных единиц
  трансляции объединяются в одно, локальные функции в них переименовываются —
  получают суффиксы.
• В задаче #251 предлагается рассмотреть специализацию всех функций
  программы, включая функции с суффиксами.
• На это нет отдельной заявки (это часть #160), но имеет смысл разрешить
  одновременную прогонку и специализацию функций, пометку одной функции
  метками $DRIVE и $SPEC одновременно. В этом случае придётся
  специализировать и функции Func*n — остатки прогоняемых функций.

Ну и кроме того, это красиво: поддержка не частного случая, а общего.
@Mazdaywik
Copy link
Member Author

  • Объединение файлов имеет смысл делать до рассахаривания. Во-первых, суффикс ~n должен быть первым. Во-вторых, в Engine.ref есть функция обхода дерева. Её можно использовать для обновления имён локальных функций.
  • Семантическую проверку нужно наоборот делать до объединения, иначе будут пропускаться некоторые ошибки. Например, необъявленные функции.
  • Рассахариватель на входе должен ожидать функции с суффиксами.

@Mazdaywik
Copy link
Member Author

По-хорошему, эта заявка блокирует #252. Автоматическая разметка применима прежде всего к программам на классическом Рефале (где такой разметки нет), а в реальных программах оптимизируемые функции и точки их вызова разнесены по разным файлам. Например, в MSCP-A все кандидаты на прогонку собраны преимущественно в этом файле:

https://github.com/TonitaN/MSCP-A/blob/master/accessMSCP.ref

Mazdaywik added a commit that referenced this issue May 17, 2020
• FrontEnd и BackEnd сделаны внешними функциями, FrontEnd возвращает признак
  того, есть ли в дереве вставки нативного кода.
  Деревья с ними сливать нельзя.
• Создание метафункций перенесено во фронтэнд.
• Функция обхода дерева обобщена.
Mazdaywik added a commit that referenced this issue May 17, 2020
Всё работает и работает, как планируется. Почему базовая?

• Нет никакой возможности узнать, чему соответствует суффикс ~n.
• Написанный код в main.ref требует некоторого рефакторинга.
• Всплыло, что у компилятора есть квадратичная зависимость по времени
  от объёма входных данных.
Mazdaywik added a commit that referenced this issue May 17, 2020
Теперь он ещё и запускается с ключом -OG, когда сообщение об ошибке
выдаёт компилятор.
Mazdaywik added a commit that referenced this issue May 17, 2020
Глобальная оптимизация (#255) выявила участки кода, имеющие сверхлинейную
зависимость по времени от входных данных. Если при компиляции отдельных
небольших файлов проблемы заметны не были, то теперь, на конкатенации
всех деревьев они встали в полный рост.

Часть кода удалось оптимизировать, заменив Map на MapAccum,
и соответственно, передавать константное значение не как параметр,
а через аккумулятор:

• FilterDeclaration в Desugaring.ref,
• GenCommand-Globals в Generator-RASL.ref

А некоторые функции пришлось переписать явно в линейные. Или, вернее,
«прямоугольные» O(m×n) вместо «квадратных» O(max(m,n)²):

• Переписана борьба с дублированием новых функций в прогонщике. Вместо
  DistinctFuncs, которая содержала две открытые переменные, делается
  два прохода по синтаксическому дереву: на первом все новые функции
  извлекаются (тут же исключается их дублирование), на втором удаляются
  те, которые в дереве уже присутствуют.
• Переписан проход Pass-RemoveRedundantDriveInline в рассахаривателе.
  В нём ранее при помощи двойной открытой переменной обнаруживались
  парные (избыточные) метки Drive/Inline, функция вызывалась до тех пор,
  пока все избыточные пары не будут разрешены. Теперь делается два
  прохода по дереву: сначала все метки извлекаются, а потом они
  фильтруются. Преобразование является точным рефакторингом — позиции
  оставленных меток сохраняются.

Формальных замеров я не делал, но цикл самоприменения с ключами -X-ODGS
ускорился примерно в два раза (если не больше).
Mazdaywik added a commit that referenced this issue May 17, 2020
Для режима --scratch не возвращался список имён файлов.

Опция -OdG, и в особенности, -OdDGS потребовали повышения лимита — иначе
недоставало памяти.
Mazdaywik added a commit that referenced this issue May 17, 2020
Это имя конструируется из имени целевого файла путём прибавления .rasl.
А имя псевдоисходника, которое отображается в дампе (unit name),
конструируется путём добавления .GLOBALS.
Mazdaywik added a commit that referenced this issue May 17, 2020
Если включена опция -OG, генерируется файл %TARGET%-locals.lst, где
перечисляются суффиксы ~n, добавляемые к локальным функциям каждой
единицы трансляции. Скрипты сборки Рефала-5λ перемещают эти файлы (если
они есть) в соответствующие подпапки папки build.
Mazdaywik added a commit that referenced this issue May 20, 2020
Глобальная оптимизация (#255) выявила нелинейную сложность в этом участке кода.
Переменная контекста во избежание копирования была перенесена в аккумулятор.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant