PHP 8: Как настроить JIT

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

PHP

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

Прежде всего, JIT будет работать, только если включен opcache, что является стандартом для большинства PHP, но вы должны убедиться, что opcache.enable установлен в 1 в вашем файлеphp.ini. Включение самого JIT осуществляется путем указания opcache.jit_buffer_size в php.ini.

Обратите внимание, что если вы запускаете PHP через командную строку, вы также можете передать эти опции через флаг -d, вместо того, чтобы добавлять их в php.ini:

Если эта директива исключена, значение по умолчанию будет равно 0, и JIT не будет запущен. Если вы тестируете JIT в сценарии CLI, вам нужно использовать opcache.enable_cli, чтобы включить opcache:

Разница между opcache.enable и opcache.enable_cli заключается в том, что первый вариант следует использовать, если вы используете, например, встроенный сервер PHP. Если же вы запускаете скрипт CLI, вам понадобится opcache.enable_cli.

Прежде чем продолжить, давайте убедимся, что JIT действительно работает, создадим PHP-скрипт, доступный через браузер или CLI (в зависимости от того, где вы тестируете JIT), и посмотрим на вывод opcache_get_status():

На выходе должно получиться что-то вроде этого:

Если значения enabled и on верны, вы готовы к работе!

Далее, есть несколько способов настроить JIT (и здесь мы попадем в путаницу конфигурации). Вы можете настроить, когда JIT должен запускаться, сколько он должен пытаться оптимизировать и т.д. Все эти параметры настраиваются с помощью одной (!) конфигурационной записи: opcache.jit. Она может выглядеть примерно так:

Итак, что означает это число? В RFC перечислены значения каждого из них. Имейте в виду: это не битовая маска, каждое число просто представляет другую опцию конфигурации. В RFC перечислены следующие параметры:

O - уровень оптимизации

  • 0 не использовать JIT
  • 1 минимальный JIT (вызов стандартных VM-обработчиков)
  • 2 выборочная инкрустация VM-обработчиков
  • 3 оптимизированный JIT, основанный на статическом определении типа отдельной функции
  • 4 оптимизированный JIT на основе статического определения типа и дерева вызовов
  • 5 оптимизированный JIT на основе статического определения типа и анализа внутренних процедур

T - JIT-триггер

  • 0 JIT все функции при первой загрузке скрипта
  • 1 JIT-функция при первом выполнении
  • 2 Профилирование по первому запросу и компиляция горячих функций по второму запросу
  • 3 Профилирование на лету и компиляция горячих функций
  • 4 Компиляция функций с тегом @jit в doc-комментариях
  • 5 Трассировка JIT

R - распределение регистров

  • 0 не выполнять распределение регистров
  • 1 использовать локальный распределитель регистров линейного сканирования
  • 2 использовать глобальный распределитель регистров линейного сканирования

C - флаги оптимизации для конкретного процессора

  • 0 нет
  • 1 включить генерацию инструкций AVX

Одна маленькая загвоздка: RFC перечисляет эти опции в обратном порядке, поэтому первая цифра представляет значение C, вторая - R, и так далее. Почему просто не было добавлено четыре конфигурационные записи, вероятно, чтобы сделать настройку JIT быстрее... верно?

В любом случае, internals предлагает 1255 в качестве лучшего по умолчанию, он будет делать максимальный джиттинг, использовать трассировку JIT, использовать глобальный распределитель регистров liner-scan - каким бы он ни был - и включает генерацию инструкций AVX.

Поэтому ваши ini-настройки (или флаги -d) должны иметь такие значения:

Помните, что opcache.jit является необязательным свойством. JIT будет использовать значение по умолчанию, если это свойство опущено.

Какое значение по умолчанию, спросите вы? Это opcache.jit=tracing.

Постойте, это не та странная структура, похожая на битмаску, которую мы видели ранее? Все верно: после того, как оригинальный RFC был принят, интерналы поняли, что опции, похожие на битовые маски, не слишком удобны для пользователя, поэтому они добавили два псевдонима, которые под капотом переводятся в битовые маски. Это opcache.jit=tracing и opcache.jit=function.

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

Таким образом, единственным параметром, который вам действительно нужно установить, чтобы включить JIT с его оптимальной конфигурацией, является opcache.jit_buffer_size, но если вы хотите быть явным, то перечислить opcache.jit будет не такой уж плохой идеей:

Понравилась статья? Поделиться с друзьями:
Добавить комментарий