Comprendre le JIT de PHP 8

Insérez la description de l'image ici

Le compilateur JIT (Just In Time) de PHP 8 sera intégré dans php en tant qu'extension.L'extension Opcache est utilisée pour convertir certains opcodes directement en instructions depuis le processeur au moment de l'exécution.

Cela signifie qu'après avoir utilisé JIT, Zend VM n'a pas besoin d'interpréter certains opcodes, et ces instructions seront directement exécutées en tant qu'instructions au niveau du processeur.

JIT pour PHP 8

L'impact du compilateur PHP 8 Just In Time (JIT) est incontestable. Mais jusqu'à présent, j'ai trouvé que je ne savais pas grand-chose sur ce que JIT devrait faire.

Après de nombreuses recherches et abandon, j'ai décidé de vérifier moi-même le code source PHP. En combinant une partie de mes connaissances du langage C et toutes les informations éparses que j'ai collectées jusqu'à présent, je vous propose cet article, j'espère qu'il pourra vous aider à mieux comprendre le PHP JIT.

Pour faire simple: lorsque JIT fonctionne comme prévu, votre code ne sera pas exécuté par Zend VM, mais directement exécuté comme un ensemble d'instructions au niveau du processeur.

C'est toute l'idée.

Mais pour mieux le comprendre, nous devons considérer comment php fonctionne en interne. Pas très compliqué, mais nécessite une introduction.

Comment le code PHP est-il exécuté?

Il est bien connu que PHP est un langage interprété, mais que signifie cette phrase?

Chaque fois qu'un code PHP (script de ligne de commande ou application WEB) est exécuté, il doit passer par un interpréteur PHP. Les interpréteurs PHP-FPM et CLI sont les plus couramment utilisés.

Le travail de l'interpréteur est simple: il reçoit du code PHP, l'interprète et renvoie le résultat.

Le langage interprété général est ce processus. Certaines langues peuvent réduire quelques étapes, mais l'idée générale est la même. En PHP, le processus est le suivant:

  1. Lisez le code PHP et interprétez-le comme un ensemble de mots-clés appelés Tokens. Ce processus permet à l'interpréteur de savoir quel code a été écrit dans chaque programme. Cette étape s'appelle Lexing ou Tokenizing.
  2. Après avoir récupéré la collection Tokens, l'interpréteur PHP essaiera de les analyser. Un arbre de syntaxe abstraite (AST) est généré via un processus appelé analyse. Ici, AST est un ensemble de nœuds indiquant les opérations à effectuer. Par exemple, "echo 1 + 1" signifie en fait "imprimer le résultat de 1 + 1" ou plus précisément "imprimer une opération, cette opération vaut 1 + 1".
  3. Avec AST, il est plus facile de comprendre les opérations et les priorités. La conversion de l'arbre de syntaxe abstraite en une opération qui peut être exécutée par le CPU nécessite une expression pour la transition (IR), que nous appelons Opcodes en PHP. Le processus de conversion d'AST en Opcodes s'appelle la compilation.
  4. Avec Opcodes, voici la partie intéressante: l'exécution de code! PHP a un moteur appelé Zend VM, qui peut recevoir une série d'opcodes et les exécuter. Après avoir exécuté tous les Opcodes, Zend VM terminera le programme.

Cette image peut vous rendre plus clair:
Insérez la description de l'image ici

Une version simplifiée de l'aperçu du processus d'explication PHP.

Comme tu peux le voir. Voici une question: même si le code PHP n'a pas changé, ce processus sera-t-il suivi à chaque exécution?

Revenons aux Opcodes. correct! C'est pourquoi l'extension Opcache existe.

Extension Opcache

L'extension Opcache est incluse avec PHP, et il n'est généralement pas nécessaire de la désactiver. Il est préférable d'ouvrir Opcache lors de l'utilisation de PHP.

Son rôle est d'ajouter une couche de mémoire cache partagée aux Opcodes. Son travail consiste à extraire les Opcodes nouvellement générés de l'AST et à les mettre en cache pour exécution.

Vous pouvez ignorer les étapes Lexing / Tokenizing et Parsing.

Ceci est un diagramme schématique du processus incluant l'extension Opcache:
Insérez la description de l'image ici
PHP utilise le processus d'explication d'Opcache. Si le fichier a déjà été analysé, PHP obtiendra les Opcodes mis en cache pour lui au lieu de l'analyser à nouveau.

Ignorez parfaitement les étapes Lexing / Tokenizing, Analyse et Compilation.

Note latérale: C'est génial
! Vous permet de dire à PHP FPM d'analyser la base de code, de la convertir en Opcodes et de la mettre en cache avant l'exécution.

Voulez-vous savoir comment JIT participe à ce processus d'interprétation? Cet article vous expliquera.

Quel est l'effet de la compilation Just In Time?

Zeev écoute
après avoir clarifié le JIT fait quoi que ce soit.

Si les extensions Opcache peuvent obtenir des Opcodes plus rapidement et les transférer directement vers Zend VM, alors JIT leur permet de s'exécuter sans utiliser Zend VM du tout.

Zend VM est un programme écrit en C qui agit comme une couche entre les Opcodes et le CPU. JIT génère directement du code compilé lors de l'exécution, afin que PHP puisse

La VM Zend est ignorée et exécutée directement par le CPU. En théorie, les performances seront meilleures.

Cela semble étrange, car avant de compiler en code machine, vous devez écrire une implémentation spécifique pour chaque type de structure. Mais en fait, c'est raisonnable.

Le JIT de PHP utilise une bibliothèque appelée DynASM (Dynamic Assembler), qui mappe un ensemble d'instructions CPU dans un format spécifique aux codes d'assemblage de nombreux types de CPU différents. Par conséquent, le compilateur n'a besoin d'utiliser DynASM que pour convertir les Opcodes en code machine d'une structure spécifique.

Cependant, il y a un problème qui me dérange depuis longtemps.

Si le préchargement peut analyser le code PHP en Opcodes avant l'exécution, et que DynASM peut compiler les Opcodes en code machine (Just In Time Compilation), pourquoi n'utilisons-nous pas immédiatement Ahead of Time Compilation pour compiler PHP immédiatement?

En écoutant l'émission de Zeev, l'une des raisons pour lesquelles j'ai trouvé est que PHP est un langage faiblement typé, ce qui signifie que PHP ne connaît généralement pas le type de variable avant que Zend VM n'essaie d'exécuter un opcode.

Vous pouvez vérifier le type d'union Zend_value pour savoir que de nombreux pointeurs pointent vers différents types de variables. Chaque fois que Zend VM essaie d'obtenir une valeur de Zend_value, il utilisera une macro comme ZSTR_VAL pour obtenir un pointeur vers la chaîne dans le type d'union.

Par exemple, ce gestionnaire de machine virtuelle Zend gère les expressions «inférieur ou égal à» (<=). Regardez-le encoder tant de branches if else, juste pour l'inférence de type.

L'utilisation du code machine pour effectuer une logique d'inférence de type n'est pas faisable et peut devenir plus lente.

Évaluer d'abord, puis compiler n'est pas un bon choix, car la compilation en code machine est une tâche gourmande en ressources processeur. Par conséquent, il n'est pas bon de tout compiler au moment de l'exécution.

Alors, comment fonctionne la compilation Just In Time?

Maintenant, nous savons que nous ne pouvons pas bien déduire le type à compiler à l'avance. Nous savons également que le coût de calcul de la compilation au moment de l'exécution est très élevé. Alors, quels sont les avantages de JIT pour PHP?

Afin de trouver un équilibre, le JIT de PHP essaie de ne compiler que des Opcodes précieux. Pour cela, JIT analysera les Opcodes à exécuter par Zend VM et vérifiera les compilations possibles. (Selon le fichier de configuration)

Quand un certain Opcode est compilé, il remettra l'exécution au code compilé, pas à Zend VM. Il ressemble à ceci:
Insérez la description de l'image ici

Processus d'interprétation JIT de PHP. S'ils sont compilés, les Opcodes ne seront pas exécutés par Zend VM.

Par conséquent, dans l'extension Opcache, il existe deux instructions de détection pour déterminer s'il faut compiler Opcode. Si nécessaire, le compilateur utilisera DynASM pour convertir cet Opcode en code machine et exécuter ce code machine.

Fait intéressant, étant donné que le code compilé dans l'interface actuelle a une limite de Mo (également configurable), l'exécution du code doit pouvoir basculer de manière transparente entre JIT et le code interprété.

Au fait, cette conférence de Benoit Jacquemont sur le JIT de php m'a aidé à comprendre le tout.

Je ne sais toujours pas quand la partie compilation sera efficace, mais je pense que je ne veux pas vraiment savoir maintenant.

Ainsi, vos gains de performances peuvent ne pas être excellents

J'espère que tout le monde sait maintenant pourquoi la plupart des applications php n'obtiennent pas beaucoup de gains de performances en raison de l'utilisation de compilateurs juste à temps. C'est pourquoi Zeev recommande d'analyser et d'expérimenter différentes configurations JIT pour votre application est la meilleure approche.

Si vous utilisez PHP FPM, vous partagerez généralement les opcodes compilés entre plusieurs requêtes, mais cela ne change toujours pas les règles du jeu.

En effet, JIT optimise les opérations intensives en calcul, et la plupart des applications PHP d'aujourd'hui sont plus contraintes d'E / S qu'autre chose. Si vous avez quand même besoin d'accéder au disque ou au réseau, peu importe que l'opération de traitement soit compilée ou non. Ce sera très similaire dans le temps.

à moins que…

Vous faites quelque chose qui n'est pas limité par les E / S, comme le traitement d'image ou l'apprentissage automatique. Tout ce qui ne touche pas les E / S bénéficiera du compilateur JIT.

C'est pourquoi les gens disent maintenant que nous préférons écrire des fonctions natives en PHP au lieu de C. Si vous souhaitez toujours compiler cette fonction, la surcharge sera inexpressive.

Je suppose que tu aimes

Origine blog.csdn.net/qq_15915293/article/details/114029992
conseillé
Classement