Problème 02 · Performance

CPU performance et profiling

Ce petit sandbox illustre comment un programme mal équilibré peut rapidement monopoliser le CPU sans bénéfice visible. Le jeu rend ce principe facile à aborder : nous lirons sa trace pour visualiser le travail, puis débroussailler le terrain jusqu’aux fonctions responsables.

Chrome DevTools ouvert sur une trace Performance du sandbox arcade : frames, Main thread et capture du jeu pixel art inspiré d’Asteroids.
Le jeu semble animé et innocent. La trace Performance montre pourtant, frame par frame, où le CPU passe réellement son temps.

Profiling basics

Une frame dispose de 16,67 ms à 60 Hz

À 60 Hz, le navigateur doit produire une nouvelle frame environ toutes les 16,67 ms. Nous pouvons chronométrer le travail JavaScript de la simulation et du rendu, puis le comparer à ce frame budget.

HUD du lab affichant la mémoire JavaScript, le temps CPU de la scène en millisecondes par image, le pourcentage du budget à 60 Hz et la cadence.
Le HUD donne ce repère pendant le jeu : temps de la scène, part du budget et cadence.
02-arcade-profiling/src/monitoring/FrameMetrics.js
const FRAME_BUDGET_MS = 1000 / 60;

const averageSceneWorkTime = this.totalSceneWorkTime / this.frameCount;

this.snapshot = {
  sceneBudgetUsed: (averageSceneWorkTime / FRAME_BUDGET_MS) * 100
};

Cette mesure porte uniquement sur le bloc entouré par les deux appels à performance.now(). Elle ne représente ni l’utilisation CPU totale du navigateur, ni tout le travail nécessaire pour afficher la frame. Dans le lab, nous prenons une moyenne sur plusieurs frames pour éviter de surinterpréter un pic isolé.

Première trace dans Performance

Ouvrez les DevTools, puis passez à l’onglet Performance.

Chrome DevTools ouvert sur l’onglet Performance, avec le bouton Record visible.
L’onglet Performance est prêt à enregistrer une trace.
  1. Choisissez une interaction courte et reproductible.
  2. Dans Performance, lancez Record, exécutez cette interaction, puis arrêtez l’enregistrement.
  3. Tentez d’interpréter le résultat.
  4. Utilisez Bottom-Up pour trouver les fonctions coûteuses et Call Tree pour comprendre comment elles ont été appelées.

Le frame budget signale qu’une frame est en danger. La trace Performance explique où le temps a été dépensé.

Provoquer une frame lente

Déclenchez l’attaque spéciale

Lancez un enregistrement, puis appuyez simultanément sur O pour recharger le condensateur et sur X pour déclencher l’attaque spéciale. La salve crée 30 particles dans la même frame : recommencez plusieurs fois pour rendre le pic bien visible.

Retenez surtout l’approche visuelle : les vignettes montrent l’état exact de chaque frame enregistrée, les pistes distinguent le travail du thread principal et du GPU, et Bottom-Up indique quelles fonctions prennent du temps, comme drawImage ici.

Trace Performance de l’attaque spéciale : captures des frames, travail du thread principal, piste GPU et vue Bottom-Up indiquant notamment drawImage.
La trace relie la salve visible aux appels de dessin qui occupent la frame.

Rendre le pic immanquable

100× les particules d’une mine

Pour obtenir un pic nettement plus grand, le lab multiplie par 100 les 32 débris d’une mine détruite. Lancez une trace, détruisez une mine, puis observez la frame qui suit : elle crée 3 200 particles physiques d’un coup.

02-arcade-profiling/src/scenes/JemAsteroidsScene.js
emitExplosion(x, y) {
  this.explosionFlash.emitParticleAt(x, y);
  const particleCount = EXPLOSIONS.particlesPerMine * 100;

  for (let index = 0; index < particleCount; index += 1) {
    const particle = new ExplosionParticle(this);
    this.explosionDebris.add(particle);
    particle.explode(x, y);
  }
}

Bingo

Cette explosion pousse le rendu et le traitement de la frame au-delà des 16,67 ms : ici, elle monte à environ 24 ms. Vous pouvez maintenant croiser ce constat avec les autres techniques de debugging pour vous entraîner sur les prochains cas. Aujourd’hui, l’objectif était simplement de le voir en action.

Trace Performance de l’explosion massive montrant la fonction step de Phaser comme principal coût CPU, avec drawImage, save et restore dans Bottom-Up.
La trace permet de remonter jusqu’à ce qui monopolise le CPU. Ici, le lab délègue le travail lourd à step de Phaser : le moteur fait son travail, et c’est très bien.

Essayez. Explorez, bidouillez, faites planter le navigateur avec des quantités absurdes de particles. Ou jouez, tout simplement. Vous vouliez une session de debugging avancé et des jeux vidéo ? Vous avez les deux. Heureux ? #ThatsWhatSheSaid

C’est volontairement excessif. Comme les débris ne sont pas détruits dans cette version du lab, rechargez la page après la trace avant de recommencer.

Simuler une machine moins rapide

Ralentissez le CPU

Dans les réglages d’environnement de Performance, le menu CPU permet de simuler une machine moins rapide. Réglez-le sur 20× slowdown, puis rejouez la même courte trace : les problèmes plus discrets ressortent alors plus facilement.

Réglages d’environnement de Chrome DevTools avec le CPU réglé sur 20× slowdown.
Le ralentissement CPU se règle dans les paramètres d’environnement de Performance.

Sur une machine moderne, le lab fait de son mieux pour rendre ce ralentissement visible : il utilise volontairement le renderer Canvas de Phaser plutôt que WebGL. Cela limite autant que possible le travail confié au GPU, afin que le coût de dessin ressorte dans la trace CPU.

Configuration Phaser du lab avec le renderer Canvas sélectionné.
Le lab choisit explicitement Phaser.CANVAS.