PHP GR8: JIT améliorera-t-il les performances de PHP 8



PHP est l'un des principaux langages de développement de Badoo. Dans nos centres de données, des milliers de cœurs de processeur sont occupés à exécuter des millions de lignes de code PHP. Nous suivons de près l'actualité et recherchons activement des moyens d'améliorer la productivité, car même une petite optimisation de nos volumes permet de réaliser d'importantes économies de ressources. L'une des principales nouveautés en matière de performances PHP est l'apparition de JIT dans la huitième version du langage. Cela, bien sûr, ne pouvait pas rester sans notre attention, et nous avons traduit l'article sur ce qu'est JIT, comment il sera implémenté en PHP, pourquoi il a été décidé de le faire et à quoi s'attendre.

Si vous n'avez pas quitté la grotte ou que vous ne venez pas du passé (dans ce cas, bienvenue), vous savez déjà que PHP 8 aura JIT: l'autre jour, le vote s'est déroulé tranquillement et pacifiquement et la grande majorité des participants a voté en faveur de la mise en œuvre, alors tout est décidé .

Dans un accès de joie, vous pouvez même dépeindre plusieurs mouvements fous comme sur la photo (d'ailleurs, cela s'appelle le "Detroit JIT":



Maintenant, asseyez-vous et lisez cet article démystifiant. Je veux clarifier le malentendu associé à ce qu'est le JIT et à son utilité, et parler de son fonctionnement (mais pas trop en détail pour ne pas vous ennuyer).

Comme je ne sais pas qui lira l'article, je passerai de questions simples à complexes. Si vous connaissez déjà la réponse à la question dans le titre, vous pouvez ignorer le chapitre correspondant en toute sécurité.

Qu'est-ce que JIT?


PHP est implémenté sur la base d'une machine virtuelle (nous l'appelons Zend VM). Le langage compile le code source PHP en instructions que la machine virtuelle comprend (c'est ce qu'on appelle l'étape de compilation). Les instructions de machine virtuelle obtenues lors de la compilation sont appelées opcodes. Au stade de l'exécution, la VM Zend exécute les opcodes, effectuant ainsi le travail requis.

Ce circuit fonctionne très bien. De plus, des outils comme APC (avant) et OpCache (aujourd'hui) mettent en cache les résultats de l'étape de compilation, cette étape n'est donc exécutée que si nécessaire.

En bref, JIT est une stratégie de compilation juste à temps (au bon moment), dans laquelle le code est d'abord traduit en une représentation intermédiaire, qui se transforme ensuite en un code machine dépendant de l'architecture lors de l'exécution.

En PHP, cela signifie que JIT considérera les instructions pour la machine virtuelle reçues au stade de la compilation comme une représentation intermédiaire et donnera du code machine qui ne sera plus exécuté par la VM Zend, mais directement par le processeur.

Pourquoi PHP a-t-il besoin de JIT?


Peu de temps avant l'avènement de PHP 7.0, l'objectif principal de l'équipe PHP était la performance du langage. La plupart des changements majeurs de PHP 7.0 ont été apportés au correctif PHPNG, ce qui a considérablement amélioré la façon dont PHP utilise la mémoire et le processeur. Depuis lors, chacun de nous doit regarder la performance de la langue.

Après la sortie de PHP 7.0, les améliorations de performances se sont poursuivies: une table de hachage (la structure de données principale en PHP) a été optimisée, la spécialisation de certains opcodes dans Zend VM et la spécialisation de certaines séquences dans le compilateur ont été mises en œuvre, l'Optimizer (composant OpCache) a été constamment amélioré et de nombreux autres changements ont été mis en œuvre.

La dure vérité est qu'à la suite de toutes ces optimisations, nous approchons rapidement de la limite des opportunités d'amélioration de la productivité.

Veuillez noter: par «limite des possibilités d'amélioration», je veux dire le fait que les compromis qui doivent être faits pour de nouvelles améliorations ne semblent plus attrayants. Lorsqu'il s'agit d'optimiser les performances, nous parlons toujours de compromis. Souvent, pour des raisons de productivité, nous devons sacrifier la simplicité. Tout le monde voudrait penser que le code le plus simple est aussi le plus rapide, mais dans le monde moderne de la programmation C, ce n'est pas le cas. Le plus rapide est le code qui est préparé pour tirer parti de la structure interne de l'architecture ou des structures intégrées dans la plateforme / le compilateur. La simplicité seule ne garantit pas de meilleures performances.

Par conséquent, à ce stade, la meilleure façon d'extraire encore plus de performances de PHP est d'implémenter JIT.

JIT va-t-il accélérer mon site?


Très probablement, de façon insignifiante.

Ce n'est peut-être pas la réponse que vous attendiez. Le fait est qu'en général, les applications PHP sont limitées par les entrées / sorties (liées aux E / S), et JIT fonctionne mieux avec du code limité par le processeur (lié aux CPU).

Que signifie «limité par les E / S et le processeur»?


Pour décrire les caractéristiques des performances globales de certains codes ou applications, nous utilisons les termes «limité par entrée-sortie» et «limité par processeur».

La définition la plus simple:

  • le code limité par les E / S fonctionnera beaucoup plus rapidement si nous trouvons un moyen d'améliorer (réduire, optimiser) les opérations d'E / S effectuées;
  • le code limité par processeur fonctionnera beaucoup plus rapidement si nous trouvons un moyen d'améliorer (réduire, optimiser) les instructions exécutées par le processeur ou d'augmenter comme par magie la vitesse d'horloge du processeur.

Le code et l'application peuvent être limités par les E / S, le processeur ou les deux.

En général, les applications PHP ont tendance à être limitées par les E / S: leur principal goulot d'étranglement est souvent les opérations d'E / S - connexion, lecture et écriture à la base de données, caches, fichiers, sockets, etc.

À quoi ressemble le code PHP limité par processeur?


Certains programmeurs PHP sont peut-être nouveaux dans le code limité par le processeur en raison de la nature de la plupart des applications PHP: ils agissent généralement comme un lien vers la base de données ou le cache, récupèrent et produisent de petites quantités de réponses HTML / JSON / XML.

Vous pouvez consulter votre base de code et trouver beaucoup de code qui n'a rien à voir avec les E / S, du code qui appelle des fonctions qui n'ont rien à voir avec les E / S. Et vous pouvez être confus que cela ne rend pas votre application limitée par le processeur, bien que son code ait plus de lignes qui ne fonctionnent pas avec les E / S que le travail.

Le fait est que PHP est l'un des langages interprétés les plus rapides. Il n'y a pas de différence notable entre l'appel d'une fonction qui n'utilise pas les E / S dans Zend VM et dans le code machine. Bien sûr, il y a une différence, mais le code machine et la machine virtuelle Zend utilisent la convention d'appel, donc peu importe -___() vous appelez -___() dans les opcodes ou dans le code machine - cela n'aura pas d'effet notable sur les performances de l'ensemble de l'application qui effectue l'appel.

Remarque: en termes simples, une convention d'appel est une séquence d'instructions exécutées avant d' entrer dans une autre fonction. Dans les deux cas, la convention d'appel transmet des arguments à la pile.

Vous demandez: "Qu'en est-il des boucles, des appels de queue et plus encore?" PHP est assez intelligent - et lorsque l'Optimizer d'OpCache est activé, votre code sera magiquement converti en une version plus efficace de ce que vous avez écrit.

Il convient de noter ici que JIT ne changera pas les conventions d'appel de Zend VM. Cela est dû au fait que PHP doit pouvoir basculer entre les modes JIT et VM à tout moment (ils ont donc décidé de conserver les conventions actuelles). Par conséquent, tous les appels que vous voyez partout en utilisant JIT ne fonctionneront pas beaucoup plus rapidement.

Si vous voulez voir à quoi ressemble le code PHP limité par processeur, jetez un œil ici: https://github.com/php/php-src/blob/master/Zend/bench.php . C'est un exemple extrême, mais il montre que toute la splendeur de JIT se révèle dans les mathématiques.

Dû faire un compromis aussi extrême pour accélérer les calculs mathématiques en PHP?


Non. Nous l'avons fait dans le but d'élargir le champ d'application de la langue (et d'élargir considérablement).

Nous ne voulons pas nous vanter, mais PHP domine le Web. Si vous êtes engagé dans le développement Web et que vous n'envisagez pas d'utiliser PHP dans votre prochain projet, alors vous faites quelque chose de mal (selon un développeur PHP très biaisé).

À première vue, il peut sembler que l'accélération des calculs mathématiques en PHP a une application très étroite. Cependant, cela nous ouvre la voie, par exemple, à l'apprentissage automatique, au rendu 3D, au rendu 2D (GUI) et à l'analyse des données.

Pourquoi cela ne peut-il pas être implémenté en PHP 7.4?


Ci-dessus, j'ai appelé JIT un compromis extrême, et je le pense vraiment: c'est l'une des stratégies de compilation les plus difficiles parmi toutes celles qui existent, sinon la plus difficile. L'implémentation de JIT représente une augmentation significative de la complexité.

Si vous demandez à Dmitry, l'auteur de JIT, s'il a rendu PHP compliqué, il répondra: "Non, je déteste la complexité" (c'est une citation).

Essentiellement, «complexe» signifie «ce que nous ne comprenons pas». Et aujourd'hui, peu de développeurs de langage comprennent vraiment l'implémentation existante de JIT.

Les travaux sur PHP 7.4 progressent rapidement et l'introduction de JIT dans cette version conduira au fait que seuls quelques-uns peuvent déboguer, corriger et améliorer le langage. C'est inacceptable pour ceux qui ont voté contre JIT en PHP 7.4.

Avant la sortie de PHP 8, beaucoup d'entre nous comprendront l'implémentation JIT. Il y a des fonctionnalités que nous voulons implémenter et des outils que nous voulons réécrire pour la huitième version, nous devons donc d'abord comprendre le JIT. Nous avons besoin de ce temps, et nous sommes très reconnaissants à la majorité d'avoir voté pour nous le donner.

Complexe n'est pas synonyme de terrible. La complexité peut être aussi belle qu'une nébuleuse étoilée, et c'est à peu près JIT. En d'autres termes, même lorsque 20 personnes de notre équipe commencent à comprendre le JIT pas pire que Dmitry, cela ne changera pas la complexité de la nature du JIT.

Le développement PHP va-t-il ralentir?


Il n'y a aucune raison de le penser. Nous avons assez de temps, donc on peut affirmer qu'au moment où PHP 8 sera prêt, il y en aura assez parmi nous qui auront suffisamment maîtrisé JIT pour travailler non moins efficacement qu'aujourd'hui lorsqu'il s'agit de corriger des bugs et de développer PHP.

Lorsque vous essayez de relier cela à l'idée de la complexité d'origine de JIT, n'oubliez pas que la plupart du temps que nous passons à introduire de nouvelles fonctionnalités est consacré à leur discussion. Le plus souvent, lorsque vous travaillez sur des fonctionnalités et corrigez des bogues, l'écriture d'un code prend des minutes ou des heures, et les discussions prennent des semaines ou des mois. Dans de rares cas, le code doit être écrit pendant des heures ou des jours, mais même alors, les discussions durent toujours plus longtemps.

C'est tout ce que je voulais dire.

Et puisque nous parlons de performance, j'invite mon collègue Pavel Murzakov au rapport du 17 mai à la conférence PHP Russie. Pasha sait comment extraire la dernière seconde CPU du code PHP!

Source: https://habr.com/ru/post/fr448622/


All Articles