Skip to Content

Chapitre 15.2 — Profiler & performance

Partie 15 : Expert — Chapitre 2/9 Version de référence : Symfony 7.4 / Blackfire.

⏱️ TL;DR

  • Mesurez avant d’optimiser. L’optimisation prématurée fait perdre du temps sur des non-problèmes. On profile, on trouve le vrai goulot, on corrige, on re-mesure.
  • En dev, le profiler montre tout : temps, requêtes SQL, mémoire, événements, cache. Le compteur de requêtes révèle les N+1 (Partie 6.6).
  • En prod-like, Blackfire profile finement (graphe d’appels, comparaisons avant/après) sans polluer le code.
  • Goulots classiques : N+1 (n°1), sérialisation lourde, trop de services instanciés, requêtes non indexées, absence de cache.
  • Le composant Stopwatch mesure des sections précises ; l’OPcache preloading accélère le bootstrap en prod.
  • Pour un dev Next.js : profiler ≈ les DevTools/React Profiler côté serveur ; Blackfire ≈ un profiler applicatif dédié (façon Datadog APM ciblé perf).

🎯 Objectifs

  • Adopter la démarche « mesurer → corriger → re-mesurer ».
  • Lire le profiler et repérer les goulots.
  • Utiliser Blackfire et Stopwatch.
  • Connaître les optimisations prod (OPcache preloading).

1. La règle d’or : mesurer d’abord

Le réflexe fatal est d’optimiser au jugé (« ça doit être lent ici »). Presque toujours, le vrai goulot est ailleurs. La démarche saine :

On corrige un goulot à la fois et on vérifie le gain. « Optimiser » sans mesure produit du code plus complexe pour un gain nul (voire négatif).

⚠️ Piège de l’optimisation prématurée : réécrire du code « pour la perf » avant d’avoir mesuré est une perte de temps et une source de bugs. 90 % du temps se passe souvent dans 10 % du code — trouvez ces 10 % par la mesure, pas à l’intuition. « Premature optimization is the root of all evil » (Knuth) reste vrai.

2. Le profiler (dev)

En dev, chaque page HTML affiche la barre de debug ; un clic ouvre le profiler (/_profiler). Il détaille, par requête :

  • le temps total et par phase (événements du noyau, contrôleur) ;
  • les requêtes SQL (nombre, durée, doublons → N+1) ;
  • la mémoire consommée ;
  • le cache (hits/miss), les événements, la sécurité, le Messenger.

C’est votre premier outil : avant toute optimisation, ouvrez le profiler sur la page lente et regardez part le temps. Le plus souvent : trop de requêtes SQL (N+1) — qu’on corrige par fetch join (Partie 6.6).

3. Blackfire (profiling fin)

Le profiler dev est pratique mais impacte les mesures (il instrumente tout). Pour un profiling précis, y compris en prod-like, on utilise Blackfire : il produit un graphe d’appels (quelle fonction consomme quoi), permet de comparer deux profils (avant/après une optimisation), et de poser des assertions de perf (« cette page doit faire moins de X requêtes SQL ») — intégrables en CI.

Blackfire répond précisément à « exactement part le temps/la mémoire ? » sur le vrai chemin d’exécution, sans deviner.

4. Les goulots classiques (et leurs corrections)

GoulotSymptôme (profiler)Correction
N+1beaucoup de requêtes SQL identiquesfetch join / DTO (6.6)
Requête non indexée1 requête très lenteindex (6.6)
Sérialisation lourdetemps dans le serializergroupes minimaux, DTO (11.2)
Pas de cacherecalcul à chaque requêtecomposant Cache (15.1)
Trop de servicesbootstrap lentservices lazy, revoir les dépendances
Rendu Twig lourdtemps dans les templatescache de fragments, ESI

Le N+1 reste, de loin, le problème n°1 — d’où l’insistance depuis la Partie 6.

5. Mesurer une section précise : Stopwatch

Pour mesurer un bout de code spécifique (pas toute la requête), le composant Stopwatch :

use Symfony\Component\Stopwatch\Stopwatch; $stopwatch = new Stopwatch(); $stopwatch->start('import'); // ... code à mesurer $event = $stopwatch->stop('import'); $this->logger->info('Import terminé', ['duration_ms' => $event->getDuration()]);

Les sections mesurées apparaissent aussi dans le profiler (timeline), pour voir leur poids relatif.

6. Optimisations de production

En prod, plusieurs leviers hors code :

  • OPcache : compile et cache le bytecode PHP (activé en prod). Preloading : précharge les classes du framework au démarrage du serveur → bootstrap plus rapide (opcache.preload).
  • Composer : --optimize-autoloader --classmap-authoritative (autoload figé, plus rapide).
  • APP_ENV=prod + cache:clear/cache:warmup : config compilée, conteneur figé (Partie 5.4).
  • FrankenPHP worker mode (chapitre suivant) : bootstrap une fois → gain majeur.

💡 Pour un dev Next.js : la démarche « mesurer d’abord » est universelle (vous connaissez le React Profiler, Lighthouse). Blackfire ≈ un APM ciblé perf (Datadog/New Relic pour la partie profiling). Et — comme côté Next où vous surveillez le bundle et les re-renders — côté Symfony vous surveillez les requêtes SQL et le bootstrap. Le N+1 est l’équivalent backend du « re-render en boucle » : invisible en petit, dévastateur en grand.

✏️ Exercices

Exercice 1. Une page de liste est lente. Quelle est la première chose à regarder dans le profiler, et le goulot le plus probable ?

✅ Solution

Le nombre de requêtes SQL (onglet Doctrine du profiler). Le goulot le plus probable sur une liste est le N+1 : une requête pour la liste + une par ligne pour charger une relation (Partie 6.6). Correction : fetch join (->join(...)->addSelect(...)) ou projection DTO. On mesure avant/après pour confirmer le gain.

Exercice 2. Pourquoi « optimiser » sans mesurer est-il contre-productif ?

✅ Solution

Parce que le vrai goulot est presque toujours ailleurs que là où on l’imagine : on complexifie du code (source de bugs) pour un gain nul sur des non-problèmes, tout en laissant le vrai goulot en place. La perf se concentre souvent dans un petit % du code — qu’on trouve par la mesure (profiler/Blackfire), pas à l’intuition. On corrige un goulot, on re-mesure, on itère.

Exercice 3. Citez deux optimisations de production hors code.

✅ Solution

Au choix : OPcache (+ preloading des classes du framework) pour un bytecode compilé et un bootstrap rapide ; composer install --optimize-autoloader (autoload figé) ; APP_ENV=prod avec cache:warmup (config compilée) ; FrankenPHP worker mode (bootstrap unique). Ce sont des gains obtenus par la configuration/l’infra, sans toucher au code applicatif.

🧠 Quiz de révision

1. Quelle est la règle d’or de la performance ?

Mesurer avant d’optimiser : profiler → identifier le vrai goulot → corriger → re-mesurer. Éviter l’optimisation prématurée.

2. Que révèle le profiler sur une page lente ?

Le temps par phase, les requêtes SQL (dont les N+1), la mémoire, le cache, les événements — pour voir part le temps.

3. Qu’apporte Blackfire par rapport au profiler dev ?

Un profiling fin (graphe d’appels), des comparaisons avant/après et des assertions de perf (CI), en prod-like, sans polluer le code.

4. Quel est le goulot backend n°1 ?

Le N+1 (requêtes en boucle sur une relation), corrigé par fetch join / DTO.

5. Que fait l’OPcache preloading ?

Il précharge les classes du framework au démarrage du serveur → bootstrap plus rapide en production.


Prochain chapitre : 15.3 — FrankenPHP worker mode — bootstrapper une fois, servir mille fois.