Build Time Optimization - Teil 1

Fast jeder Entwickler hatte mindestens einmal eine ziemlich lange Bauzeit für sein Projekt. Dies führt zu einer verringerten Produktivität und verlangsamt den Entwicklungsprozess des gesamten Teams. Wie Sie sehen, ist die Verlängerung der Erstellungszeit eines Projekts von entscheidender Bedeutung, da dies einen direkten Einfluss auf die Zeit hat, in der die Anwendung im AppStore veröffentlicht wird, und auf die schnellere Veröffentlichung neuer Funktionen in Ihrer Anwendung.

In diesem Artikel erfahren Sie, wie Sie eine Assembly in Xcode profilieren und Metriken abrufen. Im nächsten Artikel werde ich über Methoden sprechen, um Engpässe zu beseitigen und die Montage des Projekts zu beschleunigen. Es sollte auch erwähnt werden, dass wir das Kickstarter iOS-Projekt verwenden werden, das auf Github zu finden ist . Also lasst uns anfangen!

Was messen wir?


Als erstes müssen wir feststellen, was wir messen und optimieren möchten. Zwei Optionen können in Betracht gezogen werden:

  • Clean Build - Reinigen und erstellen Sie das Projekt. In CI werden häufig saubere Builds durchgeführt, um nach einer neuen Pull-Anforderung zu suchen und Komponententests auszuführen.
  • Inkrementelle Erstellung - Erstellen Sie das Projekt nach wesentlichen Änderungen am Quellcode. Diese Assembly wird vom Entwickler erstellt, während an neuen Funktionen gearbeitet wird.

In den meisten Fällen sollte die Verkürzung der Zeit während des sauberen Builds auch den inkrementellen Build beschleunigen . Die beste Option wäre, Metriken für beide Baugruppentypen zu erstellen und zu verfolgen. Wir werden die Build-Zeit nur mit der Debug- Konfiguration messen, da sie die meiste Zeit verwendet wird und einen größeren Einfluss auf die Entwicklung hat.

Wir berechnen die Montagezeit


Der effektivste Weg zur Verbesserung der Erstellungszeit sollte ein Ansatz sein, der auf der Implementierung und Überprüfung von Änderungen basiert, die auf bestimmten Metriken basieren. Berücksichtigen Sie sie sowie Tools, mit denen wir Informationen über die Erstellungszeit des Projekts erhalten können.

Xcode-Erstellungszeitbericht


Mit Xcode können wir problemlos Build-Zeitdaten abrufen. Standardmäßig werden alle Builds verfolgt, und Sie können die Build-Zeit des Projekts im Berichtsnavigator anzeigen.

Bild

Sie haben auch die Möglichkeit, ähnliche Informationen in Xcode im Aktivitäts-Viewer-Bereich anzuzeigen . Es kann für die Anzeige über die Befehlszeile aktiviert werden, indem der Befehl ausgeführt wird: Die Projekterstellungszeit wird nach der Baugruppe zusammen mit der Meldung „Erfolgreich“ angezeigt. Dies sind nur zwei grundlegende Optionen, die Ihnen eine ungefähre Vorstellung von der sauberen und inkrementellen Erstellungszeit geben sollen.

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES



Bild



Zusammenfassung der Projekterstellungszeit in Xcode


Xcode Build Time Summary - Ihr erster Freund, der Build Time-Statistiken und Engpässe erhält. Sie können es über Produkt-> Aktion ausführen-> Mit Timing-Zusammenfassung erstellen ausführen . Jetzt sehen Sie eine große Aufschlüsselung der für verschiedene Aufgaben aufgewendeten Zeit:

Bild

Diese Methode sollte ein guter Ausgangspunkt sein, um die zeitaufwändigsten Aufgaben im Montageprozess zu finden. Der obige Screenshot zeigt, dass CompileStoryboard , CompileXIB , CompileSwiftSources und die PhaseScriptExecution- Phasen den größten Teil der Erstellungszeit in Anspruch nahmen. Xcode konnte einen Teil der Aufgaben parallel ausführen, sodass die Assembly viel schneller als die für die Ausführung der einzelnen Befehle erforderliche Zeit abgeschlossen ist.

Mit xcodebuild können wir eine Zusammenfassung der Build-Zeit für Clean Build mit der Option - buildWithTimingSummary : Jetzt erhalten wir ähnliche Metriken für Incremental Build. Es ist zu beachten, dass die inkrementelle Erstellungszeit vollständig von den im Projekt geänderten Dateien abhängt. Um konsistente Ergebnisse zu erhalten, können Sie eine Datei ändern und das Projekt kompilieren. Im Gegensatz zu Buck- oder Bazel-Systemen verwendet Xcode Zeitstempel, um festzustellen, was sich geändert hat und was neu erstellt werden muss. Wir können den Zeitstempel mit touch aktualisieren:

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]

Warnungen zur Typüberprüfung


Wenn die Kompilierungszeit ein Engpass ist, können wir weitere Informationen erhalten, indem wir andere Swift Flags auf die Projekterstellungsoptionen in Xcode setzen. Wenn das Flag aktiviert ist, generiert Xcode eine Warnung für jede Funktion oder jeden Ausdruck, die mehr als 100 ms benötigt, um den Variablentyp zu bestimmen:

  • -Xfrontend -warn-long-function-body = 100
  • -Xfrontend -warn-long-expression-type-testing = 100

Bild

Jetzt kennen Sie den Code, mit dem der Swift-Compiler Probleme hat, und können jetzt versuchen, ihn zu verbessern.

Compiler-Diagnoseoptionen


Der Swift-Compiler verfügt über viele integrierte Diagnoseoptionen, mit denen Sie die Assembly profilieren können.

  • -driver-time-compilation - ein hohes Maß an Synchronisation der vom Fahrer ausgeführten Aufgaben.
  • -Xfrontend -debug-time-compilation — .
  • -Xfrontend -debug-time-function-bodies – .
  • -Xfrontend -debug-time-expression-type-checking – .

Verwenden Sie das Flag -debug-time-compilation , um Informationen zu den langsamsten Dateien beim Kompilieren abzurufen : Wie Sie sehen, dauerte das Kompilieren von SettingsNewslettersCellViewModel.swift 25 Sekunden. Aus dem Assemblyprotokoll können Sie zusätzliche Informationen zur Dateikompilierungszeit abrufen: Jetzt ist es offensichtlich, dass die Typprüfung und die semantische Analyse die zeitaufwändigste Arbeit sind. Lassen Sie uns fortfahren und die langsamsten Funktionen und Ausdrücke im Schritt Typprüfung auflisten :

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

Auf die gleiche Weise haben wir unsere Baugruppe profiliert und festgestellt, dass es in der Phase der Typprüfung eher zu Engpässen kommt. Als nächsten Schritt können Sie sich die oben aufgeführten Funktionen und Ausdrücke ansehen und versuchen, die Typinferenz zu optimieren .

Zielerstellungszeit


Es ist ratsam, die Montagezeit des Ziels separat zu messen und im Diagramm anzuzeigen. Sie können besser verstehen, welche Ziele erfasst werden oder parallel erfasst werden können. Dazu können Sie das Xcode-Build-Time-Rendering-Tool verwenden. Legen wir es als RubyGem fest: Führen Sie nach Abschluss der Installation den folgenden Befehl aus, um das Zeitstempelprotokoll in der Erstellungsphase des Skript-Skripts Ihrer Ziele einzugeben: Kompilieren Sie dann das Projekt und berichten Sie mit: Als Ergebnis sollten Sie ein schönes Gantt-Diagramm nach Erstellungszeit erhalten, das die Zeit anzeigt Versammlungen aller Ihrer Ziele:

gem install xcode-build-times



xcode-build-times install



xcode-build-times generate



Bild

Aggregierte Metriken


Es wäre großartig, die verschiedenen oben genannten Indikatoren zusammenzufassen. XCLogParser ist ein großartiges Tool, das Ihnen dabei helfen kann. Es ist ein von Xcode generierter Protokollanalysator für xcactivitylog und enthält viele Informationen zur Erstellungszeit für jedes Modul und jede Datei im Projekt, Warnungen, Fehler und Unit-Testergebnisse. Sie können es installieren, indem Sie das Repository klonen und über die Befehlszeile starten: Dies ist ein Bericht, der für das Kickstarter iOS-Projekt erstellt wurde:

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



Bild

Automatisierung


Es ist zu beachten, dass die Metriken für die Montagezeit von der Hardware und ihrer Verwendung abhängen. Sie können Ihre Ausrüstung für Experimente verwenden. Die beste Option wäre, den Prozess so weit wie möglich zu automatisieren und dedizierte CI-Geräte für die täglichen Messdaten zu verwenden. Letztendlich können sie mit Slack über das Dashboard überwacht und über sich verschlechternde Bauzeiten informiert werden.

Fazit


Die Verkürzung der Erstellungszeit eines Projekts ist entscheidend für die Verbesserung der Entwicklerproduktivität. Heute haben wir gelernt, wie man die Erstellungszeit eines Projekts misst und einige Metriken für die Analyse erhält ...

In der nächsten Veröffentlichung werden wir Methoden betrachten, mit denen die Erstellungszeit verkürzt werden kann.

Danke fürs Lesen!

All Articles