Observação:

Otimize Aplicativos Java Nativos da Nuvem com GraalVM PGO Empresarial

Introdução

Este laboratório mostra como executar um benchmark Java Microbenchmark Harness (JMH) como um executável nativo, criado com o GraalVM Native Image e aplicar o Profile-Guided Optimization (PGO) para melhorar o desempenho.

GraalVM Native Image permite que você compile um aplicativo Java em um executável nativo que começa quase que instantaneamente, requer menos memória e CPU.

A Otimização Guiada por Perfil (PGO) é uma técnica comumente usada no ecossistema Java para mitigar a otimização just-in-time ausente e reunir os perfis de execução em uma execução e, em seguida, usá-los para otimizar a(s) compilação(ões) subsequente(s). Com a PGO, você pode coletar os dados de criação de perfil e, em seguida, alimentá-los para a ferramenta native-image, que usará essas informações para otimizar ainda mais o desempenho do executável resultante.

Observações sobre o Uso do JMH com a Imagem Nativa GraalVM

Ao executar na JVM, o JMH forçará uma nova JVM para cada benchmark para garantir que não haja interferência nas medições de cada benchmark. Essa abordagem não é possível ao usar o GraalVM Native Image; portanto, você deve considerar a seguinte orientação ao criar benchmarks do JMH que devem ser executados como executáveis nativos:

Observação: O OCI (Oracle Cloud Infrastructure) fornece GraalVM Enterprise sem custo adicional.

Objetivos do laboratório

Neste laboratório, você irá:

Tempo estimado do laboratório: 30-45 minutos

OBSERVAÇÃO: se você vir o ícone de laptop nas instruções, isso significa que é necessário informar um comando. Fique de olho por isso.

# This is where we you will need to do something

Para copiar um comando, passe o mouse sobre o campo e clique no ícone Copiar para área de transferência.

Para colar um comando copiado em uma janela de terminal, clique com o botão direito do mouse e selecione a opção Colar no menu de contexto. Se preferir atalhos de teclado, use CTRL+SHIFT+V.

ETAPA 1: Estabelecer Conexão com um Host Remoto e Verificar o Ambiente de Desenvolvimento

Seu ambiente de desenvolvimento é fornecido por um host remoto: uma Instância de Computação do OCI com Oracle Linux 8, 4 CPUs e 32 GB de memória.

O ambiente de área de trabalho será exibido antes que o host remoto esteja pronto, o que pode levar até dois minutos.

O Visual Studio Code (VS Code) será aberto e se conectará automaticamente à instância da VM que foi provisionada para você. Clique em Continuar para aceitar a impressão digital da máquina.

Aceitar Código VS

Se você não clicar em Continuar, o VS Code exibirá uma caixa de diálogo, mostrada abaixo. Clique em Repetir. O VS Code pedirá que você aceite impressão digital da máquina. Clique em Continuar.

Conexão de Repetição do Código VS

Problemas com a Conexão com o Ambiente de Desenvolvimento Remoto

Se você encontrar outros problemas nos quais o VS Code falha ao estabelecer conexão com o ambiente de desenvolvimento remoto que não são abordados acima, tente o seguinte:

Parabéns, agora você está conectado a um host remoto no Oracle Cloud!

O script abrirá o VS Code, conectado ao seu host remoto, com o código-fonte do laboratório aberto.

Em seguida, abra um Terminal no VS Code. O Terminal permite que você interaja com o host remoto. Um terminal pode ser aberto no VS Code por meio do menu: Terminal > Novo Terminal, conforme mostrado abaixo.

Terminal de Código VS

Observação sobre o Ambiente de Desenvolvimento

Você usará o GraalVM Enterprise como um ambiente de runtime Java para este laboratório. GraalVM é uma distribuição JDK de alto desempenho da Oracle criada no Oracle Java SE.
Seu ambiente de desenvolvimento vem pré-configurado com o GraalVM Enterprise e o conjunto de ferramentas Native Image necessários para este laboratório. Você pode verificar isso executando estes comandos no terminal:

java -version

native-image --version

Você pode prosseguir para a próxima etapa.

ETAPA 2: Compilar e Executar um Benchmark JMH na JVM

O código-fonte do aplicativo - benchmark JMH - está disponível no seu host remoto. O benchmark JMH se origina do Jogo de Benchmarks do Compute Language. Ele cria árvores binárias - antes de qualquer nó de árvore ser coletado lixo - usando no mínimo o número de alocações.

Este benchmark JMH usa a reflexão de Java. A ferramenta native-image opera sob o que é conhecido como a suposição "mundo fechado" e não incluirá elementos acessados refletivamente no executável nativo, a menos que a ferramenta seja fornecida com a configuração necessária no tempo de construção. Para criar um executável nativo deste benchmark JMH, você precisa executar o Agente de Rastreamento para fornecer a configuração de reflexão para native-image. Isso já foi feito para você economizar tempo e a configuração gerada pode ser encontrada em src/main/resources/META-INF/native-image/. Para obter mais informações sobre a configuração de reflexão, consulte Luna Lab sobre GraalVM Native Image and Reflection.

Crie e execute o benchmark como um aplicativo Java, executando o seguinte comando:

mvn clean package exec:exec

Observe que no arquivo pom.xml há instruções para desativar explicitamente o compilador JIT GraalVM usando a opção -XX:-UseJVMCICompiler. Isso significa que o benchmark será executado usando o compilador JIT C2.

O aplicativo executará o benchmark em três iterações e exibirá os resultados no terminal. A execução deve levar menos de quatro minutos para ser concluída. O resultado final é o mais significativo. Você deverá ver algo como:

Benchmark          (binaryTreesN)   Mode  Cnt    Score   Error  Units
BinaryTrees.bench              14  thrpt    3  180.819 ± 8.301  ops/s

Agora você pode passar para a próxima etapa.

ETAPA 3: Criar e Executar um Benchmark JMH como um Executável Nativo

Agora crie um executável nativo usando o GraalVM Enterprise Native Image.

O benchmark JMH é criado com o Maven e aplica o plug-in Maven para criação de Imagens Nativas GraalVM (abra pom.xml para ver o registro do plug-in native-maven-plugin). O plug-in indica qual arquivo JAR ele precisa passar para native-image e qual deve ser a classe principal executável.

  1. Crie um executável nativo. O build deve levar aproximadamente um minuto:

    mvn package -Pnative
    

    O perfil Maven -Pnative ativa a criação de um executável nativo. Ele gerará um executável nativo no diretório target, chamado benchmark-binary-tree.

  2. Em seguida, execute o benchmark como um executável nativo:

    ./target/benchmark-binary-tree
    

    Estes são os resultados obtidos com o GraalVM Enterprise Native Image 22.2.0:

    Benchmark          (binaryTreesN)   Mode  Cnt    Score    Error  Units
    BinaryTrees.bench              14  thrpt    3  174.135 ± 10.020  ops/s
    

    Os números executáveis nativos podem ser semelhantes ou melhores em comparação com a opção anterior (não nativa). Os resultados variarão, dependendo do hardware no qual você executar o mesmo benchmark.

Agora você pode passar para a próxima etapa.

ETAPA 4: Otimizar um Executável Nativo com PGO e Executar

Agora otimize seu executável nativo usando GOP (Profile-Guided Optimization). É um processo de duas etapas. Primeiro, crie uma versão instrumentada do executável nativo e execute-a para rastrear sua execução e coletar um perfil de desempenho. Quando a execução terminar, ela gerará um arquivo de perfil, default.iprof, no diretório raiz do projeto. Em seguida, crie um executável otimizado contendo os dados de perfil sobre o benchmark e execute-o.

O recurso de Otimização Guiada por Perfil (PGO) está disponível com o GraalVM Enterprise Edition.

  1. Crie um executável nativo instrumentado informando o perfil -Pinstrumented do Maven:

    mvn package -Pinstrumented
    

    Ele gera um binário no diretório de destino, chamado benchmark-binary-tree-instr.

  2. Execute-a para coletar os perfis de frequência de execução de código:

    ./target/benchmark-binary-tree-instr
    

    Os perfis coletados dessa execução são armazenados no arquivo default.iprof no diretório de trabalho atual, se nada mais for especificado.

    Observação: Você pode especificar onde coletar os perfis ao executar um executável nativo instrumentado informando a opção -XX:ProfilesDumpFile=YourFileName no runtime. Você também pode coletar vários arquivos de perfil especificando nomes diferentes e transmiti-los para a ferramenta native-image no momento da criação.

  3. Agora que você gerou o arquivo de perfil, crie a versão otimizada:

    mvn package -Poptimized
    

    Ele gera um binário otimizado no diretório target, chamado benchmark-binary-tree-opt.

  4. Por fim, execute o executável nativo otimizado:

    ./target/benchmark-binary-tree-opt
    

Estes são os resultados obtidos com o GraalVM Enterprise Native Image 22.2.0 na máquina host:

Benchmark          (binaryTreesN)   Mode  Cnt    Score   Error  Units
BinaryTrees.bench              14  thrpt    3  223.241 ± 3.578  ops/s

A pontuação média de operações por segundo aumentou de 180 em execução como um aplicativo Java para 223 em execução como um executável nativo otimizado. Os resultados variarão, dependendo do hardware no qual você executar o mesmo benchmark.

Resumo

Este laboratório mostrou como você pode otimizar executáveis nativos com a Otimização Guiada por Perfil (PGO) para obter maior throughput em comparação com a versão Java, preservando ainda outros benefícios: inicialização instantânea, menor uso de CPU e memória. Com o PGO, você pode "treinar" seu aplicativo para cargas de trabalho específicas e transformá-lo em um binário otimizado sem sacrificar nenhum desempenho.

Saiba Mais

Parabéns! Você concluiu com sucesso este laboratório.

Mais Recursos de Aprendizagem

Explore outros laboratórios no site docs.oracle.com/learn ou acesse mais conteúdo de aprendizado gratuito no canal YouTube do Oracle Learning. Além disso, visite education.oracle.com/learning-explorer para se tornar um Oracle Learning Explorer.

Para obter a documentação do produto, visite o Oracle Help Center.