ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
28 марта
1265026
Evgeny_CD, Архитектор (04.12.2022 02:04, просмотров: 107)
К вопросу о внутреннем устройстве ЯВУ. Частичный список базовых примитивов, используемых NQP из Raku. 

https://github.com/Raku/nqp/blob/master/docs/ops.markdown


NQP это хитрая штука в основе MoarVM - современной виртуальной машины Raku.

https://en.wikipedia.org/wiki/Raku_(programming_language)#Implementations


NQP является подмножеством языка Raku, на котором написаны инструкции по разбору кода на полном Raku, превращении его в AST и кодогенерации для целей прямого исполнении и интерпретации.


Когда мы пишем на ЯВУ, то мы мозгом программиста раскладываем целевую задачу по некоему базису примитивов, которые неким способом превращаются в эффективный код.


Хорошие ЯВУ, например, Lua, содержат очень компактную структуру базовых сущностей, которые можно удобно каскадировать.


Но когда мы переходим к эффективной кодогенерации, то нам нужно больше информации, чем заложено изначально в базовых примитивах.


Условно, вот класс, вот набор его методов, и вот набор его данных. Нам надо уметь группировать это хозяйство в кучки, чтобы адресация полей была одним индексным регистром + короткой константой прямо в опкоде, и вызовы методов аналогично. Уже на боле тонком уровне идет оптимизация регистров.


При этом публичные методы и поля должны иметь возможность прямой адресации из - вне.


Тогда аппаратуре будет проще. Обратились мы к первому полю класса - кеш-лайн закешировался.


Если попытаться построить граф расширенных примитивовов, в которых нужно представлять код для кодогенарации, то он будет адского размера. Программист с ума сойдет, если будет кодить такое руками.


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


Дальше уже проще. Если например, у нас интерпретатор, и мы закодили исполнение нескольких сотен расширенных примитивов, то мы можем сильно ускорить исполнение, просто параметризуя и вызывая нативный код, соответствующий данному набору расширенных параметров.


Это отчасти объясняет, как современный Python достиг достаточно высокого быстродействия на многих типовых задачах. Это не значит, что такое быстродействие будет всегда, но, условно, при обработке текста, что есть весьма массовая операция, скорость будет всего в несколько раз меньше нативного кода.

https://caxapa.ru/1264901.html


Одновременно это объясняет, почему просто так полную инфраструктуру для вновь придуманного языка, пусть и интерпретируемого, не так то и просто создать. Нужно очень много кодинга.

Тогда становится понятен облик правильного языка для embedded.


Речь идет о ЯВУ, где в базовых примитивах будут учены важные для RT исполнения вещи. И в дополнение - внутренний слой трансформации в расширенные примитивы будет заточен под эффективное использование существующих архитектур.


Я не про дурацкий спор "давайте выкинем С/С++ и заменим из на правильный ЯВУ". Есть объектный код, который при соблюдении calling convention и прочих стандартов архитектуры, который можно слинковать в готое приложение. А уже из чего этот obj родился - это дело десятое.


Все, вероятно, должно выглядеть так.


Вот кодер пишет низкоуровневый код на некоем С подобном языке. Код транслируется в AST, и визуализируется.


Тулчейн в этой визуализации показывает, как он собирается все это оптимизировать.


Программер может выдать свои рекомендации, описывая свой замысел.


В отличие от асма, получаеся гораздо понятнее.


Вот есть представление кода, в котором показано, что собственно, код делает. Без концентрации на размещении переменных и кода.


Есть лобовой интерпретатор кода, который позволят потестировать код, и, например в синтетическом порте, сделать первые оценки профилирования - что важно, что нет. Оптимизировать все подряд глупость - Кнут не дат соврать.


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


Тут самое время корректировать код верхнего уровня, чтобы втиснуть в какие-то выявленные оптимизатором возможности. Пересмотреть упаковку структур. Пересмотреть точки перехода и проч.


Некоторые пути оптимизации не очевидны. Делаем тупой перебор. Генерим бинарник под разные параметры оптимизации, и в симуляторе ISA прогоняем, бенчмарким его. Выбираем лучшее.


Для разных кусков кода стратегия оптимизации разная. Ну ок, разные obj будут.


Вот как-то так.