O JIT atual otimiza os códigos de máquina gerados para previsão de ramificação com base nas estatísticas de tempo de execução?

8

Algumas JVMs compilariam o código de bytes Java no código de máquina nativo. Sabemos que existem muitas otimizações que poderíamos aplicar para isso. Recentemente, também aprendi que uma operação de ramificação pode bloquear a CPU e afetar significativamente o desempenho, se uma CPU fizer uma previsão errada.

Alguém sabe se alguma JVM geraria códigos de máquina mais facilmente para a CPU fazer a previsão correta com base nas estatísticas de tempo de execução coletadas?

William Wong
fonte
1
Eu acho que o HotSpot faz isso, mas também a CPU possui tecnologia de previsão dinâmica desde o Pentium II; portanto, se tomou a decisão errada duas vezes, se corrigirá na terceira vez se for permitido reconhecer o contexto.
Aadaam

Respostas:

6

Não, o HotSpot não adiciona dicas ao preditor de ramificação de hardware, conforme indicado na lista de discussão do OpenJDK :

Foi considerado e decidido contra. As plataformas que o openjdk atualmente visa, todas têm uma previsão de filial de hardware decente a espetacular. Aqueles que não o fizeram, como o Niagara 1, ignoraram os bits de previsão. A conclusão é que não vale a pena complicar o código, como diz David, 'macros mágicas'.

Rafael Winterhalter
fonte
O OpenJDK não é o HotSpot AFAIK.
Florian Margaine
Sim, ele é. HotSpot é o VM que faz parte do OpenJDK: openjdk.java.net/groups/hotspot
Rafael Winterhalter
Meu mal então. Eu pensei que o HotSpot era a VM da Sun e o OpenJDK era uma alternativa de código aberto.
Florian Margaine
2

Meu palpite é que as dicas de previsão no nível de instruções da máquina são, na melhor das hipóteses, um ruído e, na pior das hipóteses, um prejuízo (bytes de instrução desperdiçados) na moderna arquitetura fora de ordem e de execução especulativa. Fazer isso seria como dizer à CPU para diminuir a velocidade - para parar de fazer as coisas já inteligentes que foi projetada para executar.


Em segundo lugar, o grau em que a previsão do ramo pode ser aprimorada depende da causa da imprevisibilidade e da facilidade com que se pode medir os efeitos de desempenho ou observar a tendência do ramo.


No entanto, acho que o pacote existente de truques de otimização JIT já pode melhorar a previsão de ramificações até certo ponto, mesmo sem a ajuda dos contadores de erros de predição de ramificação da CPU.

Apenas um exemplo de código muito simples:

public void repeatHistory(int value)
{
    if (value == 1492)
    {
        landing();
    }
    else if (value == 1776)
    {
        ratifying();
    }
}

Supõe-se que isso repeatHistoryseja chamado muitas vezes. Quando o monitor de desempenho baseado em amostragem analisa as estatísticas da pilha de chamadas, ele pode descobrir que, por qualquer motivo, a repeatHistory()chamada ratifying()ocorre com mais frequência do que a chamada anterior landing(). Com base nesta observação, a próxima passagem da geração de código JIT para o repeatHistorymétodo levará isso em consideração e executará uma ou mais otimizações:

  • Mova a verificação para (value == 1776)antes da verificação para(value == 1492)
  • Tente incorporar o ratifying()método na ramificação emrepeatHistory()
  • Se repeatHistory()for chamado de outro loop, tente desenrolar o loop ou incline o repeatHistory()método nesse loop.
  • E muitos outros.

Depois de aplicar uma otimização, geralmente é necessário analisar novamente para ver se mais otimizações podem ser aplicadas, porque uma bem-sucedida geralmente abre as portas para mais oportunidades.


rwong
fonte