AOT: Passei uma vez pelo código e o binário vai ser justamente isso aqui x. JIT: Tive que passar várias vezes pelo mesmo trecho de código então acho que posso otimizar isso aqui x.
Valeu pelas dicas, vou assistir. Eu vejo o trade-off assim:
AOT: Não vai perder tempo durante o run-time compilando nada. Não precisa esquentar (warmup). JIT: Vai perder tempo durante o run-time compilando os hot spots. Vai precisar de um tempo de warmup para peak performance.
Só que o JIT pode fazer otimizações muito mais agressivas que o AOT. Acho que o pessoal sempre achou que AOT com -O3 era a coisa mais rápida do mundo. Pelo testes que eu venho fazendo aí parece que perde muitas vezes para o JIT. Runtime information ajuda muito nas otimizações mais agressivas, principalmente no inlining. Sem saber os hotspots, o AOT vai acabar deixando de fazer inlining nas coisas mais importantes. Uma idéia que pensei aqui: por que os compiiladores de C++ não possuem alguma diretriz para forçar inlining de algum método no matter what? Ou tem isso e eu desconheço?
O que se faz é usar PGO (profiling information) that can be fed into the AOT compiler. Tanto o AOT quanto o JIT podem ter isso. Mas daí o JIT leva muita vantagem, porque se os HotSpots mudarem em tempo de execução ele pode se re-adaptar, ou seja, recompilar os novos hot spots. AOT não existe depois que o código começa a executar.
Na minha cabeça (posso estar errado) o problema é que se o código muda, daí vc tem que refazer o PGO para refletir o novo código. Se o código muda pouco no problem. Se muda muito aí complica.
Agora para concluir, minhas pesquisas com o PGO do GraalVM e da ZingVM (ReadyNow) mostraram uma melhorar de no máximo 50%. Ou seja, não chega perto do JIT em tempo de execução não. É uma ajuda, mas não é a solução para não precisar de JIT.
NOTE: PGO = Profile-guided optimizations
por que os compiiladores de C++ não possuem alguma diretriz para forçar inlining de algum método no matter what?
Forçar inline indiscriminadamente é impacta no cache de instruções e o aumento do tamanho do binário, pode acabar poluindo o cache de instruções (https://isocpp.org/wiki/faq/inline-functions#inline-and-perf).
Sobre os hotspots mudarem durante a execução, isso não costuma ser uma preocupação no contexto de C++, porque ela é geralmente escolhida para cenários onde sabemos que estamos lidando com rotinas CPU-bound e grandes volumes de dados. Nesses cenários, mesmo que surjam novas features, times experientes em C++ geralmente já estão espertos para identificar isso.