Compilation anticipée de Xamarin.Mac

Vue d’ensemble

La compilation par avance (AOT) est une technique d’optimisation puissante pour améliorer les performances de démarrage. Toutefois, cela affecte également le temps de génération, la taille de l’application et l’exécution de votre programme de manière profonde. Pour comprendre les compromis qu’elle impose, nous allons nous plonger un peu dans la compilation et l’exécution d’une application.

Le code écrit dans des langages managés, tels que C# et F#, est compilé dans une représentation intermédiaire appelée IL. Cet il, stocké dans vos assemblys de bibliothèque et de programme, est relativement compact et portable entre les architectures de processeur. Toutefois, IL n’est qu’un ensemble intermédiaire d’instructions et, à un moment donné, il devra être traduit en code machine spécifique au processeur.

Il existe deux points dans lesquels ce traitement peut être effectué :

  • Juste-à-temps (JIT) : pendant le démarrage et l’exécution de votre application, l’il est compilé en mémoire sur du code machine.
  • Avant-temps (AOT) : pendant la génération, l’il est compilé et écrit dans des bibliothèques natives et stocké dans votre bundle d’applications.

Chaque option présente un certain nombre d’avantages et de compromis :

  • JIT
    • Heure de démarrage : la compilation JIT doit être effectuée au démarrage. Pour la plupart des applications, cela est de l’ordre de 100 ms, mais pour les grandes applications cette fois peut être beaucoup plus.
    • Exécution : comme le code JIT peut être optimisé pour le processeur spécifique utilisé, un code légèrement meilleur peut être généré. Dans la plupart des applications, c’est au maximum quelques points de pourcentage plus rapide.
  • AOT
    • Temps de démarrage : le chargement des dylibs précompilés est beaucoup plus rapide que les assemblys JIT.
    • Espace disque : ces dylibs peuvent toutefois prendre une quantité importante d’espace disque. Selon les assemblys qui sont AOTed, il peut doubler ou plus la taille de la partie code de votre application.
    • Temps de build : la compilation AOT est beaucoup plus lente que JIT et ralentit les builds qui l’utilisent. Ce ralentissement peut aller de secondes à une minute ou plus, en fonction de la taille et du nombre d’assemblys compilés.
    • Obfuscation : l’il, qui est beaucoup plus facile à rétroconcevoir que le code machine, n’est pas nécessairement nécessaire, il peut être supprimé pour aider à obfusquer le code sensible. Cela nécessite l’option « Hybride » décrite ci-dessous.

Activation d’AOT

Les options AOT seront ajoutées au volet Build Mac dans une prochaine mise à jour. En attendant, l’activation d’AOT nécessite le passage d’un argument de ligne de commande via le champ « Arguments mmp supplémentaires » dans Mac Build. Les options disponibles sont les suivantes :

--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

AOT hybride

Pendant l’exécution d’une application macOS, le runtime utilise par défaut du code machine chargé à partir des bibliothèques natives produites par la compilation AOT. Toutefois, il existe des domaines de code tels que les trampolines, où la compilation JIT peut produire des résultats beaucoup plus optimisés. Pour cela, les assemblys managés IL doivent être disponibles. Sur iOS, les applications sont limitées à toute utilisation de la compilation JIT ; ces sections de code sont également compilées par AOT.

L’option hybride indique au compilateur de compiler ces sections (comme iOS), mais aussi de supposer que l’il ne sera pas disponible au moment de l’exécution. Cet il peut ensuite être supprimé après la génération. Comme indiqué ci-dessus, le runtime sera obligé d’utiliser des routines moins optimisées à certains endroits.

Autres considérations

Les conséquences négatives de l’échelle AOT avec les tailles et le nombre d’assemblys traités. L’infrastructure cible complète, par exemple, contient une bibliothèque de classes de base (BCL) beaucoup plus grande que la bibliothèque moderne. Par conséquent, AOT prendra beaucoup plus de temps et produira des bundles plus volumineux. Cela est aggravé par l’incompatibilité de l’infrastructure cible complète avec la liaison, qui supprime le code inutilisé. Envisagez de déplacer votre application vers Moderne et d’activer la liaison pour obtenir de meilleurs résultats.

Un avantage supplémentaire d’AOT est fourni avec des interactions améliorées avec les chaînes d’outils de débogage et de profilage natives. Étant donné qu’une grande majorité du codebase sera compilé à l’avance, il aura des noms de fonctions et des symboles plus faciles à lire dans les rapports d’incident, le profilage et le débogage natifs. Les fonctions générées par JIT n’ont pas ces noms et s’affichent souvent sous la forme de décalages hexadécimaux sans nom qui sont très difficiles à résoudre.