Меня сегодня поймали и наконец-то рассказали, что такое MLIR: A Compiler Infrastructure for the End of Moore’s Law.
Мы привыкли, что в компиляторостроении выиграли компиляторы с промежуточными (intermediate) представлениями, это помогает унифицировать фронтенды и разговаривать с оптимизациями кода на одном языке (IR это отдельный язык), например, сделать умножение на два как сдвиг на один и так далее. После этого получается CPU бекенд, а так как CPU похожи, поэтому и так сойдёт. Даже нередко выходит так, что сами CPU являются заказчиками фичей в IR, потому что им так удобнее.
Но мы перестаём жить одним CPU, хочется делать какие-то другие бекенды, а вот для них уж классический IR не так подходит. Например, операция деления на GPU всегда будет эффективнее, если предпосчитать обратный, а вот с CPU такого наверняка не скажешь. А такие операции открывают большой спектр других возможностей для оптимизаций и так далее. Приходится писать свой IR, даже у того же Rust есть MIR, у Swift свой.
И Крис Латтнер задумался, а как развивать и расширять такой запрос. Здесь и родился MLIR, абстракция над всеми IR.
Вещь получается очень забавная, лучшая аналогия, которая мне пришла в голову это упрощенный пример с TensorFlow. Когда TF компилирует ваш граф, он может некоторые операции смёржить или лучше распараллелить их, и вообще если вы перемножаете матрицы, иногда это стоит делать в другом порядке, а можно ещё это делать на GPU/TPU/CPU. Но как это понять по только тому, как вы описали операции?
Можно сделать свой IR, где переменные будут операциями, и использовать инфраструктуру MLIR, какие-то очень базовые свойства вроде single static assignment и сотню интерфейсов по работе с этими переменными (удали, смёржи, переставь, замени и так далее).
То есть придётся написать свои оптимизации над графом, но использовать общую инфраструктуру, которая задокументирована, имеет фичи вроде автоматического тестирования, фаззинга, верификации, нахождении плохих примеров по верификации. А ещё дать пользователям какие-нибудь атрибуты, чтобы они лучше описывали, что их чёрные коробки делают, например, у функции нет side эффектов и тому подобное. Но лучше всего работает, конечно, с декларативными примерами, когда сами артифакты оптимизируются, а пользователи решают свои задачи с помощью этих артифактов.
Вот теперь сижу, думаю, как это затащить в pipeline execution Spark или Google Dataflow. Вроде даже ложится та же идея с графами! Да даже можно что-то более экзотичное как система сборки, где можно подсчитать как лучше мержить таргеты с кодом, которые стоит компилировать на одной машинке c заданными параметрами. Сейчас это всё делается своей инфрой, сложным кодом, а можно же унифицировано в LLVM и лучше инфрой. Ещё можно какие-то вещи у других подсматривать, как они делают. Красота.
Единственная непонятная для меня проблема пока, а что делать, если только понимаешь походу, что оптимизации были не очень, можно ли что-то другое попробовать, перекомпилировать, статически как-то всё выходит. MLIR JIT? Звучит, конечно, сочно.
В общем, называется, ушёл в отпуск, дошли руки до приятных вещей, которые откладывал.
[1] MLIR: A Compiler Infrastructure for the End of Moore’s Law
[2] Chris Lattner. MLIR, EuroLLVM
[3] MLIR Tutorial
[4] MLIR LLVM Page
[5] MLIR LLVM Repository
Мы привыкли, что в компиляторостроении выиграли компиляторы с промежуточными (intermediate) представлениями, это помогает унифицировать фронтенды и разговаривать с оптимизациями кода на одном языке (IR это отдельный язык), например, сделать умножение на два как сдвиг на один и так далее. После этого получается CPU бекенд, а так как CPU похожи, поэтому и так сойдёт. Даже нередко выходит так, что сами CPU являются заказчиками фичей в IR, потому что им так удобнее.
Но мы перестаём жить одним CPU, хочется делать какие-то другие бекенды, а вот для них уж классический IR не так подходит. Например, операция деления на GPU всегда будет эффективнее, если предпосчитать обратный, а вот с CPU такого наверняка не скажешь. А такие операции открывают большой спектр других возможностей для оптимизаций и так далее. Приходится писать свой IR, даже у того же Rust есть MIR, у Swift свой.
И Крис Латтнер задумался, а как развивать и расширять такой запрос. Здесь и родился MLIR, абстракция над всеми IR.
Вещь получается очень забавная, лучшая аналогия, которая мне пришла в голову это упрощенный пример с TensorFlow. Когда TF компилирует ваш граф, он может некоторые операции смёржить или лучше распараллелить их, и вообще если вы перемножаете матрицы, иногда это стоит делать в другом порядке, а можно ещё это делать на GPU/TPU/CPU. Но как это понять по только тому, как вы описали операции?
Можно сделать свой IR, где переменные будут операциями, и использовать инфраструктуру MLIR, какие-то очень базовые свойства вроде single static assignment и сотню интерфейсов по работе с этими переменными (удали, смёржи, переставь, замени и так далее).
То есть придётся написать свои оптимизации над графом, но использовать общую инфраструктуру, которая задокументирована, имеет фичи вроде автоматического тестирования, фаззинга, верификации, нахождении плохих примеров по верификации. А ещё дать пользователям какие-нибудь атрибуты, чтобы они лучше описывали, что их чёрные коробки делают, например, у функции нет side эффектов и тому подобное. Но лучше всего работает, конечно, с декларативными примерами, когда сами артифакты оптимизируются, а пользователи решают свои задачи с помощью этих артифактов.
Вот теперь сижу, думаю, как это затащить в pipeline execution Spark или Google Dataflow. Вроде даже ложится та же идея с графами! Да даже можно что-то более экзотичное как система сборки, где можно подсчитать как лучше мержить таргеты с кодом, которые стоит компилировать на одной машинке c заданными параметрами. Сейчас это всё делается своей инфрой, сложным кодом, а можно же унифицировано в LLVM и лучше инфрой. Ещё можно какие-то вещи у других подсматривать, как они делают. Красота.
Единственная непонятная для меня проблема пока, а что делать, если только понимаешь походу, что оптимизации были не очень, можно ли что-то другое попробовать, перекомпилировать, статически как-то всё выходит. MLIR JIT? Звучит, конечно, сочно.
В общем, называется, ушёл в отпуск, дошли руки до приятных вещей, которые откладывал.
[1] MLIR: A Compiler Infrastructure for the End of Moore’s Law
[2] Chris Lattner. MLIR, EuroLLVM
[3] MLIR Tutorial
[4] MLIR LLVM Page
[5] MLIR LLVM Repository