Implementare il compilatore just-in-time ART

Android runtime (ART) include un compilatore just-in-time (JIT) con profilazione del codice che migliora continuamente le prestazioni delle applicazioni Android durante l'esecuzione. Il compilatore JIT integra l'attuale compilatore ahead-of-time (AOT) di ART e migliora le prestazioni di runtime, consente di risparmiare spazio di archiviazione e accelera gli aggiornamenti di applicazioni e sistema. Migliora inoltre il compilatore AOT evitando il rallentamento del sistema durante gli aggiornamenti automatici delle applicazioni o la ricompilazione delle applicazioni durante gli aggiornamenti over-the-air (OTA).

Sebbene JIT e AOT utilizzino lo stesso compilatore con un set di ottimizzazioni simile, il codice generato potrebbe non essere identico. JIT utilizza le informazioni sul tipo di runtime, può eseguire un migliore inlining e rende possibile la compilazione di sostituzione dello stack (OSR), il che genera codice leggermente diverso.

Architettura JIT

Architettura JIT
Figura 1. Architettura JIT.

Compilazione JIT

La compilazione JIT prevede le seguenti attività:

Comp. guidata dal profilo
Figura 2. Compilazione guidata dal profilo.
  1. L'utente esegue l'app, che quindi attiva ART per caricare il file .dex .
    • Se il file .oat (il binario AOT per il file .dex ) è disponibile, ART lo utilizza direttamente. Sebbene i file .oat vengano generati regolarmente, non sempre contengono codice compilato (binario AOT).
    • Se il file .oat non contiene codice compilato, ART esegue il JIT e l'interprete per eseguire il file .dex .
  2. JIT è abilitato per qualsiasi applicazione che non è compilata in base al filtro di compilazione speed (che dice "compila il più possibile dall'app").
  3. I dati del profilo JIT vengono scaricati in un file in una directory di sistema a cui può accedere solo l'applicazione.
  4. Il demone di compilazione AOT ( dex2oat ) analizza quel file per guidarne la compilazione.

    demone JIT
    Figura 3. Attività del demone JIT.

Il servizio Google Play è un esempio utilizzato da altre applicazioni che si comportano in modo simile alle librerie condivise.

Flusso di lavoro JIT

Architettura JIT
Figura 4. Flusso di dati JIT.
  • Le informazioni di profilazione vengono archiviate nella cache del codice e soggette a Garbage Collection sotto pressione della memoria.
    • Non esiste alcuna garanzia che uno snapshot scattato quando l'applicazione era in background contenga dati completi (ovvero, tutto ciò che è stato sottoposto a JIT).
    • Non viene effettuato alcun tentativo di garantire che tutto venga registrato (poiché ciò può influire sulle prestazioni di runtime).
  • I metodi possono trovarsi in tre stati diversi:
    • interpretato (codice dex)
    • JIT compilato
    • AOT compilato
    Se esistono sia codice JIT che AOT (ad esempio a causa di ripetute de-ottimizzazioni), è preferibile il codice JIT.
  • Il requisito di memoria per eseguire JIT senza influire sulle prestazioni dell'app in primo piano dipende dall'app in questione. Le app di grandi dimensioni richiedono più memoria delle app di piccole dimensioni. In generale le app di grandi dimensioni si stabilizzano intorno ai 4 MB.

Attiva la registrazione JIT

Per attivare la registrazione JIT, esegui i seguenti comandi:

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

Disabilita JIT

Per disabilitare JIT, eseguire i seguenti comandi:

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

Compilazione forzata

Per forzare la compilazione, eseguire quanto segue:

adb shell cmd package compile

Casi d'uso comuni per forzare la compilazione di un pacchetto specifico:

  • Basato sul profilo:
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Completo:
    adb shell cmd package compile -m speed -f my-package
    

Casi d'uso comuni per forzare la compilazione di tutti i pacchetti:

  • Basato sul profilo:
    adb shell cmd package compile -m speed-profile -f -a
    
  • Completo:
    adb shell cmd package compile -m speed -f -a
    

Cancella i dati del profilo

Per cancellare i dati del profilo e rimuovere il codice compilato, esegui quanto segue:

  • Per un pacchetto:
    adb shell cmd package compile --reset my-package
    
  • Per tutti i pacchetti:
    adb shell cmd package compile --reset -a