Когда и где PyPy создает машинный код?

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

Иногда создается байт-код, иногда он пропускается для немедленной компиляции машинного кода (код уровня интерпретатора/уровня приложения), но я не могу понять, когда и где именно создается машинный код, который передается ОС для двоичного выполнения. через низкоуровневые инструкции (RAM/CPU).

Мне удалось это понять в случае CPython, поскольку в ceval.c есть гигантский переключатель, который уже скомпилирован, который интерпретирует байт-код и запускает соответствующий код (на самом деле на C). Имеет смысл.
Но что касается PyPy, мне не удалось получить четкое представление о том, как это делается, в частности (я не хочу вдаваться в различные детали оптимизации PyPy, я этим не занимаюсь). после здесь).

Я был бы удовлетворен ответом, указывающим на исходный код PYPY, поэтому, чтобы избежать слухов и иметь возможность увидеть его своими глазами (я заметил часть бэкэнда JIT в /rpython с различными сборщиками архитектур ЦП)


person Mehdi LAMRANI    schedule 30.08.2020    source источник


Ответы (1)


Лучшее руководство — это документация по архитектуре pypy, а также актуальная документация JIT.

Больше всего меня зацепило вот это:

у нас есть отслеживающий JIT, который отслеживает интерпретатор, написанный на RPython, а не пользовательскую программу, которую он интерпретирует.

Более подробно это описано в обзоре JIT.

Похоже, что ядро ​​​​это (от здесь):

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

Эта статья (PDF ) тоже может быть полезно.

Редактировать: Глядя на серверную часть x86 rpython/jit/backend/x86/rx86.py, серверная часть не столько компилирует, сколько напрямую выдает машинный код. Посмотрите на классы X86_64_CodeBuilder и AbstractX86CodeBuilder. На уровень выше находится Assembler386 класс в rpython/jit/backend/x86/assembler.py. Этот ассемблер использует MachineCodeBlockWrapper из rpython/jit/backend/x86/codebuf.py, который основан на X86_64_CodeBuilder для x86-64.

person Roland Smith    schedule 30.08.2020
comment
Спасибо. Я часами читаю одни и те же страницы, но до сих пор не могу уложиться в голове. У меня такое чувство, что точный и конкретный ответ, который я ищу, находится где-то между этими строками, но он кажется утонувшим в куче плотной информации. Я пошел по пути трассировки, но все, что он говорит, это то, что обнаруженные трассировки компилируются JIT (как и где в коде, кто знает...) - person Mehdi LAMRANI; 30.08.2020
comment
Спасибо за ваши правки. Хороший материал для просмотра. Похоже, что нет возможности углубиться в JIT-код. Но, по крайней мере, я знаю, где в коде сфабрикован настоящий машинный код. Очень проницательно. Мне было интересно, какой модуль на самом деле запускал/выполнял сгенерированный машинный код, если вы случайно не знаете... (сэкономил бы мне пару часов погружения, но я все равно этим занимаюсь) - person Mehdi LAMRANI; 31.08.2020
comment
Также было бы здорово иметь блок-схему пути выполнения в PyPy. Я просмотрел множество документов, но если не читать страницы и страницы объяснений, кажется, что нет одностраничной диаграммы, чтобы получить общую картину. - person Mehdi LAMRANI; 31.08.2020
comment
@MehdiLAMRANI Сгенерированный машинный код выполняется интерфейсом, но я не вникал в детали. В.р.т. блок-схему, вы можете попробовать запустить pypy через один из нескольких существующих модулей профилировщика, например. line-profiler. Это показало бы вам хотя бы поток кода. - person Roland Smith; 31.08.2020