PHP 8 добавляет к ядру JIT-компилятор, который может значительно повысить производительность. Следует сделать несколько замечаний о фактическом влиянии на реальные веб-приложения.
Прежде всего, JIT будет работать только в том случае, если включен opcache
. Opcache
включен по умолчанию для большинства инсталляций PHP, но вы должны убедиться, что opcache.enable
имеет значение 1 в файле yourphp.ini
. Включение JIT осуществляется путем указания opcache.jit_buffer_size
в php.ini
Обратите внимание, что если вы запускаете PHP через командную строку, вы также можете передать эти параметры с помощью флага -d вместо добавления их в php.ini:
php -dopcache.enable = 1 -dopcache.jit_buffer_size = 100M
Если эта директива исключена, значение по умолчанию равно 0, то JIT не будет работать. Если вы тестируете JIT в сценарии CLI, вам нужно вместо этого использовать opcache.enable_cli
, чтобы включить opcache
:
php -dopcache.enable_cli = 1 -dopcache.jit_buffer_size = 100M
Разница между opcache.enable
и opcache.enable_cli
заключается в том, что первый следует использовать, если вы, например, используете встроенный PHP-сервер. Если вы запускаете скрипт через CLI, вам понадобится opcache.enable_cli
.
Прежде чем продолжить, давайте убедимся, что JIT действительно работает, создадим PHP-скрипт, доступный через браузер или CLI (в зависимости от того, где вы тестируете JIT), и посмотрим на вывод opcache_get_status()
:
var_dump(opcache_get_status()['jit']);
Результат должен быть примерно таким:
array:7 [
"enabled" => true
"on" => true
"kind" => 5
"opt_level" => 4
"opt_flags" => 6
"buffer_size" => 9080
"buffer_free" => 0
]
Если переменные enable и on имеют значение true, то все готово!
Далее есть несколько способов настроить JIT. Вы можете настроить, когда JIT должен запускаться. Все эти параметры настраиваются с помощью одной (!) записи в конфигурации: opcache.jit.
Это выглядит примерно так:
opcache.enable = 1
opcache.jit = 1255
Итак, что означает это число? RFC перечисляет значение каждого из них. Имейте в виду: это не битовая маска, каждое число просто представляет собой вариант конфигурации. В RFC перечислены следующие варианты:
O – Уровень оптимизации
0 не JIT
1 минимальный JIT (вызов стандартных обработчиков виртуальных машин)
2 селективное встраивание обработчика VM
3 оптимизированных JIT, основанных на статическом выводе типа отдельной функции
4 оптимизированных JIT на основе статического вывода типов и дерева вызовов
5 оптимизированных JIT на основе статического вывода типов и анализа внутренних процедур
T – триггер JIT
0 JIT все функции при первой загрузке скрипта
1 функция JIT при первом выполнении
2 Профилировать по первому запросу и компилировать горячие функции по второму запросу
3 Профилируйте на лету и компилируйте горячие функции
4 Компиляция функций с тегом @jit в комментариях к документации
5 Трассировка JIT
R – размещение регистров
0 не выполнять распределение регистров
1 используйте локальный распределитель регистров liner-scan
2 используйте глобальный распределитель регистров liner-scan
C – флаги оптимизации CPU
0 нет
1 включить генерацию инструкций AVX
RFC перечисляет эти параметры в обратном порядке, поэтому первая цифра представляет значение C, вторая – R и так далее.
В любом случае, внутреннее устройство предлагает 1255 в качестве наилучшего значения по умолчанию, оно будет выполнять максимальный jitting, использовать JIT трассировки, использовать глобальный распределитель регистров линейного сканирования – что бы это ни было – и позволяет генерировать инструкции AVX.
Итак, ваши ini файл или -d-флаги должны иметь следующие значения:
opcache.enable = 1
opcache.jit_buffer_size = 100 МБ
opcache.jit = 1255
Имейте в виду, что opcache.jit, не является обязательным. JIT будет использовать значение по умолчанию, если это свойство не указано.
Какойе значение по умолчанию, спросите вы? Это будет opcache.jit = tracing
.
Погодите, это не та странная структура, похожая на битовую маску, которую мы видели ранее? Правильно: после того, как был принят исходный RFC, было принято решение, что параметры подобные битовой маске, не очень удобны для пользователя. Поэтому было добавленно два псевдонима, которые транслируются в битовую маску, opcache.jit = tracing
и opcache.jit = function
.
Разница между ними заключается в том, что function пытается оптимизировать код только в рамках одной функции, в то время как tracing может просматривать всю трассировку стека, чтобы идентифицировать и оптимизировать горячий код. Рекомендуется использовать JIT-трассировку, потому что она почти всегда дает наилучшие результаты.
Таким образом, единственный вариант, который вам действительно нужно установить для включения JIT с его оптимальной конфигурацией, – это opcache.jit_buffer_size