Les opcodes générés par le moteur PHP sont fortement influencés par la manière dont vous écrivez votre code, non seulement en termes de nombre d’instructions pour accomplir une tâche. Clairement, cela importe beaucoup et je pense qu’il est évident pour vous.
Ce qui pourrait être moins évident est que même la syntaxe du code peut complètement changer les opcodes générés, entraînant beaucoup de surcharges pour le CPU de l’ordinateur à exécuter le même code exact.
Au cours des dernières années, mon produit SaaS a beaucoup grandi et m’a donné l’occasion de m’aventurer de plus en plus dans les techniques d’optimisation pour exécuter mon chargement de travail le plus efficacement possible.
Les résultats que j’ai obtenus sont impressionnants et m’ont beaucoup aidé à débloquer un cash flow libre pour continuer à développer mon aventure SaaS.
A ce stade, le processus PHP dans mon produit SaaS traite plus de 1,2 milliard (avec une « b ») de paquets de données par jour sur une machine avec 2vCPU et 8GB de mémoire. Je use d’un groupe d’autoscaling AWS pour avoir plus de flexibilité en cas d’impulsions imprévues, mais il ne rajoute rarement qu’une seconde machine (une à deux fois par semaine).
Allons aborder le sujet de cet article. Je pense que vous le trouverez très intéressant.
Qu’est-ce que des opcodes PHP ?
Les opcodes de PHP sont l’abréviation de opérations code, et ils se réfèrent aux instructions de bas niveau qui sont exécutées par le moteur PHP après que le code source PHP que vous écrivez ait été compilé.
En PHP, la compilation du code se produit à runtime : de base, la première fois que votre code est pris par le moteur PHP, il sera compilé en ce code facilement interprétable par la machine, mis en cache (ainsi le moteur ne compile pas le même code à nouveau) et ensuite exécuté.
Voici une représentation simple du processus :
Mise en cache des opcodes PHP
Le cache d’opcodes PHP permet de sauver trois étapes dans le processus d’exécution du code : l’analyse du code PHP brut, la tokenisation et la compilation.
Une fois que les opcodes sont générés pour la première fois, ils sont stockés en mémoire pour être réutilisés dans les demandes ultérieures. Cela réduit la nécessité pour le moteur PHP de recompiler le même code PHP à chaque exécution, économisant beaucoup de consommation de CPU et de mémoire.
Le plus couramment utilisé est le OPCache pour le cache d’opcodes, qui est inclus par défaut à partir de PHP 5.5 jusqu’à les versions récentes. Il est hautement efficient et largement supporté.
Le cache du précompilé du code bytecode nécessite d’invalider le cache après chaque déploiement. Cela est dû au fait que si les fichiers modifiés ont la version du bytecode dans le cache, PHP continuera de faire tourner l’ancienne version du code jusqu’à ce que vous vidiez le cache des opcodes, ce qui signifie que le nouveau code sera à nouveau compilé, générant un nouvel élément de cache.
Comment enquêter sur les opcodes PHP
Pour comprendre comment la syntaxe différente peut impacter les opcodes du script, nous avons besoin d’une manière de saisir le code compilé généré par le moteur PHP.
Il existe deux manières de récupérer les opcodes.
Fonctions native OPCache
Si vous avez l’extension OPCache activée sur votre machine, vous pouvez utiliser ses fonctions native pour obtenir les opcodes d’un fichier PHP spécifique :
// Force compilation of a script
opcache_compile_file(__DIR__.'/yourscript.php');
// Get OPcache status
$status = opcache_get_status();
// Inspect the script's entry in the cache
print_r($status['scripts'][__DIR__.'/yourscript.php']);
VLD (Vulcan Logic Disassembler) Extension PHP.
VLD est une extension PHP populaire qui désassemble le code PHP compilé et affiche les opcodes. Il s’agit d’une puissante tool pour comprendre comment PHP interprète et exécute votre code. Une fois installée, vous pouvez exécuter un script PHP avec VLD activé en utilisant la commande php
avec les options -d
:
php -d vld.active=1 -d vld.execute=0 yourscript.php
La sortie incluera des informations détaillées sur les opcodes compilés, y compris chaque opération, sa ligne de code associée et plus.
Utilisez 3v4l (acronyme pour EVAL)
3v4l est une très utile outil en ligne qui vous permet de visualiser les opcodes générés par un code PHP que vous tapez dans l’éditeur. Il s’agit essentiellement d’un serveur PHP avec VLD installé pour pouvoir attraper l’affichage de VLD et montrer les opcodes dans le navigateur.
Comme c’est gratuit, nous utiliserons cet outil en ligne pour les prochaines analyses.
Comment Générer des Opcodes PHP Efficaces
3v4l est parfait pour comprendre comment la syntaxe de code que nous utilisons peut influencer les opcodes PHP résultants de façon positive ou négative. Commencez à coller le code ci-dessous dans 3v4l. Gardez la configuration « toutes les versions supportées » et cliquez sur « évaluer« .
namespace App;
strlen('ciao');
Après l’exécution du code, un menu de tabulations apparaîtra en bas. Naviguez vers l’onglet VLD pour visualiser les opcodes correspondants.
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
5 0 E > INIT_NS_FCALL_BY_NAME 'App%5CSpace%5Cstrlen'
1 SEND_VAL_EX 'ciao'
2 DO_FCALL 0
3 > RETURN 1
Notez que la première opération est INIT_NS_FCALL_BY_NAME
. L’interpréteur construit le nom de la fonction en utilisant le namespace du fichier actuel, mais il n’existe pas dans le namespace App\Example
— alors comment ça fonctionne ?
L’interpréteur vérifiera si la fonction existe dans le namespace actuel. Si ce n’est pas le cas, il tentera d’appeler la fonction correspondante du noyau.
Ici, nous avons l’occasion de demander à l’interpréteur d’éviter cette double vérification et d’exécuter directement la fonction du noyau.
Essayez d’ajouter un backslash (\
) avant strlen
et cliquez sur “eval”:
namespace App;
\strlen('ciao');
Dans l’onglet VLD, vous pouvez maintenant voir l’opcode avec une seule instruction.
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > > RETURN 1
Comme vous avez communiqué l’emplacement exact de la fonction, il n’a pas besoin d’examiner les options de secours.
Si vous n’aimez pas utiliser le backslash, vous pouvez importer la fonction comme n’importe quelle classe de l’espace de noms racine :
namespace App;
use function strlen;
strlen('ciao');
Utilisez les Optimisations d’Opcode Automatiques
Il existe également de nombreux automatismes internes du moteur PHP pour générer un opcode optimisé en évaluant des expressions statiques à l’avance. C’était l’une des raisons les plus importantes de l’amélioration de la performance de PHP depuis la version 7.x.
Beaucoup de dynamiques comme celles-ci peuvent vraiment vous aider à réduire la consommation de ressources et à économiser des coûts. Après avoir effectué cette recherche, j’ai commencé à utiliser ces astuces dans tout mon code.
Permettez-moi de vous montrer un exemple utilisant les constantes PHP. Exécutez ce script dans 3v4l :
namespace App;
if (PHP_OS === 'Linux') {
echo "Linux";
}
Regardez les deux premières lignes de l’opcode PHP :
line #* E I O op fetch ext return operands
------------------------------------------------------------------------------------- 5 0 E > FETCH_CONSTANT ~0 'App%5CPHP_OS' 1 IS_IDENTICAL ~0, 'Linux' 2 > JMPZ ~1, ->4 6 3 > ECHO 'Linux' 7 4 > > RETURN 1
FETCH_CONSTANT
essaye d’obtenir la valeur de PHP_OS
du espace de nommage courant et cherchera dans l’espace de nommage global car il n’existe pas ici. Ensuite, l’instruction IS_IDENTICAL
exécute l’instruction IF
.
Maintenant essayez d’ajouter un backslash à une constante :
namespace App;
if (\PHP_OS === 'Linux') {
echo "Linux";
}
Comme vous pouvez le voir dans l’opcode, le moteur n’a pas besoin d’essayer d’obtenir la constante parce qu’il est clair où elle se trouve, et comme il s’agit d’une valeur statique, elle est déjà en mémoire.
De plus, l’instruction IF
a disparu parce que l’autre côté de l’instruction IS_IDENTICAL
est une chaîne statique («Linux
») donc l’IF
peut être marqué comme «true
» sans l’overhead de l’interprétation à chaque exécution.
C’est pourquoi vous avez beaucoup de pouvoir pour influencer le rendement final de votre code PHP.
Conclusion
J’espère que cet article vous a été intéressant. Comme je l’ai mentionné au début de cet article, je tire beaucoup de bénéfices de l’utilisation de cette tactique et, en fait, elles sont également utilisées dans nos paquets.
Vous pouvez voir un exemple ici de comment j’ai utilisé ces astuces dans notre paquet PHP pour optimiser son performances.
Si vous voulez en savoir plus sur les défis de la construction d’une entreprise orientée développeurs, vous pouvez me suivre sur LinkedIn.
Source:
https://dzone.com/articles/php-opcode-improve-application-performance