Генетическое программирование для тестирования компилятора: опыт аспиранта ML-лаборатории ИТМО

Виктор Петухов, студент второго курса аспирантуры Университета ИТМО и техлид в одной из команд проекта Kotlin в JetBrains (занимается компилятором Kotlin), решил совместить работу с детальным изучением профессиональной проблематики в научном формате и присоединился к лаборатории машинного обучения ИТМО. Рассказываем, что из этого получилось.

Фотография Marc Reichelt / Unsplash.comФотография Marc Reichelt / Unsplash.com

История вопроса

Языки программирования — фундамент огромного спектра продуктов, сервисов и критически значимой инфраструктуры. В своей научной статье по этой теме Виктор подчеркивает, что ошибки в коде компиляторов действительно могут привести к существенным последствиям. Однако количество всевозможных тестовых сценариев для них обычно крайне велико, поэтому составлять их приходится с привлечением интеллекта — человеческого или «искусственного», чтобы должным образом исследовать наиболее подверженные ошибкам части компилятора.

Но автоматическое составление таких тестов обладает ограничениями. Как правило, мы тяготеем к генерированию семантически корректных фрагментов кода, минуя парсер (самую простую часть компилятора) и пробираясь к самым сложными частям: подсистеме вывода типов, механизму разрешения вызовов и прочим. Если использовать для этого формальную модель, такую как грамматику, доля получаемых семантически корректных фрагментов кода будет слишком мала.

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

Задача попутной оптимизации характеристики производительности при генерации кода является не простым дополнением к произвольной генерации. На данный момент над этой проблемой работает не так много специалистов, поэтому Виктор увидел здесь возможность для развития профессиональных и научных компетенций — решил предложить такой способ генерации исходного кода на Kotlin, чтобы «либо время компиляции, либо потребляемая память были максимальными».

Как это работает

Использование генетического программирования для тестирования производительности компилятора подразумевает, что с каждой новой генерацией кода осуществляется оптимизация некоторого целевого параметра — например, использованной памяти.

Генератор кода, в свою очередь, также должен обеспечивать как можно большую долю семантически корректных фрагментов. Для этого Виктор — вместе с коллегами — разработал генератор с оператором скрещивания, который учитывает типы доступных переменных.

Пример скрещивания фрагментов исходного кода с учетом типовПример скрещивания фрагментов исходного кода с учетом типов

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

В ходе эксперимента были обнаружены некоторые проблемы в производительности компилятора Kotlin — например, экспоненциальный рост времени анализа лямбд в правой части оператора »+=» по мере увеличения глубины вложенности этих лямбд. Команда компилятора уже занимается этой проблемой. На скриншоте далее — показываем, как изменяется время компиляции приведенного фрагмента кода, если добавлять вложенные лямбды.

Пример точечной проблемы, которую удалось обнаружитьПример точечной проблемы, которую удалось обнаружить

Что дальше

Сейчас проектом занимаются пять человек. Это — коллективный труд исследователей Университета ИТМО и представителей JetBrains. Коллеги убеждены в целесообразности продолжения исследования и совершенствования предложенного Виктором подхода.

«Мы хотели бы реализовать и оператор мутации, чтобы избавиться от предвзятости относительно начального набора данных и генерировать принципиально новые конструкции языка. Помимо генетического программирования мы планируем применить здесь и генеративные модели, а затем провести сравнение результатов и подумать о разработке методологии тестирования производительности компиляторов»

— Виктор Петухов, аспирант второго года обучения, программист — на факультете ИТ и программирования, программист в JetBrains и в команде компилятора Kotlin.

Дополнительное чтение в нашем блоге на Хабре:

© Habrahabr.ru