Пришло время проанализировать коды операций PHP, которые генерируются интерпретатором PHP.Для этого вам нужно установить расширение VLD и использовать его из командной строки для генерации операционных кодов php-скрипта под рукой.
Анализ кода операции
- Кажется, что
$i++
не совпадает с ++$i
с точки зрения кодов операций и использования памяти.Оператор $ i ++;генерирует коды операций:
POST_INC ~4 !1
FREE ~4
Увеличивает счетчик на 1 и сохраняет предыдущее значение в слоте памяти # 4.Тогда, потому что это значение никогда не используется - освобождает его от памяти.Вопрос - зачем нам хранить значение, если оно никогда не используется?
Кажется, что действительно есть штраф за цикл, поэтому мы можем повысить производительность, выполнив
развертывание цикла .
Оптимизированный тестовый код
Изменение POST_INC наASSIGN_ADD (который не сохраняет дополнительную информацию в памяти) и выполняет развертывание цикла, дает использовать такой тестовый код:
while (true) {
// Slow version
$t1 = microtime(true);
for ($n = 0, $i = 0; $i < 2000; $i+=10) {
// loop unrolling
$n += 2 * (($i+0) * ($i+0));
$n += 2 * (($i+1) * ($i+1));
$n += 2 * (($i+2) * ($i+2));
$n += 2 * (($i+3) * ($i+3));
$n += 2 * (($i+4) * ($i+4));
$n += 2 * (($i+5) * ($i+5));
$n += 2 * (($i+6) * ($i+6));
$n += 2 * (($i+7) * ($i+7));
$n += 2 * (($i+8) * ($i+8));
$n += 2 * (($i+9) * ($i+9));
}
$t2 = microtime(true);
echo "{$n}\n";
// Optimized version
$t3 = microtime(true);
for ($n = 0, $i = 0; $i < 2000; $i+=10) {
// loop unrolling
$n += ($i+0) * ($i+0);
$n += ($i+1) * ($i+1);
$n += ($i+2) * ($i+2);
$n += ($i+3) * ($i+3);
$n += ($i+4) * ($i+4);
$n += ($i+5) * ($i+5);
$n += ($i+6) * ($i+6);
$n += ($i+7) * ($i+7);
$n += ($i+8) * ($i+8);
$n += ($i+9) * ($i+9);
}
$n *= 2;
$t4 = microtime(true);
echo "{$n}\n";
$speedup = round(100 * (($t2 - $t1) - ($t4 - $t3)) / ($t2 - $t1), 0);
$table[$speedup]++;
echo "****************\n";
foreach ($table as $s => $c) {
if ($s >= 0 && $s <= 20)
echo "$s,$c\n";
}
}
Results
Скрипт агрегирует количество попаданий ЦП в один или другойзначение ускорения.Когда ЦП и Ускорение отображаются в виде графика, мы получаем такую картину:
Таким образом, наиболее вероятно, что сценарий получит ускорение на 10%.Это означает, что наша оптимизация привела к ускорению + 2% (по сравнению с оригинальными сценариями 8%).
Ожидания
Я почти уверен, что все эти вещисделано - может быть сделано автоматически с помощью PHP JIT'er.Я не думаю, что сложно автоматически изменить пару кодов операций POST_INC / FREE в один код операции PRE_INC при создании двоичного исполняемого файла.Также не чудо, что PHP JIT'er может применить развертывание цикла.И это только начало оптимизаций!
Надеемся, что JIT'er будет в PHP 8.0