Сравнение производительности версий PHP

от автора

image

В этой статье мы рассмотрим результаты нескольких бенчмарков, начиная с PHP 5 и вплоть до экспериментальной JIT-ветки (сейчас в разработке). На момент написания не было известно, появится ли до PHP 8 ещё какая-то основная версия, например PHP 7.2. Но логично предположить, что возможности экспериментальной ветки как минимум будут включены в PHP 8.

C момента своего появления в 1994-м язык PHP радикально изменился. Первые релизы представляли собой просто внешние CGI-программы, которые создавались во многом как личный проект Расмуса Лердорфа. С третьей версии PHP был серьёзно переработан, возникла группа разработчиков языка.

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

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

Почти 20 лет создатели языка прилагали огромные усилия, чтобы удовлетворять всевозможные требования. Хотя с появлением PHP 3 производительность существенно возросла, сколько-то серьёзные результаты язык смог продемонстрировать только с PHP 4, когда появился движок Zend.

В 2000-м были внедрены новые in-memory компилятор и модель исполнения (executor model). Это позволило вновь сильно поднять производительность PHP, нередко в 5—10 раз. В результате его начали всерьёз рассматривать как инструмент для создания веб-приложений и сайтов. И сегодня PHP достиг высот, которых никто не ожидал от этого языка, когда он появился.

Но взрывной рост популярности PHP лишь привёл к росту требований о повышении производительности. К счастью, у движка Zend прекрасный потенциал для модернизации.
Хотя PHP 5 не стал заметным шагом вперёд и в некоторых случаях был даже медленнее PHP 4, группа разработчиков Zend постоянно оптимизировала движок от релиза к релизу, в результате PHP 5.6 оказался быстрее в 1,5—3 раза.

Но главный рывок произошёл с выходом PHP 7 в декабре 2015-го. Через год была анонсирована версия 7.1, тоже получившая ряд улучшений.

Компилятор PHP JIT и ожидания по улучшению производительности PHP 8

В настоящее время разрабатывается очень многообещающая версия Zend. Она будет основана на версии из релиза 7.1, а когда именно выйдет, пока не объявлено. Так что сейчас это экспериментальная JIT-ветка.

Одна из главных интриг связана с Just-In-Time (JIT) компиляцией. Это методика преобразования кода в другой формат (нативный машинный код) прямо перед выполнением. Цель JIT — повысить скорость работы программ. Посмотрим, смогут ли разработчики сдержать обещание.

Бенчмарк обработки PHP-скриптов

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

Применялись следующие бенчмарки:

Бенчмарки прогонялись на последних второстепенных релизах основных версий PHP:

Те же бенчмарки прогонялись и на всех промежуточных релизах, например между 5.3.0 и 5.3.29. Результаты красноречивы: релизы не демонстрировали заметных улучшений производительности. Улучшения отмечались только при переходах между основными версиями, например с PHP 5.4 на PHP 5.5 или с PHP 5.6 на PHP 7.

Это означает, что те же скрипты будут выполняться примерно с одной скоростью и на PHP 5.4.0, и на PHP 5.4.45.

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

Сравнение результатов процессорных бенчмарков

По каждому бенчмарку приведены три значения:

  • Время, с: время выполнения (в секундах).
  • Относительное изменение, %: изменение времени выполнения по сравнению с предыдущей версией. Если бенчмарк выполнялся быстрее — значение положительное, если медленнее — отрицательное.
  • Абсолютное изменение, крат: насколько быстрее выполнялся скрипт по сравнению с PHP 5.0.

Результаты прогона бенчмарков вы можете увидеть в таблице ниже.

PHP version bench.php micro_bench.php mandelbrot.php (3)
Время, с Относительное изменение, % Абсолютное изменение, крат Время, с Относительное изменение, % Абсолютное изменение, крат Время, с Относительное изменение, % Абсолютное изменение, крат
5.0.5 8,650 (1) сбой 251,470
5.1.6 3,718 57,02 2,327 (1) сбой 87,354 65,26 2,879
5.2.17 3,838 –3,23 2,254 (1) сбой 86,550 0,92 2,905
5.3.29 2,614 31,89 3,309 19,469 68,018 21,41 3,697
5.4.45 2,056 21,35 4,207 10,300 47,10 (2) 1,890 33,610 50,59 7,482
5.5.38 1,995 2,97 4,336 10,456 –1,51 1,862 30,553 9,10 8,231
5.6.28 1,798 9,87 4,811 10,243 2,04 1,901 29,903 2,13 8,410
7.0.13 0,670 62,74 12,910 4,056 60,40 4,800 15,562 47,96 16,159
7.1.0 0,495 26,12 17,475 3,327 17,97 5,582 9,228 40,70 27,251
JIT-ветка 0,208 54,68 41,587 2,185 35,41 8,910 4,680 49,28 53,733

(1) Бенчмарк не может выполняться на версиях до 5.3, потому что он использует свойства, которые ещё не были реализованы.

(2) Результаты в этой колонке немного смещены, потому что бенчмарку для работы нужен как минимум PHP 5.3. Их можно взять просто для справки, раз нельзя сравнить с PHP 5.0.

(3) Это модифицированная версия скрипта mandelbrot.php, который выполнялся слишком быстро в версии 7.1.0 в экспериментальной ветке, так что не получалось точно измерить скорость. Поэтому мы внутри скрипта выполняли сто вычислений, а не одно.

Конечно, чисто процессорные бенчмарки не позволяют оценить все аспекты производительности PHP. Данные могут быть нерепрезентативны. Тем не менее на основе этих данных можно сделать выводы:

  • PHP 5.1 более чем вдвое быстрее PHP 5.0.
  • Версии 5.2 и 5.3 обладают новым набором улучшений, но не таких впечатляющих, как у 5.1.
  • Следующий скачок производительности был у версии 5.4.
  • Расширение opcache поставлялось с 5.5 и 5.6. Это позволяло повысить производительность за счёт ускорения загрузки кода, когда один и тот же скрипт выполнялся последовательно. Однако opcache не слишком полезно для скриптов, исполняемых в режиме CLI.
  • PHP 7.0 — главный прорыв с точки зрения производительности. Движок Zend был полностью переработан, и мы наблюдаем результат этих масштабных изменений.
  • В PHP 7.1 в расширении opcache были оптимизированы опкоды, что объясняет скачок производительности по сравнению с 7.0.
  • Экспериментальная JIT-ветка демонстрирует очередной скачок производительности. Но в некоторых случаях никакого улучшения нет. Иногда ветка оказывается даже медленнее, потому что компилирование не ускоряет работу кода. Но не будем забывать, что эта фича пока в разработке.

Сопоставление производительности разных версий PHP

PHP 5 гораздо производительнее, чем PHP 4. Движок Zend, лежащий в основе интерпретатора, был полностью переработан (Zend Engine 2), что открыло дорогу дальнейшим улучшениям. Здесь мы не будем освещать все различия между PHP 4 и PHP 5, вкратце пройдёмся лишь по вещам, внедрённым после PHP 5.0.

Ниже перечислены только те изменения, которые затронули ядро PHP. Более подробный список нововведений и изменений: PHP 5 и PHP 7.

PHP 5.1

  • Скомпилированные переменные
  • Специализированный исполнитель (Specialized executor)
  • Кеш real-path
  • Ускоренная обработка выражения switch()
  • Ускоренные функции массивов
  • Ускоренное извлечение переменных
  • Ускоренный вызов «волшебных» методов

PHP 5.2

  • Новый диспетчер памяти
  • Оптимизированное копирование массивов/хеш-таблиц
  • Оптимизированные выражения require_once() и include_once()
  • Небольшие оптимизации специфических внутренних функций
  • Улучшенное компилирование HEREDOC и компилирование интерполированных строк

PHP 5.3

  • Сегментированный стек VM
  • Бесстековая VM
  • Замена констант в ходе компилирования
  • Ленивая инициализация таблицы символов
  • Улучшение real-path кеша
  • Улучшение скорости runtime и потребления памяти
  • Ускоренный парсинг языка
  • Улучшение размера двоичных PHP-файлов и запуска кода (code startup)

PHP 5.4

  • Отложенное размещение хеш-таблицы
  • Константные таблицы (Constant tables)
  • Рантаймовые кеши привязки (binding caches)
  • Интернированные строки (Interned Strings)
  • Улучшенный уровень вывода (output layer)
  • Улучшена производительность тернарных операторов при использовании массивов

PHP 5.5

  • Улучшено соглашение о вызове (calling convention) виртуальной машины
  • Интеграция OPcache
  • Другие оптимизации движка Zend

PHP 5.6

  • Оптимизирована обработка пустых строк, минимизирована необходимость в размещении новых пустых значений

PHP 7 vs. PHP 5.6

Большинство из этих улучшений относятся к движку Zend:

  • Рефакторинг основных структур данных
  • Улучшена конвенция вызова виртуальной машины
  • Новый API парсинга параметров
  • Новый диспетчер памяти
  • Многочисленные улучшения исполнителя виртуальной машины
  • Существенно уменьшено использование памяти
  • Улучшены функции __call() и __callStatic()
  • Улучшена конкатенация строк
  • Улучшен поиск символов в строках

PHP 7.1, улучшения производительности

  • Новый оптимизационный фреймворк на базе SSA (встроен в opcache)
  • Глобальная оптимизация байткода PHP на основе выведения типов (type inference)
  • Высокоспециализированные обработчики опкодов виртуальной машины

Свойства PHP 8 или PHP 7.2, экспериментальная JIT-ветка

  • Компилирование Just-In-Time

Как измерялась производительность

Прогон бенчмарков был чуть более сложным процессом, чем запуск Unix-команды time, и проходил в несколько этапов:

Настройка системы

С сделал выделенную систему с такими характеристиками:

  • VPS с одним виртуальным ядром, 2,4 ГГц, 2 Гб памяти и два SSD drives — один для ОС, второй для хранения исходных файлов PHP, бинарных файлов и записи отчётов.
  • ОС Debian Wheezy 3.2.82-1
  • Компилятор Gnu C 4.9.2-10 (дистрибутив Debian Jessie).

Хотя система поставлялась с компилятором Gnu C 4.7.2, пришлось поставить более свежую версию: экспериментальная JIT-ветка должна компилироваться с помощью Gnu C 4.8 и выше.

Компилирование исходного кода

Перед сборкой полных дистрибутивов был запущен скрипт configure со следующими параметрами:

--prefix=/usr/local/php  --disable-debug --disable-phpdbg --enable-mysqlnd --enable-bcmath --with-bz2=/usr --enable-calendar --with-curl --enable-exif --enable-fpm --with-freetype-dir --enable-ftp --with-gd --enable-gd-jis-conv --enable-gd-native-ttf --with-gettext=/usr --with-gmp --with-iconv --enable-intl --with-jpeg-dir --enable-mbstring --with-mcrypt --with-openssl --enable-pcntl --with-pdo-mysql=mysqlnd --with-png-dir --with-recode=/usr --enable-shmop --enable-soap --enable-sockets --enable-sysvmsg --enable-sysvsem --enable-sysvshm --enable-wddx --with-xmlrpc --with-xsl --with-zlib=/usr --enable-zip --with-mysqli=mysqlnd

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

Запуск бенчмарков

Каждый бенчмарк запускался с помощью PHP CLI (Command-Line Interface) через специальный скрипт, который делал следующее:

1) С помощью функции microtime() на лету модифицировал скрипт, чтобы изнутри измерять время его выполнения. После модифицирования скрипт выглядел так:

<?php     $__start__ = microtime( true );     /***         Здесь исходный код бенчмарка     ***/     fprintf( STDERR, microtime( true ) - $__start__);  ?>     

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

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

3) Скрипт выполнялся пять раз, сохранялись минимальное, максимальное и среднее время выполнения. В этой статье представлены только средние значения — «время выполнения скрипта».

Использовались такие настройки в php.ini:

engine = On short_open_tag = Off realpath_cache_size = 2M max_execution_time = 86400 memory_limit = 1024M error_reporting = 0 display_errors = 0 display_startup_errors = 0 log_errors = 0 default_charset = "UTF-8"  [opcache] zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.optimization_level=-1 opcache.fast_shutdown=1 opcache.validate_timestamps=1 opcache.revalidate_freq=60 opcache.use_cwd=1 opcache.max_accelerated_files=100000 opcache.max_wasted_percentage=5 opcache.memory_consumption=128 opcache.consistency_checks=0 opcache.huge_code_pages=1  // PHP 8/Next only opcache.jit=35 opcache.jit_buffer_size=32M

Интерпретирование результатов

Длительность выполнения измерялась с помощью Unix-команды time. Пример выходных данных:

$ time php bench.php real: 0m1.96s user: 0m1.912s sys: 0m0.044s

Значение real — это время от вызова команды до её прерывания (пока не происходит возврата к командной строке).

Значение user — время, потраченное на выполнение пользовательского кода (в данном случае — исполняемого PHP-файла).

Значение sys — время, потраченное на выполнение кода ОС (kernel). Это значение должно быть минимальным, но может оказаться сильно больше представленного, если ваш код обращается, например, к медленным устройствам. Также на величину значения способна повлиять высокая загруженность ОС.

На системах в состоянии ожидания суммарное значение user + sys должно быть очень близко к real. В приведённом выше примере: user + sys = 1,956 с, real = 1,960 с. Разница в 0,004 с связана не с нашим процессом, а с разными задачами ОС, например с диспетчеризацией.

Тот же скрипт был выполнен на высоконагруженной ОС при параллельном компилировании тремя разными PHP-версиями:

$ time php bench.php real: 0m7.812s user: 0m2.02s sys: 0m0.101s

Как видите, уровень нагрузки сильно влияет на время выполнения (возможно, и на системное время). Поэтому я добавил в бенчмарк ещё одно значение — overhead операционной системы. Это разница между полным временем выполнения (elapsed time) и суммой пользовательского и системного времени.

Я удостоверился, чтобы во время прогона бенчмарков это значение в течение 99 % времени было меньше 100 миллисекунд, даже когда выполнение скриптов занимало десятки секунд.

Спасибо Дмитрию Стогову и всей команде разработки PHP

Эта статья писалась при активной помощи Дмитрия Стогова. Он прояснил ряд моментов и рецензировал представленную здесь информацию.

image

Дмитрий был разработчиком расширения Turck MMCache, которое со времён PHP 4 может использоваться для кеширования PHP-опкодов в совместно используемой памяти. После этого Дмитрий начал работать над Zend, чем и занимается по сей день.

Также он когда-то инициировал создание PHPNG — того, что позднее превратилось в PHP 7. В работе над этой и последующими версиями с Дмитрием сотрудничали Никита Попов и Синьчэнь Хуэй (Xinchen Hui).

В создание PHP 5 внесли большой вклад Энди Гутманс, Зеев Сураски и Стас Малышев. Многих других разработчиков я не стану здесь перечислять, чтобы не загромождать статью.

Специальное благодарственное видео для всех, кто помогал развивать PHP

В 2016-м исполнился 21 год со дня появления PHP — 8 июня 1995 г.

image

Чтобы отдать должное всем, кто так или иначе внёс свой вклад в развитие PHP, Питер Кокот с помощью Gource создал анимационное видео. В нём рассказывается о развитии ключевых модулей PHP в течение всей жизни языка.

Питер Кокот хорошо известен в PHP-сообществе. Он основал в Facebook PHP Group, крупнейшую группу, посвящённую отдельному языку программирования. В ней состоят более 140 тыс. участников и 22 модератора.
Создатель PHP Расмус Лердорф сказал: «В мире PHP ничего не происходит без движения сообщества». Надеюсь, эти слова будут вдохновлять вас.

Если вы не можете помочь развитию PHP с помощью написания кода на С, то можете выкладывать свои PHP-разработки на GitHub, PHP Classes, Packagist — куда угодно. Чем больше мест, где мы будем делиться друг с другом наработками, тем лучше.

Также вы можете поучаствовать в краудфандинговой кампании PHP Diversity Rainbow elePHPant.

Заключение

Цель статьи — дать представление о производительности разных версий PHP, начиная с 5.0 и заканчивая свежайшей экспериментальной версией. Тестирование выполнялось с помощью известных бенчмарков. Также в статье приведён список улучшений, повысивших производительность различных версий PHP.

ссылка на оригинал статьи https://habrahabr.ru/post/326696/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *