Construire un benchmark de navigateur incapable de se figer
Les benchmarks échouent de façons embarrassantes. Ils se figent à 97%. Ils annoncent un chiffre qui varie de 30% d’un essai à l’autre. Ils attribuent à votre portable un score plus faible parce qu’il a un meilleur écran. En reconstruisant le nôtre pour la 2.0, nous avons gardé la liste de ces modes de défaillance scotchée au-dessus du bureau, et travaillé contre chacun d’eux en particulier. Voici quelques notes prises en chemin.
Inverser la mesure
Charge fixe et FPS mesurés : c’est la forme traditionnelle, et dans un navigateur elle ne sert presque à rien. Les machines rapides se collent à la fréquence de rafraîchissement de l’écran — le navigateur ne rend pas plus vite que la synchronisation verticale, donc tout ce qui est bon rapporte « 60 » ou « 120 » — et les machines lentes produisent un diaporama qui mesure votre patience, pas leurs performances.
Nous avons donc figé la cible — un budget de 16,67 ms par image — et fait de la charge la variable. Chaque scène augmente son nombre de particules jusqu’à ce que les images dépassent le budget, cherche la frontière par dichotomie, puis exige trois fenêtres de confirmation propres consécutives avant d’accepter un niveau. Le résultat, la « charge stable maximale », a un sens physique que l’on peut se représenter : cette machine pousse 840 000 particules de nébuleuse avant de commencer à perdre des images.
Un benchmark inversé échoue aussi proprement par construction. Un appareil modeste ne produit pas un test cassé : il se stabilise simplement sur un barreau plus bas de la même échelle.
Des percentiles, parce que les saccades mentent
Chaque fenêtre est jugée sur son temps d’image moyen et sur son 95e percentile. Le critère p95 existe parce que les moyennes blanchissent les saccades : une machine qui rend 95 images à l’heure et 5 à 40 ms est désagréable à l’usage mais affiche une moyenne correcte. Les seuils sur percentile, c’est la façon de transformer « ça saccade » en chiffre. Une fenêtre anormale isolée — une notification, une pause du ramasse-miettes — est rejouée plutôt que comptée, mais deux échecs consécutifs refusent le niveau. Indulgent avec les accidents, intraitable avec les tendances.
La machine à états paranoïaque
L’exigence « ne peut pas se figer » a produit le code le moins glorieux et le plus porteur du projet. Chaque scène exécute une machine à états — contrôle préalable, référence, chauffe, montée en charge, encadrement, confirmation, ancrage — et chaque état possède une sortie stricte :
- à l’époque de la 2.0, une scène disposait de 30 secondes et un test complet de 150, un point c’est tout ;
- passer l’onglet en arrière-plan annule la fenêtre de mesure en cours et met en pause ; au-delà de 30 secondes masqué, le test se termine avec une raison nommée ;
- un redimensionnement ou un changement de rapport de pixels reconstruit la scène et refait la chauffe plutôt que de mesurer n’importe quoi ;
- une perte de contexte WebGL, un GPU coincé (aucune image pendant plusieurs secondes), une scène qui lève une exception : chacun correspond à sa propre raison de sortie, et un chien de garde continue de battre même quand la boucle de rendu ne le peut plus ;
- la touche Échap fonctionne pendant chacun de ces états, parce qu’un bouton d’annulation qui ne marche que lorsque tout va bien n’est pas un bouton d’annulation.
Le test peut se terminer plus tôt, dégradé ou annulé. La seule chose qu’il ne peut pas faire, c’est rester planté là.
Honnêteté thermique
Une charge GPU soutenue chauffe la machine ; une machine chaude ralentit ; un benchmark qui l’ignore mélange en silence la meilleure minute de votre appareil avec sa pire. Chaque scène mesure donc deux fois une charge de référence légère — une fois au début, une fois à la fin. Si la seconde lecture est plus lente de plus de 15%, la scène est marquée dégradée, la marque survit jusque dans la fiche de résultats et dans le score (une déduction plafonnée) et, si vous envoyez un échantillon, jusque dans le jeu de données : les médianes publiques peuvent ainsi exclure les tests bridés au lieu de les absorber.
Équité face au haut rafraîchissement
Un piège subtil : jugé naïvement à l’aune de son propre intervalle de rafraîchissement, un portable à 120 Hz devrait rendre chaque image en 8,3 ms pour « tenir son rafraîchissement » — soit le double de l’exigence imposée à une machine en 60 Hz. Notre budget est fixé à 16,67 ms pour tout le monde. Les écrans à haute fréquence ressentent toujours leur avantage — ils affichent les images supplémentaires quand la charge est légère — mais la ligne de réussite se situe au même endroit sur toutes les dalles. Votre moniteur est un choix de confort ; le travail du benchmark est de mesurer l’ordinateur qui se trouve derrière.
Ce que nous avons délibérément laissé de côté
Pas encore de WebGPU : s’il arrive, ce sera comme profil séparé avec son propre espace de score, jamais échangé en douce sous le même chiffre. Pas de web workers pour le rendu dans cette version : la surface de panne ajoutée — mort du worker, transfert de contexte, entrées inter-threads — se heurtait à l’exigence de non-blocage, et la charge mesurée est identique dans les deux cas. Et aucune affirmation en percentiles sur la fiche de résultats tant que le jeu de données anonyme n’aura pas franchi de vrais seuils d’échantillonnage : un percentile calculé sur quarante tests n’est qu’une impression déguisée en chiffre.
La spécification complète, calcul du score compris, est rédigée dans la méthodologie. Si vous trouvez un appareil où l’un des points ci-dessus ne tient pas, c’est un bug : admin arobase screentest.pro.