Implementando o compilador ART Just-In-Time (JIT)

O Android runtime (ART) inclui um compilador just-in-time (JIT) com perfil de código que melhora continuamente o desempenho dos aplicativos Android à medida que são executados. O compilador JIT complementa o atual compilador antecipado (AOT) do ART e melhora o desempenho do tempo de execução, economiza espaço de armazenamento e acelera as atualizações de aplicativos e sistemas. Ele também melhora o compilador AOT, evitando a desaceleração do sistema durante atualizações automáticas de aplicativos ou recompilação de aplicativos durante atualizações over-the-air (OTA).

Embora JIT e AOT usem o mesmo compilador com um conjunto semelhante de otimizações, o código gerado pode não ser idêntico. O JIT faz uso de informações de tipo de tempo de execução, pode fazer melhor inlining e possibilita a compilação de substituição de pilha (OSR), o que gera um código ligeiramente diferente.

Arquitetura JIT

Arquitetura JIT
Figura 1. Arquitetura JIT.

Compilação JIT

A compilação JIT envolve as seguintes atividades:

Composição guiada por perfil
Figura 2. Compilação guiada por perfil.
  1. O usuário executa o aplicativo, que aciona o ART para carregar o arquivo .dex .
    • Se o arquivo .oat (o binário AOT para o arquivo .dex ) estiver disponível, o ART o usará diretamente. Embora os arquivos .oat sejam gerados regularmente, eles nem sempre contêm código compilado (binário AOT).
    • Se o arquivo .oat não contiver código compilado, o ART será executado por meio do JIT e do interpretador para executar o arquivo .dex .
  2. O JIT está habilitado para qualquer aplicativo que não seja compilado de acordo com o filtro de compilação de speed (que diz "compile o máximo que puder do aplicativo").
  3. Os dados do perfil JIT são despejados em um arquivo em um diretório do sistema que somente o aplicativo pode acessar.
  4. O daemon de compilação AOT ( dex2oat ) analisa esse arquivo para conduzir sua compilação.

    daemon JIT
    Figura 3. Atividades do daemon JIT.

O serviço Google Play é um exemplo usado por outros aplicativos que se comportam de forma semelhante às bibliotecas compartilhadas.

Fluxo de trabalho JIT

Arquitetura JIT
Figura 4. Fluxo de dados JIT.
  • As informações de criação de perfil são armazenadas no cache de código e sujeitas à coleta de lixo sob pressão de memória.
    • Não há garantia de que um instantâneo tirado quando o aplicativo estava em segundo plano conterá dados completos (ou seja, tudo que foi JITed).
    • Não há nenhuma tentativa de garantir que tudo seja registrado (pois isso pode afetar o desempenho do tempo de execução).
  • Os métodos podem estar em três estados diferentes:
    • interpretado (código dex)
    • JIT compilado
    • AOT compilado
    Se o código JIT e AOT existir (por exemplo, devido a desotimizações repetidas), o código JITed é o preferido.
  • O requisito de memória para executar o JIT sem afetar o desempenho do aplicativo em primeiro plano depende do aplicativo em questão. Aplicativos grandes exigem mais memória do que aplicativos pequenos. Em geral, aplicativos grandes se estabilizam em torno de 4 MB.

Ativando o registro JIT

Para ativar o registro JIT, execute os seguintes comandos:

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

Desativando JIT

Para desabilitar o JIT, execute os seguintes comandos:

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

Forçando compilação

Para forçar a compilação, execute o seguinte:

adb shell cmd package compile

Casos de uso comuns para forçar a compilação de um pacote específico:

  • Baseado em perfil:
    adb shell cmd package compile -m speed-profile -f my-package
    
  • Completo:
    adb shell cmd package compile -m speed -f my-package
    

Casos de uso comuns para forçar a compilação de todos os pacotes:

  • Baseado em perfil:
    adb shell cmd package compile -m speed-profile -f -a
    
  • Completo:
    adb shell cmd package compile -m speed -f -a
    

Limpando dados do perfil

Para limpar os dados do perfil e remover o código compilado, execute o seguinte:

  • Para um pacote:
    adb shell cmd package compile --reset my-package
    
  • Para todos os pacotes:
    adb shell cmd package compile --reset -a