Le framework Flutter fonctionne bien et rapidement par défaut, mais cela signifie-t-il que vous n'avez pas du tout besoin de penser aux performances? Non. Il est absolument réel d'écrire des applications Flutter qui seront lentes. D'autre part, vous pouvez également utiliser le framework au maximum et rendre vos applications non seulement rapides, mais aussi efficaces, consommant moins de temps processeur et batterie.

Voici ce que nous voulons voir: un résultat statistiquement significatif de la comparaison de deux versions de votre application par une métrique significative. Lisez la suite pour savoir comment.
Il existe quelques directives générales pour optimiser les performances dans Flutter:
- Engagez le moins de widgets possible lors de la mise à jour de l'état.
- Mettre à jour l'état uniquement lorsque cela est nécessaire.
- Supprimez les tâches gourmandes en calcul de vos méthodes de
build
et, idéalement, de l'isolat principal.
La triste vérité est que pour de nombreuses questions sur l'optimisation des performances, la réponse sera «quelle chance». Cette optimisation particulière vaut-elle l'effort et le coût de maintenance pour ce widget particulier? Cette approche particulière a-t-elle un sens dans cette situation particulière?
La seule réponse utile à ces questions est le test et la mesure. Quantifiez la façon dont chaque choix affecte les performances et prenez des décisions en fonction de ces données.
La bonne nouvelle est que Flutter fournit d'excellents outils de profilage des performances comme Dart DevTools (actuellement dans la version d'aperçu), qui comprend l'inspecteur Flutter, ou vous pouvez utiliser l' inspecteur Flutter directement à partir d'Android Studio (avec le plugin Flutter installé). Vous disposez d'un Flutter Driver
pour tester votre application et le Profile mode
pour enregistrer les informations de performances.
La mauvaise nouvelle est que les smartphones modernes sont trop intelligents.
Le problème avec les régulateurs
La quantification des performances des applications Flutter est particulièrement difficile pour les contrôleurs iOS et Android. Ces démons au niveau du système contrôlent la vitesse des processeurs centraux et graphiques en fonction de la charge. Bien sûr, cela est bon, car il offre un fonctionnement fluide avec une consommation de batterie réduite.
L'inconvénient est que vous pouvez rendre votre application beaucoup plus rapide en augmentant la quantité de travail qu'elle effectue.
Vous pouvez voir ci-dessous comment l'ajout d'un cycle d'appels d'impression sans signification à l'application a fait passer le régulateur à une fréquence accrue, ce qui a rendu l'application beaucoup plus rapide et ses performances plus prévisibles.

Le problème avec les régulateurs: par défaut, vous ne pouvez pas faire confiance à vos numéros. Dans ce diagramme d'étendue, nous avons des exécutions distinctes sur l'axe x (marquées par l'heure exacte à laquelle elles ont commencé) et le temps de génération sur l'axe Y. Comme vous pouvez le voir, lorsque nous introduisons des instructions d'impression complètement inutiles, cela conduit au fait que le temps de construction diminue mais pas en place.
Dans cette expérience, le pire code a entraîné un temps de construction plus rapide (voir ci-dessus), un temps de tramage plus rapide et une fréquence d'images plus élevée. Lorsqu'un code objectivement pire conduit à des indicateurs de performance améliorés, vous ne pouvez pas vous fier à ces indicateurs comme guide (recommandation).
Ce n'est qu'un exemple de la façon dont les tests de performances des applications mobiles peuvent être intuitifs et complexes.
Ci-dessous, je partage quelques-uns des conseils que j'ai rassemblés en travaillant sur l'application Developer Quest de Flutter pour Google I / O.
Conseils généraux
- Ne mesurez pas les performances en mode débogage (
DEBUG mode
). Mesurez les performances uniquement en Profile mode
profil. - Mesurez sur un appareil réel, pas sur iOS Simulator ou Android Emulator. Les émulateurs logiciels sont parfaits pour le développement, mais ont des caractéristiques de performances différentes des vraies. Flutter ne vous permettra pas de travailler en mode profilage sur un appareil simulé, car cela n'a aucun sens. Les données que vous collectez de cette manière ne s'appliquent pas aux performances réelles.
- Idéalement, utilisez exactement le même appareil physique. Faites-en votre appareil de test de performances dédié et ne l'utilisez jamais pour autre chose.
- Découvrez les outils de profilage des performances Flutter.
Régulateurs CPU / GPU
Comme indiqué ci-dessus, les systèmes d'exploitation modernes modifient la fréquence de chaque processeur et GPU à leur disposition en fonction de la charge et de certaines autres heuristiques. (Par exemple, toucher l'écran augmente généralement la vitesse de votre téléphone Android.)
Sur Android, vous pouvez désactiver ces contrôles. Nous appelons ce processus «verrouillage de mise à l'échelle».
- Créez un script qui désactive les commandes de votre appareil pour tester les performances. Vous pouvez utiliser l' exemple Skia pour vous inspirer. Vous pouvez également consulter l' API CPU Unix .
- Vous voudrez peut-être quelque chose de moins polyvalent et plus léger si vous ne faites pas autant de tests que Skia. Consultez le script shell dans Developer Quest pour voir où aller. Par exemple, la partie suivante du script définit la CPU pour le contrôleur d'espace utilisateur (le seul contrôleur qui ne modifie pas la fréquence du processeur lui-même).
- Votre objectif ici n'est pas de simuler des performances réelles (les utilisateurs n'éteignent pas les régulateurs sur leurs appareils), mais d'avoir des indicateurs de performances comparables entre les démarrages.
- À la fin, vous devez expérimenter et adapter le script shell au périphérique que vous utiliserez. Cela fonctionne, mais jusqu'à ce que vous le fassiez, vos données de performances vous tromperont.

Une première version de Developer Quest, testée avec le pilote Flutter sur mon bureau.
Pilote de flottement
Flutter Driver vous permet de tester automatiquement votre application. Lisez la section «Performance Profiling» sur flutter.dev pour savoir comment l'utiliser lors du profilage de votre application.
- Pour tester les performances, ne testez pas manuellement votre application. Utilisez toujours le pilote Flutter pour obtenir des données vraiment indicatives.
- Écrivez votre code de pilote Flutter pour qu'il vérifie ce que vous voulez vraiment mesurer. Si vous avez besoin des performances globales de l'application, essayez de parcourir toutes les parties de l'application et faites ce que l'utilisateur ferait.
- Si votre application comporte un élément de caractère aléatoire (
Random
, événements de réseau, etc.), créez un "faux" pour de telles situations. Les tests doivent être aussi proches les uns des autres que possible. - Si vous le souhaitez, vous pouvez ajouter des événements personnalisés à la chronologie à l'aide des
startSync()
et finishSync()
de la classe Timeline . Cela peut être utile si vous êtes intéressé par les performances d'une fonction particulière. Mettez startSync()
à son début et finishSync()
à sa fin. - Enregistrez à la fois le résumé ( writeSummaryToFile ) et, plus important encore, la chronologie brute ( writeTimelineToFile ).
- Testez plusieurs fois chaque version de votre application. Pour Developer Quest, j'ai passé 100 démarrages. (Lorsque vous mesurez des choses qui peuvent être bruyantes, comme l'utilisation de la métrique p99, vous pourriez avoir besoin de beaucoup plus d'exécutions.) Pour les systèmes basés sur POSIX, cela signifie simplement faire quelque chose comme ceci:
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
.

Outil de chronologie de Chrome pour vérifier les résultats de profilage dans Flutter.
Chronologie
La chronologie est la sortie brute de vos résultats de profilage. Flutter écrit ces informations dans un fichier JSON, qui peut être téléchargé dans chrome://tracing
.
- Découvrez comment ouvrir la chronologie complète dans Chrome. Vous ouvrez simplement
chrome://tracing
dans le navigateur Chrome, cliquez sur «Charger» et sélectionnez le fichier JSON. Vous pouvez en lire plus dans ce petit guide . (Il existe également un outil de chronologie Flutter qui se trouve actuellement dans l'aperçu technique. Je ne l'ai pas utilisé car le projet Developer Quest a été lancé avant que les outils Flutter ne soient prêts.) - Utilisez les touches WSAD pour parcourir la chronologie dans
chrome://tracing
et 1234 pour changer les modes de fonctionnement. - Lorsque vous configurez les tests de performances pour la première fois, envisagez d'exécuter Flutter Driver avec l'outil Systrace Android. Cela vous donne une meilleure idée de ce qui se passe réellement dans l'appareil, y compris des informations sur la mise à l'échelle de la fréquence du processeur. Ne mesurez pas l'application entière avec Systrace, car cela rendra tout plus lent et moins prévisible.
- Comment exécuter Android Systrace avec Flutter Driver? Tout d'abord, lancez Android Systrace avec
/path/to/your/android/sdk/platform-tools/systrace/systrace.py --atrace-categories=gfx,input,view,webview,wm,am,sm,audio,video,camera,hal,app,res,dalvik,rs,bionic,power,pm,ss,database,network,adb,pdx,sched,irq,freq,idle,disk,load,workq,memreclaim,regulators,binder_driver,binder_lock
. Ensuite, flutter run test_driver/perf.dart --profile --trace-systrace
application flutter run test_driver/perf.dart --profile --trace-systrace
. Enfin, exécutez Flutter Driver flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/
(où NNNNN est le port qui vous donne l'application de flutter à exécuter ci-dessus).
Mesures
Il vaut mieux regarder autant de métriques que possible, mais j'ai décidé que certaines sont plus utiles que d'autres.
Le temps de génération et le temps de pixellisation (les métriques fournies par défaut à l'aide de TimelineSummary
) ne sont utiles que pour les tests de performances vraiment difficiles, qui ne comprennent pas grand-chose d'autre que la création d'une interface utilisateur.
Ne considérez pas TimelineSummary.frameCount
comme un moyen de calculer des images par seconde (FPS). Les outils de profilage Flutter ne fournissent pas d'informations sur la fréquence d'images réelle. TimelineSummary
fournit la méthode countFrames()
, mais elle ne compte que le nombre d'assemblages de trames terminés. Une application bien optimisée qui limite les reconstructions (mises à jour) inutiles aura un FPS inférieur à une application non optimisée qui reconstruit fréquemment.
Personnellement, j'obtiens les données les plus utiles en mesurant le temps processeur total passé à exécuter le code Dart. Cela compte le code exécuté à la fois dans vos méthodes de build
et en dehors. En supposant que vous exécutez des tests de profilage sur un appareil verrouillé à l'échelle, le temps total du processeur peut être considéré comme une bonne approximation de la quantité de batterie plus / moins consommée par votre application.

Le moyen le plus simple de connaître le temps processeur total passé à exécuter le code Dart est d'estimer le nombre d'événements MessageLoop:FlushTasks
sur la chronologie. Pour Developer Quest, j'ai écrit un outil Dart pour les extraire.
Pour rechercher les fichiers indésirables (corbeille) (c'est-à-dire les images perdues), recherchez les extrêmes. Par exemple, pour un cas spécifique de Developer Quest et le périphérique sur lequel nous avons testé, il est utile de jeter un œil au temps de génération du 95e centile. (Le temps de génération du 90e centile était trop similaire, même si vous comparez le code avec des niveaux de performances complètement différents, et les nombres du 99e centile sont généralement bruyants. Vos performances peuvent varier.)

Comme mentionné ci-dessus, testez chaque version de votre application plusieurs (peut-être 100) fois. Utilisez ensuite des données moyennes ou centiles avec des champs d'erreur. Mieux encore, utilisez des tableaux de répartition.
Résultats
Après le réglage, vous pouvez comparer en toute confiance les validations et mener des expériences. Ci-dessous, vous pouvez voir la réponse à un dilemme commun: "cette optimisation des coûts de maintenance en vaut-elle la peine?"

Je pense que dans ce cas particulier , la réponse est oui. Grâce à quelques lignes de code, chaque passage automatisé de notre application prend en moyenne 12% de temps CPU en moins.
Mais - et c'est le principal message de cet article - les mesures d'une autre optimisation peuvent montrer quelque chose de complètement différent. Il est tentant mais erroné d'essayer d'extrapoler une mesure de performance trop largement.
En d'autres termes: "quelle chance." Et nous devons le supporter.