Size: a a a

Compiler Development

2020 March 10

M

MaxGraey in Compiler Development
Александр Вольнов
Я рассматриваю генерацию кода именно для увеличения производительности как альтернатива интерпретации.
Может дешевле и проще будет просто цикл на JS сгенерировать, о чём я писал выше. Просто я не знаю, насколько там большой оверхед кучи wasm модулей на пол-килобайта. Если там на каждый модуль отдельный тяжёлый инстанс ВМ создаётся, то конечно лучше уж тогда JS генерить.
> Я рассматриваю генерацию кода именно для увеличения производительности как альтернатива интерпретации.

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

M

MaxGraey in Compiler Development
> Если там на каждый модуль отдельный тяжёлый инстанс ВМ создаётся, то конечно лучше уж тогда JS генерить.

Инстансы (по крайней мере в браузере) довольно тяжелые да. А еще в том же хроме они текут по памяти
источник

АВ

Александр Вольнов in Compiler Development
MaxGraey
> Я рассматриваю генерацию кода именно для увеличения производительности как альтернатива интерпретации.

Таким способом ты только угробишь производительность. И потом допустим память и таблицы вызовов ты можешь расшарить для этих модулей, а вот датасекцию и глобальные переменные уже будет проблиматично - придется это каждый раз прокидывать в каждый модуль и обновлять. Ну и по памяти. Каждлый модуль потребляет некоторое колличестко памяти для того же сендбокса, секций и т д. А так же тебе же нужно будет пройтись по всем этим модулям и вызвать их, верно? Ты это будешь делать на стороне хоста скорее всего и вот тут неожиданность - интероп зачастую очень медленный
Допустим у меня будет в маленьком модуле будет тупо самодостаточный цикл, которому не нужны никакие функции, глобальные переменные и так далее. В эту функцию просто будут передаваться указатели на данные, которые надо обработать.
Мне по идее надо будет вызвать функцию один, может пару раз, чтобы сразу обработать большой массив данных, так что может это покроет оверхед.
Но идея генерить JS мне больше нравится. Какой там оверхед с вызовом JS из wasm?
источник

M

MaxGraey in Compiler Development
Александр Вольнов
Допустим у меня будет в маленьком модуле будет тупо самодостаточный цикл, которому не нужны никакие функции, глобальные переменные и так далее. В эту функцию просто будут передаваться указатели на данные, которые надо обработать.
Мне по идее надо будет вызвать функцию один, может пару раз, чтобы сразу обработать большой массив данных, так что может это покроет оверхед.
Но идея генерить JS мне больше нравится. Какой там оверхед с вызовом JS из wasm?
Оверхед сильно зависит от рантайма (браузера) а так же от того какой тип данных ты гоняешь, например функции с нативными типами i32, i64, f32, f64 будут относительно быстро вызываться, если там будут строки, объекты, массивы, которые нужно уже через линейную память гонять - до тут ситуацию совершенно другая
источник

M

MaxGraey in Compiler Development
Александр Вольнов
Допустим у меня будет в маленьком модуле будет тупо самодостаточный цикл, которому не нужны никакие функции, глобальные переменные и так далее. В эту функцию просто будут передаваться указатели на данные, которые надо обработать.
Мне по идее надо будет вызвать функцию один, может пару раз, чтобы сразу обработать большой массив данных, так что может это покроет оверхед.
Но идея генерить JS мне больше нравится. Какой там оверхед с вызовом JS из wasm?
Если пару раз, то тут JIT не нужен. JIT имеет смысл только когда ты сотни и тысячи раз вызываешь
источник

AK

Andrei Kurosh in Compiler Development
Александр Вольнов
В любом случае, сделать самому без посредников типа CLR можно оптимальнее, так как контроля больше. Придётся конечно повозиться с кодогенерацией под разные архитектуры. Зато будет лёгкий рантайм, который можно запускать на любой платформе, не таская тяжёлый дотнет. Даже под WebAssembly собрать. Правда я пока не знаю, можно ли там будет JIT организовать.
Рантайм дотнета не очень большой (судя по Blazor - единицы мегабайт) и в него вложено на порядки больше человеко-часов, чем энтузиаст может вложить в свой проект, поэтому насчет того, что в конечном итоге получится "оптимальнее" для общего случая я сильно сомневаюсь
источник

АВ

Александр Вольнов in Compiler Development
MaxGraey
Оверхед сильно зависит от рантайма (браузера) а так же от того какой тип данных ты гоняешь, например функции с нативными типами i32, i64, f32, f64 будут относительно быстро вызываться, если там будут строки, объекты, массивы, которые нужно уже через линейную память гонять - до тут ситуацию совершенно другая
Я рассматриваю только нативные типы. То есть если код будет работать со строками, то только в виде байтов в памяти Wasm-модуля. По сути на ARM/x86 будет генерироваться машинный код, а под браузер - низкоуровневый JS.
источник

M

MaxGraey in Compiler Development
Александр Вольнов
Допустим у меня будет в маленьком модуле будет тупо самодостаточный цикл, которому не нужны никакие функции, глобальные переменные и так далее. В эту функцию просто будут передаваться указатели на данные, которые надо обработать.
Мне по идее надо будет вызвать функцию один, может пару раз, чтобы сразу обработать большой массив данных, так что может это покроет оверхед.
Но идея генерить JS мне больше нравится. Какой там оверхед с вызовом JS из wasm?
Ну и для JIT-а тебе нужен будет все равно интерпретатор, Иначе как ты собираешься профиль составлять?
источник

АВ

Александр Вольнов in Compiler Development
MaxGraey
Если пару раз, то тут JIT не нужен. JIT имеет смысл только когда ты сотни и тысячи раз вызываешь
Нужен, потому что сама функция будет делать много. В ней будет цикл на тысячи-миллионы итераций.
источник

АВ

Александр Вольнов in Compiler Development
MaxGraey
Ну и для JIT-а тебе нужен будет все равно интерпретатор, Иначе как ты собираешься профиль составлять?
Я свой язык делаю, естественно первым делом там будет интерпретатор. А сейчас я просто заранее продумываю, как я буду всё оптимизировать через JIT под разные платформы.
источник

M

MaxGraey in Compiler Development
Это могло бы выглядеть так:
1) Сначала работает интерпретатор скомпилированный в wasm, который составляет статистический профиль что как должно инлайниться, девиртуализироваться и т д,
2) Дальше по всем этм данным собирается в фоне wasm модуль
3) Который потом инстанциируется и в режиме hot-spot заменяет интерпретатор

Естественно без деоптимизаций, только однонаправленная 2-х этапная архитектура
источник

АВ

Александр Вольнов in Compiler Development
Andrei Kurosh
Рантайм дотнета не очень большой (судя по Blazor - единицы мегабайт) и в него вложено на порядки больше человеко-часов, чем энтузиаст может вложить в свой проект, поэтому насчет того, что в конечном итоге получится "оптимальнее" для общего случая я сильно сомневаюсь
Я делаю свой интерпретируемый язык со своей VM и не имеющий ничего общего с .NET. Можно только некоторые отдельные операции оптимизировать через JIT. Так что Blazor тут вообще ни при чём.
источник

M

MaxGraey in Compiler Development
Andrei Kurosh
Рантайм дотнета не очень большой (судя по Blazor - единицы мегабайт) и в него вложено на порядки больше человеко-часов, чем энтузиаст может вложить в свой проект, поэтому насчет того, что в конечном итоге получится "оптимальнее" для общего случая я сильно сомневаюсь
Не очень большой это пару килобайт, а пару мегабайт - это весьма здоровый рантайм я бы сказал
источник

AK

Andrei Kurosh in Compiler Development
MaxGraey
Не очень большой это пару килобайт, а пару мегабайт - это весьма здоровый рантайм я бы сказал
Сомневаюсь что реально утолкать в пару килобайт JIT, GC и стандартную библиотеку
источник

M

MaxGraey in Compiler Development
Andrei Kurosh
Сомневаюсь что реально утолкать в пару килобайт JIT, GC и стандартную библиотеку
Ну вот в AssemblyScript и TinyGo как то умудрились ;)
источник

АВ

Александр Вольнов in Compiler Development
MaxGraey
Это могло бы выглядеть так:
1) Сначала работает интерпретатор скомпилированный в wasm, который составляет статистический профиль что как должно инлайниться, девиртуализироваться и т д,
2) Дальше по всем этм данным собирается в фоне wasm модуль
3) Который потом инстанциируется и в режиме hot-spot заменяет интерпретатор

Естественно без деоптимизаций, только однонаправленная 2-х этапная архитектура
А этот wasm модуль отдельный? То есть его интеропом дёргать придётся? Или можно как-то в основной модуль добавить скомпилированные функции?
источник

M

MaxGraey in Compiler Development
Александр Вольнов
А этот wasm модуль отдельный? То есть его интеропом дёргать придётся? Или можно как-то в основной модуль добавить скомпилированные функции?
Это отдельный единственный модуль да. Просто он генериться динамически исходя из информации полученной от интерпретаптора. Такой себе PGO
источник

M

MaxGraey in Compiler Development
В таком виде это еще может существовать
источник

AK

Andrei Kurosh in Compiler Development
MaxGraey
Ну вот в AssemblyScript и TinyGo как то умудрились ;)
эээ, я почему-то думал, что JIT и стандартная библиотека в AssemblyScript предоставляются рантаймом WASM, а GC там вообще нет - или я не прав?
источник

M

MaxGraey in Compiler Development
Andrei Kurosh
эээ, я почему-то думал, что JIT и стандартная библиотека в AssemblyScript предоставляются рантаймом WASM, а GC там вообще нет - или я не прав?
Абсолютно не верно) Во первых я не раз уже выкладывал сюда пейпер по которому мы делали GC. Точнее там гибрид ARC и GC
источник