PHP JIT

PHP JIT

Just In Time

Несмотря на то, что JIT может не предлагать каких-либо существенных краткосрочных улучшений, нужно понимать, что он откроет множество возможностей для роста PHP как в качестве веб-языка, так и в качестве языка общего назначения

Что такое JIT? JIT - это Just In Time, или просто компиляция "на лету", вы вероятно знаете, что PHP является интерпретируемым языком, он не компилирует программы в прямом смысле этого значения, как, например это делают C, Haskell, Go или Rust. 

PHP реализован на базе виртуальной машины (Zend VM). Язык компилирует исходный PHP-код в инструкции, которые понимает виртуальная машина (это называется стадией компиляции). Полученные на стадии компиляции инструкции виртуальной машины называются опкоды (opcodes). На стадии исполнения (runtime) Zend VM исполняет опкоды, выполняя тем самым требуемую работу. Операционные коды довольно низкоуровневые, поэтому их гораздо быстрее преобразовать в машинный код, чем в исходный код PHP. В ядре PHP есть расширение OPcache для кэширования этих кодов операций.

«Just In Time» - это стратегия компилятора, при которой, во время выполнения приложения, компилируются части кода, так что вместо интерпретирования каждый раз, можно всегда использовать скомпилированную версию.

Это можно представить себе как «кэшированную версию» интерпретируемого кода, сгенерированного во время выполнения. 

В PHP это означает, что JIT будет рассматривать полученные на стадии компиляции инструкции для виртуальной машины как промежуточное представление и выдавать машинный код, который будет выполняться уже не Zend VM, а непосредственно процессором.

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

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

Эти горячие части могут быть скомпилированы как оптимизированный машинный код и использоваться на лету, в нужный момент, вместо реального кода. Конечно на самом деле все гораздо сложнее, если вы хотите узнать больше, вы можете чекнуть ускоренный курс Mozilla в JIT-компиляторах.

Для этого поста в блоге достаточно понять, что JIT-компилятор может значительно улучшить производительность вашей программы...ну или нет :))

Зеев Сураски, один из разработчиков ядра PHP, недавно продемонстрировал демо с генерацией фракталов:


Необычно для PHP, не правда ли? "Слон в комнате": Часто ли вы видели, чтобы PHP использу для создания фрактальных анимаций :)))

Зная, что JIT-компилятор пытается идентифицировать «горячие» части вашего кода, вы можете догадаться, почему он оказывает такое влияние на фрактальный пример: множество одних и тех же вычислений происходит снова и снова.

Однако, поскольку PHP чаще всего используется при создании веб-приложений, мы также должны измерить влияние JIT именно на эту область.

А оказывается, что во время обработки веб-запроса кода гораздо меньше. Это не означает, что JIT вообще не может улучшить производительность сети, но мы уже не увидим подобных улучшений, как в случае с фрактальным примером. Дело в том, что в большинстве случаев PHP-приложения ограничены по вводу-выводу (I/O bound, обработка сетевых соединений, чтение и запись файлов, обращение к СУБД, кэширование и т.п.), а JIT лучше всего работает с кодом, который ограничен по процессору (CPU bound).

Это причина, чтобы отказаться от JIT? Точно нет! Есть веские аргументы, чтобы добавить его, хотя это может и не оказать должного влияния на производительность, на которую мы все же надеемся.

JIT открывает возможности для использования PHP как очень производительного языка вне области веб.

Это достаточно веские аргументы в пользу JIT. К сожалению, есть аргументы и против JIT:

- Сложность в обслуживании

Поскольку JIT генерирует машинный код, вы можете представить его как достаточно сложный материал для понимания «программистом языка более высокого уровня».

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

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

Так вот, на сегодняшний день, лишь несколько человек могут поддерживать такую ​​кодовую базу, поэтому вопрос о том, можно ли поддерживать компилятор JIT должным образом, кажется оправданным.

Конечно, люди могут узнать, как работает компилятор. Но это все же сложный материал. Прямо сейчас он насчитывает около 50+ тысяч строк кода. И обратите внимание: это не обычная база кодов клиент-веб-приложение. Это почти-так-же-близко-как-программирования-CPU .

Опять же, это не должно быть причиной отказа от JIT, но стоимость обслуживания должна быть тщательно продумана.

Стоит упомянуть еще одну деталь:

Кроссплатформенность. Начиная с последних версий, JIT также работает в Windows и Mac! Большой шаг вперед.

Так и зачем нам это?

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

Конечно не будучи экспертом в этой области, все это кажется очень сложным, но очень интересно видеть как такие вещи движутся в мире PHP. Мне очень любопытно, куда этот путь приведет. Это может сделать PHP более жизнеспособным выбором для таких ресурсоемких процессов, как, например, машинное обучение, 3D-рендеринг, 2D (графический интерфейс) и анализ данных, и это лишь некоторые из них.

JIT безопасность

JIT скомпилирует коды операций в машинный код и выполнит их. Все это находится в памяти. Проблема заключается в том, что по соображениям безопасности память должна быть доступна либо для записи, либо для исполнения (W ^ X). Но никогда не одновременно.

Текущая реализация PHP  отключает запись в буфер JIT  во время выполнения, используя системный вызов mprotect(). Это означает, что он скомпилирует код, запишет его в память и защитит его, чтобы сделать его недоступным для записи во время выполнения, предотвращая всевозможные эксплойты.

В настоящее время есть 2 основных расширения PHP, которые нарушают принцип W ^ X. Phar и PCRE JIT. Но новый PHP JIT в opcache с самого начала учитывает W ^ X, что очень радует.

Проверка текущей версии JIT на OpenBSD 6.0, в которой по умолчанию включен W ^ X, показывает, что все работает нормально. Нарушений нет. Обратите внимание, что SELinux (Security-Enhanced Linux) также включает такие виды защиты.



Ну и последнее, в JIT RFC было предложено включить JIT в PHP 8, а также добавить экспериментальную версию в PHP 7.4. К сожалению или счастью, RFC прошел только для PHP 8, но не для версии 7.4. Это означает, что нам придется подождать до PHP 8, прежде чем мы сможем опробовать его на реальных проектах. Конечно, вы можете скомпилировать PHP 8 из исходного кода, если хочется "пощупать" его уже сейчас.

Сергей Мухин

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

Есть вопросы?

Я почти всегда в режиме онлайн

Связаться со мной