Profilage à l'aide d'instruments

Dans l'équipe d'assistance aux entreprises, nous voyons beaucoup de projets iOS. À un moment donné, dans tout développement iOS, les développeurs finissent souvent par lancer leur jeu et par se demander "Pourquoi diable ce jeu tourne-t-il si lentement ? Il existe d'excellents outils d'analyse des performances et l'un des meilleurs est Instruments. Lisez la suite pour savoir comment l'utiliser pour trouver vos problèmes !
Pour utiliser Instruments, ou tout autre outil de débogage de XCode, vous devez construire un projet Unity pour la cible de construction iOS (avec les options de construction de développement et de débogage de script décochées). Vous devrez ensuite compiler le projet XCode résultant avec XCode en mode Release et le déployer sur un appareil iOS connecté.
Après avoir démarré Instruments (en appuyant longuement sur le bouton de lecture ou en sélectionnant Produits>Profil), sélectionnez le Time Profiler. Pour commencer un profilage, sélectionnez l'application construite dans le sélecteur d'application, puis appuyez sur le bouton rouge Enregistrer. L'application sera lancée sur l'appareil iOS avec les instruments connectés, et le Time Profiler commencera à enregistrer la télémétrie. La télémétrie apparaît sous la forme d'un graphique bleu sur la ligne de temps des instruments.

P.S. Pour nettoyer la hiérarchie des appels, appuyez sur le bouton Call Tree en bas à gauche du panneau Details pour afficher les options et sélectionnez Flatten Recursion et Hide System Libraries.

Une liste des appels de méthode apparaît dans la section détaillée de la fenêtre Instruments. Chaque appel de méthode de niveau supérieur représente un thread au sein de l'application.
En général, la méthode principale est l'emplacement de tous les points chauds d'intérêt, car elle contient tout le code géré.
Le développement de la méthode principale permet d'obtenir une arborescence profonde d'appels de méthodes. La branche principale se situe entre deux méthodes :
- [startUnity] et UnityLoadApplication (ces noms de méthodes apparaissent parfois en TOUTES CAPS).
- PlayerLoop
[startUnity] est intéressant car il contient tout le temps passé à initialiser le moteur Unity. Une méthode nommée UnityLoadApplication se trouve en dessous. C'est sous UnityLoadApplication que le temps de démarrage peut être profilé.

Une fois que vous avez obtenu une belle tranche temporelle de votre application, mettez le Profiler en pause et commencez à développer l'arbre. Au fur et à mesure que vous descendez dans l'arbre, vous remarquerez que le temps en ms diminue dans la colonne de gauche. Ce que vous recherchez, ce sont des éléments qui entraînent une réduction significative du temps. Il s'agira d'un point névralgique de la performance. Une fois que vous en avez trouvé un, vous pouvez revenir à votre base de code et découvrir ce qui prend tant de temps. Il se peut qu'il s'agisse d'une opération totalement nécessaire, ou qu'à un moment donné, dans un passé lointain, vous ayez piraté un code de pré-production qui s'est retrouvé dans votre projet de production, ou... eh bien... il pourrait y avoir un million de raisons en réalité. C'est à vous de décider si vous voulez corriger ce problème ou comment vous voulez le faire, car vous connaissez votre code mieux que quiconque :D
Les instruments peuvent également être utilisés pour rechercher les pertes de performances qui sont largement réparties - celles qui n'ont pas de point névralgique unique, mais qui se manifestent plutôt par quelques millisecondes de temps perdu dans de nombreux endroits différents d'une base de code. Pour ce faire, tapez un nom de fonction partiel ou complet dans la boîte de recherche de symboles d'Instruments, affichée en appuyant sur ⌘F ou en cliquant sur Find/Find... dans le menu Edit. Pour établir le profil d'une tranche de jeu, développez PlayerLoop et réduisez toutes les méthodes qui se trouvent en dessous. Si vous souhaitez établir le profil du temps de démarrage, développez UnityLoadApplication et réduisez les méthodes qui se trouvent en dessous. Le nombre total de millisecondes gaspillées pour une opération spécifique peut être grossièrement estimé en regardant le temps total passé dans PlayerLoop ou UnityLoadApplication et en soustrayant le nombre de millisecondes situé dans la colonne "self".
Méthodes courantes à rechercher :
- "Box(", "box" et "box" - ils indiquent qu'il y a une mise en boîte des valeurs en C# ; la plupart des cas de mise en boîte sont trivialement corrigés.
- "Concat" - la concaténation de chaînes de caractères est souvent facilement optimisée.
- "CreateScriptingArray" - Toutes les API Unity qui renvoient des tableaux alloueront de nouvelles copies des tableaux. Réduire au minimum les appels à ces méthodes.
- "Réflexion" - la réflexion est lente. Utilisez ces données pour estimer le temps perdu en réflexion et l'éliminer dans la mesure du possible.
- "FindObjectOfType" - Permet de localiser les appels répétés ou inutiles à FindObjectOfType, ou à d'autres API Unity connues pour leur lenteur.
- "Linq" - Examinez le temps perdu à créer et à rejeter des requêtes Linq ; envisagez de remplacer les points chauds par des méthodes optimisées manuellement.
Outre le profilage du temps de l'unité centrale, Instruments vous permet également d'établir le profil de l'utilisation de la mémoire. Le profileur d'Allocations d'Instruments fournit deux sondes qui offrent des vues détaillées de l'utilisation de la mémoire d'une application. La sonde Allocations permet d'inspecter les objets résidant dans la mémoire pendant une période donnée. La sonde VM Tracker permet de surveiller la taille du tas de mémoire sale, qui est la principale mesure utilisée par iOS pour déterminer quand une application doit être fermée de force.
Les deux sondes seront exécutées simultanément lors de la sélection du profileur Allocations dans Instruments. Comme d'habitude, commencez un profilage en appuyant sur le bouton rouge d'enregistrement.
Pour configurer correctement la sonde Allocations, assurez-vous que les paramètres suivants sont corrects. En bas de la fenêtre, assurez-vous que l'option Durée de vie de l'allocation (option du milieu) est réglée sur Créé et persistant. Dans les options d'enregistrement (menu Fichier), assurez-vous que l'option Ignorer les événements pour la mémoire libérée est cochée.
L'affichage le plus utile pour examiner le comportement de la mémoire est l'affichage des statistiques, qui est l'affichage par défaut lors de l'utilisation de la sonde Allocations. Cet écran affiche une ligne de temps. Lorsqu'il est utilisé avec les paramètres recommandés, le graphique affiche des lignes bleues indiquant la durée et l'ampleur des allocations de mémoire encore en cours. En observant ce graphique, vous pouvez détecter les fuites de mémoire ou les mémoires de longue durée en répétant simplement le scénario testé et en veillant à ce qu'aucune ligne bleue ne subsiste entre les exécutions.
Un autre affichage utile est celui des arbres d'appel. Il affiche la ligne de code à laquelle les allocations sont effectuées, ainsi que la quantité de mémoire consommée par cette ligne de code. Vous pouvez modifier l'affichage en cliquant à droite de Détails, comme indiqué ici :

Vous pouvez voir ci-dessous qu'environ 25 % de l'utilisation totale de la mémoire de l'application testée est uniquement due aux nuanceurs. Étant donné que l'emplacement des shaders se trouve dans le thread de chargement, il doit s'agir des shaders standard fournis avec les projets Unity par défaut, qui sont ensuite chargés au moment du démarrage de l'application.

Comme précédemment, une fois que vous avez identifié un hotspot, ce que vous en faites dépend totalement de votre projet.
Et voilà. Un petit guide des instruments. 1000(ish) mots et pas de références à A-Team. Nous ne voulons pas avoir de problèmes comme la dernière fois. Les violations du droit d'auteur ne sont officiellement pas drôles™.
L'équipe Enterprise Support est en train de créer d'autres guides, et nous publierons les versions complètes de nos guides de bonnes pratiques dans les mois à venir !
Nous aimons qu'un plan se concrétise.
