Mikael Randy

Encore un blog …

décembre 30th, 2011

De l’intérêt de la micro-optimisation

Développement, PHP, by Mikael Randy.

Il y a quelques jours, sur Nexen, je tombais sur un article portant sur la micro-optimisation, et peu de temps après, sur une « réponse » de Zenprog.

Comme je trouve le sujet intéressant et que j’ai un avis complémentaire, bien que différent, je me permet dont d’écrire cet article pour l’exposer.

Différence entre temps d’exécution et temps de rendu

Pour ma part, je trouve la micro-optimisation assez peu intéressante dans le sens où elle est micro. Cette optimisation se base en tout et pour tout sur le temps d’exécution brut d’un script PHP, en se demandant si je peux gagner 10% en remplaçant tout mes echo par des print, ou alors en utilisant des  » au lieu de ‘.

Sauf que, dans la vie d’une application web, ce temps n’est rien. Pour enfoncer une porte ouverte, le fonctionnement du web se décompose en plusieurs phases :

  1. Envoi d’une requête : interroger les serveurs DNS, trouver le serveur et ouvrir une connexion avec lui.
  2. Génération de la réponse : le temps d’exécution
  3. Téléchargement du résultat : le temps que le HTML généré par le PHP reviennent sur le client
  4. Interprétation du résultat : le temps que le navigateur interprète le HTML, découvre les ressources nécessaire au rendu
  5. Chargement des ressources annexes (assets) : pour chaque ressource, on repart du début (requête, réponse, téléchargement et interprétation)

Le temps de rendu est l’ensemble des temps nécessaires pour réaliser toutes ces phases.

Prenons l’exemple, au hasard, d’un moteur de recherche bien connu, et analysons le chargement de la page d’accueil :

Analyse du chargement de la homepage

Voici ce que l’on peut apprendre de cette analyse :

  • le temps complet de chargement de la page est de 964ms
  • la requête initiale (requête, génération, téléchargement du résultat) prend 110ms (95ms de génération du résultat)

Il est donc clair que le temps de rendu (le temps nécessaire pour que l’utilisateur puisse utiliser la page) est 9 fois plus important que le temps d’exécution du script sur le serveur. Du coup, gagner 10% sur le temps d’exécution ne fait gagner que 1% sur le temps de rendu.
Et je parle ici de la page d’accueil de Google, qui optimise beaucoup ses chargements, mais pour d’autres sites, moins optimisé, c’est encore pire dès que le nombre de CSS, de JS ou d’images croît.

Optimisez vos chargements

Pour agir de façon drastiquement efficace sur votre temps de rendu, tant que le temps d’exécution est inférieur à 75% du temps de rendu, c’est du côté du chargement qu’il faut chercher.

Pour agir sur le chargement, j’utilise 2 outils : Page Speed et Yslow. Ces outils se basent sur une liste d’optimisations de chargement de pages web.
Je vous conseille de ne pas chercher à atteindre la perfection sur tout les points, mais c’est une bonne base de travail. Je vous conseille également de travailler avec les 2 outils en parallèle, car ils ne sont pas toujours d’accord, et cela permet de pondérer les conseils de chacun.

Micro-optimisation vs. macro-optimisation

Sur ce point, je suis totalement d’accord avec ZenProg : commencer par ce qui apporte réellement un gain de performance à vos sites !

Par expérience, je sais que lorsqu’un script PHP est lent, il faut commencer par traquer les causes suivantes :

  1. Requêtes non optimisées
  2. Schéma de base de données non optimisé
  3. Requêtes dans des boucles
  4. Boucles non optimisées

Requêtes non optimisées

Faire un EXPLAIN PLAN est un minimum vital pour des requêtes un minimum complexe. Dans de (trop) nombreux cas, 80% du temps d’exécution du script est l’oeuvre d’une requête non optimisée qui bloque le PHP

Schéma de base de données non optimisé

Comme le dit ZenProg, un index bien pensé (un index sur le(s) champ(s) sur lequel/lesquels se base les requêtes les plus fréquentes) permet de gagner beaucoup de temps, pour la même raison que pour le point précédent.

Requêtes dans une boucle

L’une des plus grosses fautes de développement, selon moi, c’est de ne pas contrôler les requêtes générées par son code source. Il est très facile de se retrouver dans un cas de figure où une requête est exécutée dans une boucle, surtout avec les frameworks MVC.
Contrôler le nombre de requêtes générées, et travailler sur des données de test réalistes (des dizaines d’enregistrement minimum) permettent donc de se rendre compte quand le nombre de requêtes d’une page semble trop important pour le travail réalisé, et donc se rendre compte qu’on a des requêtes inutiles.

Boucles non optimisées

Je vois trop souvent des algos qui, suite à plusieurs évolutions, se retrouvent avec plusieurs parcours d’un même tableau.
Au final, c’est du temps perdu lors des milliers/millions d’exécution de l’algo, juste parce le développeur n’a pas voulu « perdre » quelques minutes à prendre du recul sur son algo.

La lisibilité du code

Je sais que je sors un peu du sujet, mais je trouve qu’on y perd plus lorsque la micro-optimisation d’un code source rend sa lecture difficile

L’optimisation hors script

Je ne pouvais pas finir cet article portant sur l’optimisation sans parler de l’optimisation que j’appelle « hors site ».
J’entends par là qu’il y a des optimisations qui sont applicables sans se pencher sur un script, mais qui améliorent drastiquement son temps d’exécution :

  • Mettre en place un cache d’Opcode (APC, …)
  • Mettre en place un cache de rendu

Conclusion

Pour moi, bencher si print est plus efficace que echo, c’est de la masturbation intellectuelle pour la plupart des développeurs web que nous sommes.
Après la démonstration que je viens de vous faire, je pense que le jour où vous en serez réduis à remplacer vos print par des echo dans votre code source pour l’optimiser, c’est que vous aurez des besoins en performance très particulier, et que vous aurez déjà éculé les optimisations que je vous ai listées.

Back Top

Responses to “De l’intérêt de la micro-optimisation”

  1. Merci pour cette réponse, qui a le mérite d’insister sur le fait que après tout, le temps de génération d’une page (le temps qu’on peut réduire en optimisant son script PHP — et pas que via de la micro-optimisation !) ne représente finalement qu’une toute petite portion du temps de chargement d’une page…

    Et finalement, l’utilisateur, entre une page qui met 100 ms côté PHP et 5 secondes au total à charger, et une page qui met 120 ms côté PHP et 2 secondes au total à charger, il y a fort à parier qu’il préférera la seconde.
    Dans cette idée, quelque chose d’aussi simple que regrouper quelques fichiers JS et CSS et mettre en place un peu de compression dessus, permet souvent de gagner bien plus, d’un point de vue « utilisateur », que quelques astuces de micro-optimisation.

    J’ai juste tiqué en voyant « des dizaines d’enregistrement minimum » comme taille réaliste pour des données : j’ai plus tendance à considérer qu’il est intéressant de développer sur un jeu de données à l’image de ce qu’on aura en production (dans le cas d’un volume de données qui n’est pas réellement amené à évoluer), ou même sur un jeu de données faisant la taille de ce qu’on aura à moyen terme (six mois / un an) en production.

  2. Merci pour ce retour.

    Pour le nombre d’enregistrement, j’ai hésité avant de le mettre comme ça, et je n’ai pas trouvé de tournure qui me convienne.
    Mon idée est avant tout qu’il faut au moins une dizaine d’enregistrement pour voir apparaitre les soucis de requêtes.
    Travailler avec une volumétrie proche de la réalité va mettre en avant les soucis d’optimisation de requêtes, surtout.

  3. Hey :-) ,

    J’ajouterais que c’est aux développeurs des bibliothèques (comme Symfony, Hoa etc.) de se soucier des performances. Par la suite, les utilisateurs de ces bibliothèques n’ont plus à se poser de problèmes comme tu le soulignes. Ils utilisent des outils et s’ils les utilisent bien, les performances seront là, mais chercher à faire de l’optimisation avec ce genre d’outils ne rime à pas grand chose (tes arguments sont pertinents dans ce cas).

    Chacun son travail je pense et il faut que tous ses mondes communiquent entre eux pour faire remonter leurs exigences respectives. Une certaine écoute et connaissance doit exister :-) .

    Mon commentaire est court mais je sais que tu sauras méditer là dessus ;-) .
    Bonne fête à toi et à ta petite famille (on est très content pour vous soit dit en passant !).

  4. Salut

    Les soucis de requêtes tu les vois pas avec des dizaines d’enregistrement car le SGDB préfère souvent un table scan quand il y a peu de lignes donc même si tu mets des index il ne les utilisera pas forcément.
    Si tu veux travailler les perfs backend faut avoir un volume s’approchant (dans l’idéal dépassant d’un ordre de grandeur) du volume de prod.

  5. @Ivan : Bibliothèque ou pas, ça reste la même chose. Tous les framework ont plus à optimiser au niveau de l’inclusion des fichiers ou sur le fonctionnement général que sur de la micro-optimisation. Par exemple, dans les 1eres versions de Symfony, la principale perte de temps était due au chargement des ressources qui était trop long, puis au système de routing qui était mal pensé.
    Là, pour moi, on est sur de l’optimisation algorithmique, pas sur de la micro-optimisation.
    Et je reprend ma point final, quand tu en es à utiliser la micro-optimisation, c’est que tu veux te masturber intellectuellement.

    @Eric : Effectivement. Comme je le disais à @Pascal, je travaille sur des données représentatives, et j’ai voulu trouver une manière de dire qu’il ne faut pas travailler avec 3 lignes, et je me suis dit que quelques dizaines était déjà pas mal. Mais oui, tu as raison sur le fonctionnement des optimiser SQL qui prennent des raccourcis pour des petites tables.

  6. Si je dois utiliser des bibliothèques, j’attends de son auteur qu’il se soit masturber intellectuellement (ce qui comprend algorithmiquement), sinon je n’ai qu’à faire le taff moi-même. Et bien sûr, en plus, j’attends que des problèmes d’I/O soient réglées (accès aux HDD pour les fichiers PHP, autres ressources, mémoire etc.).

  7. Mais, à nouveau, tes recherches se basent sur un minimum d’algorithmie, ou d’analyse du fonctionnement.
    Optimiser les I/O, c’est du même tonneau que la base de données, parce que c’est une ressource critique pour les performances.

    Mais gagner 1% d’exécution parce que tu utilises print plutôt que echo, c’est de la bullshit.

  8. Dans un contexte Web peut-être, mais tu ne connais pas toujours le contexte d’utilisation de tes bibliothèques ;-) . Je parle d’une généralité après. Dans des cas concrets, tu as raisons et je ne te contre-dis pas, mais à part echo vs. print, les restes des optimisations sont des optimisations algorithmiques :-) .

  9. Effectivement, si nous ne nous mettons pas au même niveau d’analyse, il y a soucis.
    J’ai bien commencé mon article par « dans la vie d’une application web » et l’ai terminé par « pour la plupart des développeurs web que nous sommes. »

  10. Sauf cas très particulier (grosse boucle en PHP, grosses requêtes, etc.), en effet, je constate que la micro-optimisation est un luxe dont on n’a pas toujours besoin… ni le temps. Après, on peut toujours prendre de bonnes habitudes, c’est toujours ça de pris.

    Je constate les mêmes choses côté front-end : certains gagnent 4 caractères avec les notations courtes en CSS… et oublient de factoriser les 3/4 de leurs propriétés ainsi que de gzipper leurs CSS ! ^^

  1. No trackbacks yet.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*