Optimisation du temps de construction - Partie 1

Presque tous les développeurs ont rencontré au moins une fois un temps de construction assez long pour leur projet. Cela conduit à une productivité réduite et ralentit le processus de développement de toute l'équipe. Comme vous pouvez le voir, l'augmentation du temps de construction d'un projet est cruciale car elle a un impact direct sur le moment où l'application est publiée sur l'AppStore et pour une publication plus rapide des nouvelles fonctionnalités de votre application.

Dans cet article, nous allons apprendre à profiler un assembly dans Xcode et à obtenir des métriques. Dans le prochain article, je parlerai des méthodes pour éliminer les goulots d'étranglement et accélérer l'assemblage du projet. Il convient également de mentionner que nous utiliserons le projet iOS Kickstarter, qui se trouve sur Github . Alors, commençons!

Que mesurons-nous?


La première chose que nous devons faire est de déterminer ce que nous essayons de mesurer et d'optimiser. Deux options peuvent être envisagées:

  • Clean build - nettoyez et construisez le projet. Souvent, des builds propres sont effectuĂ©s dans CI pour rechercher une nouvelle demande d'extraction et exĂ©cuter des tests unitaires.
  • GĂ©nĂ©ration incrĂ©mentielle - gĂ©nĂ©rez le projet après des modifications importantes du code source. Cet assemblage est crĂ©Ă© par le dĂ©veloppeur tout en travaillant sur de nouvelles fonctionnalitĂ©s.

Dans la plupart des cas, la réduction du temps lors de la génération propre devrait également accélérer la génération incrémentielle . La meilleure option serait de créer des métriques pour les deux types d'assemblages et de les suivre. Nous mesurerons le temps de génération à l'aide de la configuration de débogage uniquement parce qu'elle est utilisée la plupart du temps et a un impact plus important sur le développement.

Nous calculons le temps de montage


Le moyen le plus efficace d'améliorer le temps de génération devrait être une approche basée sur l'implémentation et la vérification des changements en fonction de métriques spécifiques. Considérez-les, ainsi que les outils que nous pouvons utiliser pour obtenir des informations sur le temps de construction du projet.

Rapport de temps de construction Xcode


Nous pouvons facilement obtenir des données de temps de construction en utilisant Xcode. Il suit toutes les générations par défaut et vous permet de visualiser le temps de génération du projet dans le navigateur de rapports.

image

Vous avez également la possibilité d'afficher des informations similaires dans Xcode dans le panneau du visualiseur d'activité . Il peut être activé pour l'affichage à l'aide de la ligne de commande en exécutant la commande: Le temps de construction du projet est affiché après l'assemblage avec le message «Réussi». Ce ne sont que deux options de base qui devraient vous donner une idée approximative du temps de construction propre et incrémentiel .

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES



image



Résumé du temps de construction du projet dans Xcode


Résumé du temps de construction de Xcode - Votre premier ami à obtenir des statistiques de temps de construction et des goulots d'étranglement. Vous pouvez l'exécuter via Product-> Perform Action-> Build With Timing Summary . Vous verrez maintenant une grande répartition du temps passé sur diverses tâches:

image

Cette méthode devrait être un bon point de départ pour trouver les tâches les plus longues dans le processus d'assemblage. La capture d'écran ci-dessus montre que CompileStoryboard , CompileXIB , CompileSwiftSources et les phases PhaseScriptExecution ont pris la plupart du temps de construction. Xcode a pu effectuer une partie des tâches en parallèle, donc l'assemblage est terminé beaucoup plus rapidement que le temps nécessaire pour terminer la tâche de chacune des commandes.

Nous pouvons obtenir un résumé du temps de construction pour la génération propre en utilisant xcodebuild avec l'option - buildWithTimingSummary : Maintenant, obtenons des mesures similaires pour la construction incrémentielle. Il convient de noter que le temps de génération incrémentiel dépend entièrement des fichiers en cours de modification dans le projet. Pour obtenir des résultats cohérents, vous pouvez modifier un fichier et compiler le projet. Contrairement aux systèmes Buck ou Bazel, Xcode utilise des horodatages pour déterminer ce qui a changé et ce qui doit être reconstruit. Nous pouvons mettre à jour l'horodatage en utilisant le toucher:

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
clean build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
CompileStoryboard (29 tasks) | 87.128 seconds
CompileSwiftSources (4 tasks) | 54.144 seconds
PhaseScriptExecution (14 tasks) | 18.167 seconds
CompileAssetCatalog (2 tasks) | 6.532 seconds
CompileXIB (21 tasks) | 6.293 seconds
CodeSign (7 tasks) | 3.069 seconds
Ld (4 tasks) | 2.342 seconds
LinkStoryboards (2 tasks) | 0.172 seconds
CompileC (3 tasks) | 0.122 seconds
Ditto (20 tasks) | 0.076 seconds
Touch (4 tasks) | 0.007 seconds
** BUILD SUCCEEDED ** [92.620 sec]



touch KsApi/mutations/CancelBackingMutation.swift && \
xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
PhaseScriptExecution (14 tasks) | 18.089 seconds
CodeSign (7 tasks) | 2.990 seconds
CompileSwiftSources (1 task) | 1.245 seconds
Ld (1 task) | 0.361 seconds
** BUILD SUCCEEDED ** [23.927 sec]

Avertissements de vérification de type


Lorsque le temps de compilation est un goulot d'étranglement, nous pouvons obtenir plus d'informations en définissant Other Swift Flags sur les options de construction du projet dans Xcode. Lorsque l'indicateur est activé, Xcode génère un avertissement pour toute fonction ou expression qui prend plus de 100 ms pour déterminer le type de variables:

  • -Xfrontend -warn-long-function-corps = 100
  • -Xfrontend -warn-long-expression-type-verification = 100

image

Vous connaissez maintenant le code avec lequel le compilateur Swift a des problèmes et vous pouvez maintenant essayer de l'améliorer.

Options de diagnostic du compilateur


Le compilateur Swift possède de nombreuses options de diagnostic intégrées que vous pouvez utiliser pour profiler l'assemblage.

  • -driver-time-compilation - un haut niveau de synchronisation des tâches effectuĂ©es par le pilote.
  • -Xfrontend -debug-time-compilation — .
  • -Xfrontend -debug-time-function-bodies – .
  • -Xfrontend -debug-time-expression-type-checking – .

Utilisons l' indicateur -debug-time-compilation pour obtenir des informations sur les fichiers les plus lents lors de la compilation: Comme vous pouvez le voir, il a fallu 25 secondes pour compiler SettingsNewslettersCellViewModel.swift . À partir du journal d'assemblage, vous pouvez obtenir des informations supplémentaires sur le temps de compilation du fichier: il est désormais évident que la vérification de type et l' analyse sémantique sont les travaux les plus longs. Allons de l'avant et listons les fonctions et expressions les plus lentes dans l'étape de vérification de type :

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-compilation" |
awk '/CompileSwift normal/,/Swift compilation/{print; getline; print; getline; print}' |
grep -Eo "^CompileSwift.+\.swift|\d+\.\d+ seconds" |
sed -e 'N;s/\(.*\)\n\(.*\)/\2 \1/' |
sed -e "s|CompileSwift normal x86_64 $(pwd)/||" |
sort -rn |
head -3

25.6026 seconds Library/ViewModels/SettingsNewslettersCellViewModel.swift
24.4429 seconds Library/ViewModels/PledgeSummaryViewModel.swift
24.4312 seconds Library/ViewModels/PaymentMethodsViewModel.swift



===-------------------------------------------------------------------------===
Swift compilation
===-------------------------------------------------------------------------===
Total Execution Time: 25.6026 seconds (26.6593 wall clock)

---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
24.4632 ( 98.3%) 0.5406 ( 76.5%) 25.0037 ( 97.7%) 26.0001 ( 97.5%) Type checking and Semantic analysis
0.0981 ( 0.4%) 0.1383 ( 19.6%) 0.2364 ( 0.9%) 0.2872 ( 1.1%) Name binding
0.1788 ( 0.7%) 0.0043 ( 0.6%) 0.1831 ( 0.7%) 0.1839 ( 0.7%) IRGen
0.0508 ( 0.2%) 0.0049 ( 0.7%) 0.0557 ( 0.2%) 0.0641 ( 0.2%) Parsing
0.0599 ( 0.2%) 0.0020 ( 0.3%) 0.0619 ( 0.2%) 0.0620 ( 0.2%) SILGen
0.0285 ( 0.1%) 0.0148 ( 2.1%) 0.0433 ( 0.2%) 0.0435 ( 0.2%) SIL optimization
0.0146 ( 0.1%) 0.0015 ( 0.2%) 0.0161 ( 0.1%) 0.0162 ( 0.1%) Serialization, swiftmodule
0.0016 ( 0.0%) 0.0006 ( 0.1%) 0.0022 ( 0.0%) 0.0022 ( 0.0%) Serialization, swiftdoc
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0001 ( 0.0%) SIL verification, pre-optimization
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) AST verification
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) SIL verification, post-optimization
24.8956 (100.0%) 0.7069 (100.0%) 25.6026 (100.0%) 26.6593 (100.0%) Total



xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-expression-type-checking \
-Xfrontend -debug-time-function-bodies" |
grep -o "^\d*.\d*ms\t[^$]*$" |
awk '!visited[$0]++' |
sed -e "s|$(pwd)/||" |
sort -rn |
head -5

16226.04ms Library/Styles/UpdateDraftStyles.swift:31:3
10551.24ms Kickstarter-iOS/Views/RewardCardContainerView.swift:171:16 instance method configureBaseGradientView()
10547.41ms Kickstarter-iOS/Views/RewardCardContainerView.swift:172:7
8639.30ms Kickstarter-iOS/Views/Controllers/AddNewCardViewController.swift:396:67
8233.27ms KsApi/models/templates/ProjectTemplates.swift:94:5

De la même manière, nous avons profilé notre assemblage et découvert qu'au stade de la vérification de type, il y a plutôt des goulots d'étranglement. À l'étape suivante, vous pouvez jeter un œil aux fonctions et expressions répertoriées ci-dessus et essayer d'optimiser l' inférence de type .

Temps de construction cible


Il est conseillé de mesurer séparément le temps d'assemblage de la cible et de les afficher sur le graphique. Vous pouvez aider à comprendre quelles cibles sont collectées ou peuvent être collectées en parallèle. Pour ce faire, vous pouvez utiliser l'outil de rendu xcode-build-time. Définissons-le comme RubyGem: Une fois l'installation terminée, exécutez la commande suivante pour entrer le journal d'horodatage dans la phase d' exécution du script de génération de vos cibles: compilez ensuite le projet et le rapport en utilisant: Par conséquent, vous devriez obtenir un joli diagramme de Gantt par temps de génération qui indique l'heure assemblages de toutes vos cibles:

gem install xcode-build-times



xcode-build-times install



xcode-build-times generate



image

Mesures agrégées


Il serait intéressant d'agréger les différents indicateurs mentionnés ci-dessus. XCLogParser est un excellent outil qui peut vous aider avec cela. Il s'agit d'un analyseur de journal pour xcactivitylog généré par Xcode, et donne beaucoup d'informations sur le temps de construction de chaque module et fichier du projet, les avertissements, les erreurs et les résultats des tests unitaires. Vous pouvez l'installer en clonant le référentiel et en le lançant via la ligne de commande: Il s'agit d'un rapport créé pour le projet Kickstarter iOS:

git clone https://github.com/spotify/XCLogParser
rake build
xclogparser parse --project Kickstarter --reporter html



image

Automatisation


Il convient de noter que les métriques de temps d'assemblage dépendent du matériel et de leur utilisation. Vous pouvez utiliser votre équipement pour des expériences. La meilleure option serait d'automatiser le processus autant que possible et d'utiliser un équipement CI dédié pour les mesures quotidiennes. En fin de compte, ils peuvent être surveillés sur le tableau de bord et informés de l'aggravation des temps de construction à l'aide de Slack.

Conclusion


Réduire le temps de construction d'un projet est essentiel pour améliorer la productivité des développeurs. Aujourd'hui, nous avons appris à mesurer le temps de construction d'un projet et à obtenir des mesures pour l'analyse ...

Dans la prochaine publication, nous examinerons les méthodes qui peuvent être utilisées pour réduire le temps de construction.

Merci d'avoir lu!

All Articles