Perché il codice Java generato per eseguire una corsa funzionamento più lentamente di un “loop interprete”?

StackOverflow https://stackoverflow.com/questions/875695

Domanda

Ho qualche codice Java che esegue operazioni bit per bit su un BitSet. Ho una lista di operazioni e può "interpretare" loro da loop su di loro, ma è importante per me che posso eseguire queste operazioni il più rapidamente possibile, così ho cercato di generare dinamicamente il codice di applicarle. I generare sorgente Java per eseguire le operazioni e compilare una classe attuazione di tali operazioni utilizzando Javassist.

Purtroppo, il mio codice generato dinamicamente viene eseguito più lentamente rispetto al codice interpretato. Sembra che questo è perché HotSpot sta ottimizzando il codice interpretato, ma non è l'ottimizzazione del codice compilato: Dopo l'eseguo qualche migliaio di volte, il mio codice interpretato corre due volte più veloce come ha fatto inizialmente, ma il mio codice compilato non mostra alcun aumento di velocità. Coerentemente con questa ipotesi, il mio codice interpretato è inizialmente più lento del codice compilato, ma è alla fine più veloce.

Non sono sicuro perché questo sta accadendo. La mia ipotesi è che forse Javassist utilizza un caricatore di classe di cui classi HotSpot non tocca. Ma io non sono esperto di carico di classe in Java, quindi non sono sicuro se questo è un'ipotesi ragionevole o come fare per testarlo. Ecco come sto creando e caricando la classe con Javassist:

ClassPool pool = ClassPool.getDefault();
CtClass tClass = pool.makeClass("foo");

// foo implements MyInterface, with one method
tClass.addInterface(pool.get(MyInterface.class.getName()));

// Get the source for the method and add it
CtMethod tMethod = CtNewMethod.make(getSource(), tClass);
tClass.addMethod(tMethod);

// finally, compile and load the class
return (MyInterface)tClass.toClass().newInstance();

Qualcuno ha un'idea di quello che sta succedendo qui? Mi piacerebbe davvero apprezzato tutto l'aiuto che si può dare.

Sto usando la JVM server Sun 1.6 su Windows XP a 32 bit.

È stato utile?

Soluzione

HotSpot non importa dove il codice proviene. Ad esempio, sarà codice felicemente linea chiamata attraverso un metodo chiamata virtuale con un'implementazione caricata da una classe loader diverso.

Vi suggerisco di scrivere nel codice sorgente le operazioni che si sta tentando di eseguire per questo benchmark, e quindi punto di riferimento che. Di solito è più facile scrivere un esempio di codice generato piuttosto che scrivere il generatore in ogni caso.

C'è un certo numero di motivi per cui HotSpot potrebbe non ottimizzare il codice così difficile come potrebbe. Per esempio i metodi molto lunghi tendono a non essere inline o ha metodo inline in loro.

Altri suggerimenti

Credo di capire cosa stava succedendo qui. Il mio primo errore è stato generando metodi che sono stati troppo a lungo. Dopo mi fisso che, ho notato che anche se il mio codice generato è stato ancora più lento, ma alla fine si avvicinò alla velocità del codice interpretato.

Penso che il più grande aumento di velocità arriva dal HotSpot ottimizzare il mio codice. Nella versione interpretata, c'è ben poco di codice per ottimizzare, in modo da HotSpot prende rapidamente cura di esso. Nella versione generata, c'è un sacco di codice per ottimizzare, in modo da HotSpot richiede più tempo per lavorare la sua magia su tutto il codice.

Se corro i miei punti di riferimento abbastanza a lungo, ora vedo il mio codice generato eseguendo solo leggermente migliore rispetto al codice interpretato.

C'è un impostazioni JVM che controlla come codice veloce dovrebbero essere raccolti XX: CompileThreshold = 10000

  

Numero di chiamate di metodi / rami prima della compilazione [-client: 1,500]

Non so se questo aiuterà, perché nel tuo esempio, la dimensione sembrano giocare un ruolo fondamentale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top