Implémenter le compilateur ART juste-à-temps

Android Runtime (ART) inclut un compilateur just-in-time (JIT) avec profilage du code qui améliore en continu les performances des applications Android lors de leur exécution. Le compilateur JIT complète le compilateur AOT (Ahead-of-Time) actuel d'ART. Il améliore les performances d'exécution, économise de l'espace de stockage et accélère les mises à jour des applications et du système. Il améliore également le compilateur AOT en évitant le ralentissement du système lors des mises à jour automatiques des applications ou de la recompilation des applications lors des mises à jour OTA (Over-the-Air).

Bien que JIT et AOT utilisent le même compilateur avec un ensemble d'optimisations similaires, le code généré peut ne pas être identique. JIT utilise des informations sur le type d'exécution, peut effectuer un meilleur inlining et permet la compilation OSR (On Stack Replacement), ce qui génère un code légèrement différent.

Architecture JIT

Architecture JIT
Figure 1 : Architecture JIT.

Compilation JIT

La compilation JIT implique les activités suivantes :

Composition guidée par le profil
Figure 2. Compilation guidée par le profil.
  1. L'utilisateur exécute l'application, ce qui déclenche le chargement du fichier .dex par ART.
    • Si le fichier .oat (binaire AOT pour le fichier .dex) est disponible, ART l'utilise directement. Bien que les fichiers .oat soient générés régulièrement, ils ne contiennent pas toujours de code compilé (binaire AOT).
    • Si le fichier .oat ne contient pas de code compilé, ART exécute le fichier .dex via JIT et l'interpréteur.
  2. La compilation JIT est activée pour toute application qui n'est pas compilée selon le filtre de compilation speed (qui indique "compiler autant que possible à partir de l'application").
  3. Les données du profil JIT sont transférées dans un fichier d'un répertoire système auquel seule l'application peut accéder.
  4. Le daemon de compilation AOT (dex2oat) analyse ce fichier pour piloter sa compilation.

    Daemon JIT
    Figure 3 : Activités du daemon JIT.

Le service Google Play est un exemple utilisé par d'autres applications qui se comportent de manière similaire aux bibliothèques partagées.

Workflow JIT

Architecture JIT
Figure 4. Flux de données JIT.
  • Les informations de profilage sont stockées dans le cache de code et soumises à la récupération de mémoire inutilisée en cas de pression sur la mémoire.
    • Il n'est pas garanti qu'un instantané pris lorsque l'application était en arrière-plan contienne des données complètes (c'est-à-dire tout ce qui a été compilé JIT).
    • Aucune tentative n'est faite pour s'assurer que tout est enregistré (car cela peut avoir un impact sur les performances d'exécution).
  • Les méthodes peuvent avoir trois états différents :
    • interprété (code DEX)
    • Compilé JIT
    • Compilé AOT
    Si du code JIT et AOT existe (par exemple, en raison de désoptimisations répétées), le code JIT est préféré.
  • La quantité de mémoire requise pour exécuter JIT sans affecter les performances de l'application au premier plan dépend de l'application en question. Les applications volumineuses nécessitent plus de mémoire que les applications de petite taille. En général, les grandes applications se stabilisent autour de 4 Mo.

Activer la journalisation JIT

Pour activer la journalisation JIT, exécutez les commandes suivantes :

adb root
adb shell stop
adb shell setprop dalvik.vm.extra-opts -verbose:jit
adb shell start

Désactiver JIT

Pour désactiver la compilation JIT, exécutez les commandes suivantes :

adb root
adb shell stop
adb shell setprop dalvik.vm.usejit false
adb shell start

Forcer la compilation

Pour forcer la compilation, exécutez la commande suivante :

adb shell cmd package compile

Voici quelques cas d'utilisation courants de la compilation forcée d'un package spécifique :

  • Basé sur le profil :
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Totale :
    adb shell cmd package compile -m speed -f my-package
    

Voici quelques cas d'utilisation courants de la compilation forcée de tous les packages :

  • Basé sur le profil :
    adb shell cmd package compile -m speed-profile -f -a
    
  • Totale :
    adb shell cmd package compile -m speed -f -a
    

Effacer les données de profil

Sur Android 13 ou version antérieure

Pour effacer les données de profil local et supprimer le code compilé, exécutez la commande suivante :

adb shell pm compile --reset 

Sur Android 14 ou version ultérieure

Pour effacer uniquement les données de profil locales :

adb shell pm art clear-app-profiles 

Remarque : Contrairement à la commande pour Android 13 ou version antérieure, cette commande n'efface pas les données de profil externe (.dm) installées avec l'application.

Pour effacer les données de profil local et supprimer le code compilé généré à partir des données de profil local (c'est-à-dire pour rétablir l'état d'installation), exécutez la commande suivante :

adb shell pm compile --reset 

Remarque : Cette commande ne supprime pas le code compilé généré à partir des données de profil externes (.dm) installées avec l'application.

Pour effacer tout le code compilé, exécutez la commande suivante :

adb shell cmd package compile -m verify -f 

Remarque : Cette commande conserve les données de profil locales.