Xamarin.Mac vorab kompilieren

Übersicht

Die AOT-Kompilierung (Ahead of Time) ist eine leistungsfähige Optimierungsmethode zur Verbesserung der Startleistung. Es wirkt sich jedoch auch auf ihre Buildzeit, die Anwendungsgröße und die Programmausführung in tiefgreifender Weise aus. Um die Kompromisse zu verstehen, die sie auferlegt, werden wir uns ein wenig mit der Kompilierung und Ausführung einer Anwendung befassen.

Code, der in verwalteten Sprachen wie C# und F# geschrieben wurde, wird zu einer Zwischendarstellung namens IL kompiliert. Diese IL, die in Ihrer Bibliothek und Programmassemblys gespeichert ist, ist relativ kompakt und zwischen Prozessorarchitekturen portierbar. IL ist jedoch nur ein Zwischensatz von Anweisungen und muss irgendwann in den prozessorspezifischen Computercode übersetzt werden.

Es gibt zwei Punkte, in denen diese Verarbeitung erfolgen kann:

  • Just-in-Time (JIT): Beim Starten und Ausführen Ihrer Anwendung wird die IL im Arbeitsspeicher in Computercode kompiliert.
  • Voraus der Zeit (AOT): Während des Buildvorgangs wird die IL kompiliert und in native Bibliotheken geschrieben und in Ihrem Anwendungspaket gespeichert.

Jede Option bietet eine Reihe von Vorteilen und Kompromissen:

  • JIT
    • Startzeit : Die JIT-Kompilierung muss beim Start erfolgen. Für die meisten Anwendungen ist dies in der Größenordnung von 100 ms, aber für große Anwendungen kann dieses Mal deutlich mehr sein.
    • Ausführung : Da der JIT-Code für den verwendeten Prozessor optimiert werden kann, kann etwas besserer Code generiert werden. In den meisten Anwendungen ist dies höchstens ein paar Prozentpunkte schneller.
  • AOT
    • Startzeit : Das Laden vorkompilierter Dylibs ist deutlich schneller als JIT-Assemblys.
    • Speicherplatz auf dem Datenträger : Diese Dylibs können jedoch einen erheblichen Speicherplatz belegen. Je nachdem, welche Assemblys AOTed sind, kann sie die Größe des Codeteils Ihrer Anwendung verdoppeln oder mehr.
    • Buildzeit : Die AOT-Kompilierung ist wesentlich langsamer als JIT und verlangsamt die Verwendung von Builds. Diese Verlangsamung kann von Sekunden bis zu einer Minute oder mehr liegen, abhängig von der Größe und Anzahl der kompilierten Assemblys.
    • Verschleierung : Da die IL, die deutlich einfacher zu entwickeln ist als Maschinencode, nicht unbedingt erforderlich ist, kann sie entfernt werden, um sensiblen Code zu verschleiern. Dies erfordert die unten beschriebene Option "Hybrid".

Aktivieren von AOT

AOT-Optionen werden dem Mac-Buildbereich in einem zukünftigen Update hinzugefügt. Bis dahin erfordert die Aktivierung von AOT die Übergabe eines Befehlszeilenarguments über das Feld "Zusätzliche mmp-Argumente" in Mac Build. Die folgenden Optionen sind verfügbar:

--aot[=VALUE]          Specify assemblies that should be AOT compiled
                          - none - No AOT (default)
                          - all - Every assembly in MonoBundle
                          - core - Xamarin.Mac, System, mscorlib
                          - sdk - Xamarin.Mac.dll and BCL assemblies
                          - |hybrid after option enables hybrid AOT which
                          allows IL stripping but is slower (only valid
                          for 'all')
                          - Individual files can be included for AOT via +
                          FileName.dll and excluded via -FileName.dll

                          Examples:
                            --aot:all,-MyAssembly.dll
                            --aot:core,+MyOtherAssembly.dll,-mscorlib.dll

Hybrid-AOT

Während der Ausführung einer macOS-Anwendung verwendet die Runtime standardmäßig Computercode, der aus den nativen Bibliotheken geladen wird, die von der AOT-Kompilierung erstellt werden. Es gibt jedoch einige Codebereiche wie Trampoline, in denen die JIT-Kompilierung zu deutlich optimierten Ergebnissen führen kann. Dies erfordert, dass die IL für verwaltete Assemblys verfügbar ist. Unter iOS sind Anwendungen auf die Verwendung der JIT-Kompilierung beschränkt. Diese Codeabschnitte werden ebenfalls AOT kompiliert.

Die Hybridoption weist den Compiler an, diese Abschnitte (wie iOS) zu kompilieren, aber auch davon auszugehen, dass die IL zur Laufzeit nicht verfügbar ist. Diese IL kann dann nach dem Build entfernt werden. Wie oben erwähnt, wird die Runtime an einigen Stellen gezwungen, weniger optimierte Routinen zu verwenden.

Weitere Überlegungen

Die negativen Folgen der AOT-Skalierung mit den Größen und der Anzahl der verarbeiteten Assemblys. Das vollständige Zielframework enthält beispielsweise eine wesentlich größere Basisklassenbibliothek (Base Class Library, BCL) als Modern, sodass AOT deutlich länger dauert und größere Bündel erzeugt. Dies wird durch die Inkompatibilität des vollständigen Zielframeworks mit dem Verknüpfen verstärkt, wodurch nicht verwendeter Code entfernt wird. Erwägen Sie, Ihre Anwendung auf Modern zu verschieben und die Verknüpfung zu aktivieren, um die besten Ergebnisse zu erzielen.

Ein weiterer Vorteil von AOT ist die verbesserte Interaktion mit nativen Debugging- und Profilerstellungstools. Da ein Großteil der Codebasis im Voraus kompiliert wird, verfügt sie über Funktionsnamen und Symbole, die in nativen Absturzberichten, der Profilerstellung und dem Debuggen leichter zu lesen sind. JIT-generierte Funktionen verfügen nicht über diese Namen und werden häufig als unbenannte Hexoffsets angezeigt, die nur sehr schwer aufzulösen sind.