Il JIT corrente ottimizza i codici macchina generati per la previsione delle filiali in base alle statistiche di runtime?

8

Alcune JVM compilerebbero codice byte Java in codice macchina nativo. Sappiamo che ci sono molte ottimizzazioni che potremmo applicare per questo. Recentemente, ho anche appreso che un'operazione di ramo può bloccare la CPU e influire in modo significativo sulle prestazioni, se una CPU fa una previsione sbagliata.

Qualcuno sa se una JVM potrebbe generare codici macchina più facili per la CPU che effettua la previsione giusta in base alle statistiche di runtime raccolte?

    
posta William Wong 06.08.2012 - 18:05
fonte

2 risposte

6

No, HotSpot non aggiunge suggerimenti al predittore del ramo hardware come indicato su OpenJDK mailing list :

It's been considered, and decided against. The platforms which openjdk currently targets all have decent to spectacular hardware branch prediction. Those that didn't, such as Niagara 1, ignored prediction bits. Conclusion is that it's not worth complicating the code with, as David says, 'magic macros'.

    
risposta data 25.02.2015 - 23:56
fonte
2

La mia ipotesi è che i suggerimenti di previsione a livello di istruzione della macchina siano nel migliore dei casi un rumore, e nel peggiore dei casi un danno (spreco di byte di istruzioni) su un'architettura moderna in esecuzione speculativa, fuori dall'ordine. Fare ciò equivarrebbe a dire alla CPU di stupire - a smettere di fare le sue cose già intelligenti che è stato progettato per eseguire.

In secondo luogo, il grado in cui può essere migliorata la previsione del ramo dipende dalla causa del misprediction e dalla facilità con cui si possono misurare gli effetti delle prestazioni di, o osservare la tendenza del ramo.

Tuttavia, ritengo che il pacchetto esistente di trucchi di ottimizzazione JIT possa già migliorare la previsione dei rami in una certa misura, anche senza l'ausilio di contatori di errata previsione della CPU.

Solo un esempio di codice molto semplice:

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

Supposto che repeatHistory venga chiamato un sacco di volte. Quando il monitor delle prestazioni basato sul campionamento analizza le statistiche dello stack di chiamata, potrebbe trovare che, per qualsiasi motivo, repeatHistory() chiama ratifying() si verifica più frequentemente rispetto alla precedente chiamata landing() . Sulla base di questa osservazione, la prossima passata di generazione del codice JIT per il metodo repeatHistory terrà conto di questo ed eseguirà una o più ottimizzazioni:

  • Sposta il segno di spunta per (value == 1776) prima del controllo per (value == 1492)
  • Tentativo di incorporare il metodo ratifying() nel ramo in repeatHistory()
  • Se il repeatHistory() viene chiamato da un altro ciclo, prova a srotolare il ciclo o incorpora il metodo repeatHistory() in quel ciclo.
  • E molti altri.

Dopo aver applicato una ottimizzazione, è spesso necessario analizzare nuovamente per vedere se è possibile applicare più ottimizzazioni, perché una soluzione di successo spesso apre la porta a più opportunità.

risposta data 26.02.2015 - 08:47
fonte

Leggi altre domande sui tag