iOS Time Profiler


Exemple

Le premier instrument que vous regardez est le Time Profiler . À des intervalles mesurés, Instruments arrêtera l'exécution du programme et effectuera une trace de pile sur chaque thread en cours d'exécution. Pensez-y en appuyant sur le bouton pause dans le débogueur de Xcode. Voici un aperçu du Time Profiler: -

Cet écran affiche l' Call Tree . L' Call Tree indique le temps passé à exécuter différentes méthodes dans une application. Chaque ligne est une méthode différente du chemin d'exécution du programme. Le temps passé dans chaque méthode peut être déterminé à partir du nombre de fois où le profileur est arrêté dans chaque méthode. Par exemple, si 100 échantillons sont effectués à intervalles de 1 milliseconde et qu'une méthode particulière se trouve au sommet de la pile dans 10 échantillons, vous pouvez en déduire qu'environ 10% du temps d'exécution total - 10 millisecondes - a été utilisé. dans cette méthode. C'est une approximation assez grossière, mais ça marche!

Dans Xcode's barre de menus Xcode's , sélectionnez Product\Profile ou press ⌘I . Cela va construire l'application et lancer des instruments. Vous serez accueilli avec une fenêtre de sélection qui ressemble à ceci:

Ce sont tous des modèles différents fournis avec Instruments.

Sélectionnez l'instrument Time Profiler et cliquez sur Choisir. Cela ouvrira un nouveau document sur les instruments. Cliquez sur le bouton d'enregistrement rouge en haut à gauche pour lancer l'enregistrement et lancer l'application. On vous demandera peut-être votre mot de passe pour autoriser les Instruments à analyser d'autres processus - ne craignez rien, il est sécuritaire de fournir ici! Dans la fenêtre Instruments , vous voyez le temps qui passe et une petite flèche se déplaçant de gauche à droite au-dessus du graphique au centre de l'écran. Cela indique que l'application est en cours d'exécution.

Maintenant, commencez à utiliser l'application. Recherchez des images et explorez un ou plusieurs résultats de recherche. Vous avez probablement remarqué que les résultats de recherche sont fastidieusement lents, et le fait de parcourir une liste de résultats de recherche est également incroyablement ennuyeux - c'est une application terriblement maladroite!

Eh bien, vous avez de la chance, car vous êtes sur le point de le réparer! Cependant, vous allez d'abord avoir un aperçu de ce que vous examinez dans Instruments . Tout d'abord, assurez-vous que le sélecteur de vue sur le côté droit de la barre d'outils a les deux options sélectionnées, comme ceci:

Cela garantira que tous les panneaux sont ouverts. Etudiez maintenant la capture d'écran ci-dessous et l'explication de chaque section en dessous:

1. Ce sont les commandes d'enregistrement . Le bouton rouge "enregistrer" arrête et démarre l'application en cours de profilage lorsque l'utilisateur clique dessus (il bascule entre une icône d'enregistrement et une icône d'arrêt). Le bouton de pause fait exactement ce que vous attendez et interrompt l'exécution en cours de l'application.

2. Ceci est la minuterie d'exécution. La minuterie compte combien de temps l'application est en cours d'exécution et combien de fois elle a été exécutée. Si vous arrêtez puis redémarrez l'application à l'aide des commandes d'enregistrement, cela déclencherait une nouvelle exécution et l'affichage afficherait alors l'exécution 2 de 2.

3. Ceci s'appelle une piste. Dans le cas du modèle Time Profiler que vous avez sélectionné, il n'y a qu'un seul instrument, il n'y a donc qu'une piste. Vous en apprendrez plus sur les spécificités du graphique présenté plus loin dans ce didacticiel.

4. Ceci est le panneau de détail. Il affiche les informations principales sur l'instrument que vous utilisez. Dans ce cas, il montre les méthodes les plus «chaudes», c'est-à-dire celles qui ont utilisé le plus de temps CPU. Si vous cliquez sur la barre en haut qui indique Call Tree (la main gauche) et sélectionnez Sample List, vous obtenez une vue différente des données. Cette vue montre chaque échantillon unique. Cliquez sur quelques exemples et vous verrez la trace de la pile capturée apparaître dans l'inspecteur des détails étendus.

5. Il s’agit du groupe d’inspecteurs. Il existe trois inspecteurs: Paramètres d'enregistrement, Paramètres d'affichage et Détails étendus. Vous en apprendrez plus sur certaines de ces options sous peu.

Forage profond

Effectuez une recherche d'image et explorez les résultats. Personnellement, j'aime bien chercher un «chien», mais choisissez ce que vous voulez - vous pourriez être l'un de ces chats!

Maintenant, faites défiler la liste vers le haut et le bas plusieurs fois pour avoir une bonne quantité de données dans Time Profiler . Vous devriez remarquer que les chiffres au milieu de l'écran changent et que le graphique est rempli. Cela vous indique que les cycles du processeur sont utilisés.

Vous ne vous attendriez vraiment pas à ce qu'une interface utilisateur soit aussi maladroite car cette table view est prête à être expédiée jusqu'à ce qu'elle défile comme du beurre! Pour identifier le problème, vous devez définir certaines options.

Sur le côté droit, sélectionnez l' inspecteur Paramètres d'affichage (or press ⌘+2) . Dans l' inspecteur , sous la section Call Tree , sélectionnez Séparer par thread , Inverser l' Call Tree , Masquer les symboles manquants et Masquer les bibliothèques système. Il ressemblera à ceci:

Voici ce que chaque option fait pour les données affichées dans le tableau à gauche:

Separate by Thread: Chaque thread doit être considéré séparément. Cela vous permet de comprendre quels threads sont responsables de la plus grande utilisation du processeur .

Inverser l'arborescence des appels: avec cette option, la stack trace la stack trace est considérée de haut en bas. C'est généralement ce que vous voulez, car vous voulez voir les méthodes les plus profondes où le processeur passe son temps.

Masquer les symboles manquants: Si le fichier dSYM est introuvable pour votre application ou une system framework , au lieu de voir les noms de méthode (symboles) dans la table, vous ne verrez que les valeurs hexadécimales correspondant aux adresses contenues dans le binaire. Si cette option est sélectionnée, seuls les symboles entièrement résolus sont affichés et les valeurs hexadécimales non résolues sont masquées. Cela permet de désencombrer les données présentées.

Masquer les bibliothèques système: Lorsque cette option est sélectionnée, seuls les symboles de votre propre application sont affichés. Il est souvent utile de sélectionner cette option, car vous ne vous souciez généralement pas de savoir où le processeur passe du temps dans votre propre code - vous ne pouvez pas faire grand chose sur la quantité de CPU system libraries du system libraries !

Aplatir la récursivité: cette option traite les fonctions récursives (celles qui s'appellent elles-mêmes) comme une seule entrée dans chaque stack trace , plutôt que comme une seule entrée.

Fonctions principales: L' activation de cette option fait que les Instruments compte le temps total passé dans une fonction comme la somme du temps directement dans cette fonction, ainsi que le temps passé dans les fonctions appelées par cette fonction.

Donc, si la fonction A appelle B, alors le temps de A est indiqué comme le temps passé dans A PLUS le temps passé en B. Cela peut être très utile, car il vous permet de choisir le plus grand chiffre à chaque descente dans la pile d'appels. sur vos méthodes les plus chronophages.

Si vous exécutez une application Objective-C , Show Obj-C Only est également disponible : Si cette option est sélectionnée, seules les méthodes Objective-C sont affichées, et non les fonctions C ou C++ . Il n'y en a pas dans votre programme, mais si vous regardez une application OpenGL , cela peut avoir du C++ , par exemple.

Bien que certaines valeurs puissent être légèrement différentes, l'ordre des entrées doit être similaire à celui du tableau ci-dessous une fois que vous avez activé les options ci-dessus:

Eh bien, cela n'a certainement pas l'air trop beau. La grande majorité du temps est consacrée à la méthode qui applique le filtre «tonal» aux vignettes. Cela ne devrait pas vous choquer trop, car le chargement et le défilement de la table étaient les éléments les plus clairs de l'interface utilisateur, et c'est à ce moment que les cellules de la table sont constamment mises à jour.

Pour en savoir plus sur ce qui se passe dans cette méthode, double-cliquez sur sa ligne dans la table. Cela fera apparaître la vue suivante:

C'est intéressant, n'est-ce pas? applyTonalFilter() est une méthode ajoutée à UIImage dans une extension et presque 100 % du temps passé dans celle-ci est consacré à la création de la sortie CGImage après l'application du filtre d'image.

Il n'y a pas grand chose à faire pour accélérer les choses: la création de l'image est un processus assez intensif et prend autant de temps que nécessaire. Essayons de reculer et de voir où applyTonalFilter() est appelé. Cliquez sur Call Tree dans le fil d'Ariane en haut de la vue de code pour revenir à l'écran précédent:

Cliquez maintenant sur la petite flèche à gauche de la ligne applyTonalFilter en haut de la table. Cela dépliera l'arbre d'appel pour afficher l'appelant de applyTonalFilter. Vous devrez peut-être déployer la prochaine rangée également; Lors du profilage de Swift, il y aura parfois des lignes en double dans l'arborescence des appels, avec le préfixe @objc. Vous êtes intéressé par la première ligne préfixée par le nom cible de votre application (InstrumentsTutorial):

Dans ce cas, cette ligne fait référence à la vue de la collection de résultats cellForItemAtIndexPath . Double-cliquez sur la ligne pour afficher le code associé au projet.

Maintenant, vous pouvez voir quel est le problème. La méthode d'application du filtre tonal prend beaucoup de temps à exécuter et est appelée directement depuis cellForItemAtIndexPath, qui bloquera le main thread (et donc l'interface utilisateur entière) chaque fois qu'il demandera une image filtrée.

Allocations

Il existe des informations détaillées sur tous les objets en cours de création et la mémoire qui les sauvegarde. il montre également que vous retain counts pour chaque objet. Pour recommencer avec un nouveau instruments profile , quittez l'application Instruments. Cette fois, créez et exécutez l'application et ouvrez le navigateur de débogage dans la zone Navigateurs. Cliquez ensuite sur Mémoire pour afficher des graphiques sur l’utilisation de la mémoire dans la fenêtre principale:

Ces graphiques sont utiles pour avoir une idée rapide de la performance de votre application. Mais vous allez avoir besoin d'un peu plus de puissance. Cliquez sur le bouton Profile in Instruments , puis sur Transférer pour amener cette session dans Instruments . L' instrument d'allocation démarrera automatiquement.

Cette fois, vous remarquerez deux pistes. L'un s'appelle Allocations et l'autre s'appelle Fuites. La piste Allocations sera discutée en détail plus tard; La piste Leaks est généralement plus utile dans Objective-C et ne sera pas abordée dans ce tutoriel. Alors, quel bug allez-vous traquer ensuite? Il y a quelque chose de caché dans le projet que vous ne savez probablement pas. Vous avez probablement entendu parler de fuites de mémoire. Mais ce que vous ne savez peut-être pas, c'est qu'il existe deux types de fuites:

Les vraies fuites de mémoire sont celles où un objet n'est plus référencé par rien, mais toujours alloué - cela signifie que la mémoire ne peut jamais être réutilisée. Même si Swift et ARC aident à gérer la mémoire, le type de fuite de mémoire le plus courant est un retain cycle or strong reference cycle . C'est à ce moment que deux objets contiennent des références fortes les uns aux autres, de sorte que chaque objet empêche l'autre de se désallouer. Cela signifie que leur mémoire n'est jamais libérée!

La croissance de la mémoire sans limite est l'endroit où la mémoire continue à être allouée et n'a jamais la possibilité d'être libérée . Si cela continue pour toujours, alors system's memory sera remplie et vous aurez un gros problème de mémoire. Sous iOS, cela signifie que l'application sera détruite par le système.

Avec l'instrument en cours d' exécution sur les allocations de l'application, faire cinq différentes recherches dans l'application , mais ne pas percer vers le bas dans les résultats encore. Assurez-vous que les recherches ont des résultats! Maintenant, laissez l'application régler un peu en attendant quelques secondes.

Vous devriez avoir remarqué que le graphique dans la piste Allocations a augmenté. Cela vous dit que la mémoire est allouée. C'est cette fonctionnalité qui vous guidera pour trouver unbounded memory growth .

Vous allez effectuer une generation analysis . Pour ce faire, appuyez sur le bouton appelé Mark Generation. Vous trouverez le bouton en haut de l'inspecteur Paramètres d'affichage:

Appuyez dessus et vous verrez un drapeau rouge apparaître sur la piste, comme ceci:

Le but de l' generation analysis de generation analysis est d'effectuer une action plusieurs fois et de voir si la mémoire croît de unbounded fashion . Effectuez une recherche, attendez quelques secondes que les images soient chargées, puis revenez à la page principale. Puis marquez à nouveau la génération. Répétez cette opération pour différentes recherches. Après un forage dans quelques recherches, instruments ressemblera à ceci:

À ce stade, vous devriez être suspect. Remarquez comment le graphique bleu monte à chaque recherche dans laquelle vous explorez . Eh bien, ce n'est certainement pas bon. Mais attendez, qu'en est-il memory warnings? Vous en savez à propos de ça, non? Memory warnings sont la manière dont iOS indique à une application que les choses se resserrent dans le service de mémoire et que vous devez effacer de la mémoire.

Il est possible que cette croissance ne soit pas uniquement due à votre application. cela pourrait être quelque chose dans les profondeurs d' UIKit qui retient la mémoire. Donnez aux frameworks système et à votre application la possibilité d’éclaircir la mémoire avant de pointer un doigt vers l’une ou l’autre.

Simulez un memory warning en sélectionnant Instrument\Simulate Memory Warning dans la barre de menu de l’instrument ou Hardware\Simulate Memory Warning de Hardware\Simulate Memory Warning dans la barre de menus simulator's . Vous remarquerez que l'utilisation de la mémoire diminue légèrement, voire pas du tout. Certainement pas revenir là où ça devrait être. Donc, il y a encore une croissance de la mémoire illimitée qui se passe quelque part.

Le fait de marquer une génération après chaque itération de l'exploration d'une recherche permet de voir quelle mémoire a été allouée entre chaque génération. Jetez un œil dans le panneau de détails et vous verrez un tas de générations.