2010-03-31 13 views
35

Ho un programma che ho scritto io stesso in java, ma voglio testare i tempi di esecuzione del metodo e ottenere i tempi per i metodi specifici. Mi stavo chiedendo se è possibile, forse in qualche modo un plug-in di eclissi? o magari inserendo del codice?Come posso eseguire il benchmark del tempo di esecuzione del metodo in java?

Vedo, è un programma piuttosto piccolo, nient'altro che 1500 linee, che sarebbe meglio uno strumento dedicato o System.currentTimeMillis()?

Molte grazie

+3

si dovrebbe usare 'System.nanoTime()' per misurare il tempo trascorso * * (vedi http://stackoverflow.com/questions/238920/quick-question-java-system-clock/ 239661 # 239661), non 'System.currentTimeMillis()'. Altri punti (warmup, JIT) menzionati da @Stephen in un commento sono ancora validi. –

+1

Utilizzare la classe cronometro per questa attività –

risposta

35

Altro che usare un profiler, un modo semplice per ottenere ciò che si vuole è la seguente:

public class SomeClass{ 
    public void somePublicMethod() 
    { 
     long startTime = System.currentTimeMillis(); 
     someMethodWhichYouWantToProfile(); 
     long endTime = System.currentTimeMillis(); 
     System.out.println("Total execution time: " + (endTime-startTime) + "ms"); 
    } 
} 
+0

@Stephen C - punti giusti. Quanto sopra è il metodo che utilizzo principalmente quando cerco di ottenere una rapida idea dell'efficienza del metodo. I miei requisiti nella maggior parte dei casi non sono necessari per la precisione di MS. –

+1

Potrei voler aggiungere a questa risposta che potresti prendere in considerazione il riscaldamento. Usando il flag '-XX: CompileThreshold = 100' costringi la JVM a compilare il tuo metodo al codice nativo quando è stato eseguito 100 volte. Quindi potresti eseguirlo 100 volte senza cronometrare. Dopo di che è stato compilato in codice nativo e potresti misurarlo correttamente. –

+0

C'è un modo per compensare il tempo necessario per chiamare il metodo? Ad esempio, non voglio contare il tempo necessario per copiare i parametri e indicare l'indirizzo di ritorno, ecc. – Celeritas

2

Si dovrebbe usare un profiler come

saranno facilmente integrarsi con qualsiasi IDE e spettacolo qualunque dettaglio che vi serve.

Ovviamente questi strumenti sono complessi e pensati per essere utilizzati per profilare programmi complessi, se hai bisogno di alcuni semplici benchmark ti suggerisco di usare System.currentTimeMillis() o System.nanoTime() e calcolare il delta di millisecondi tra le chiamate da solo.

+0

Vedo, è un programma piuttosto piccolo, nient'altro che 1500 righe, che sarebbe meglio uno strumento dedicato o System.currentTimeMillis()? – KP65

+0

Se hai solo bisogno di controllare la velocità con cui alcuni metodi vanno con __System.currentTimeMillis() __, ma ricorda che non è affatto preciso! Puoi avere quantizzazione di decimi di millisecondi e problemi simili. Il profiling è molto più il modo migliore per fare ciò che devi fare, ma richiede un po 'di apprendimento. – Jack

1

È possibile aggiungere questo codice e verrà indicato per quanto tempo il metodo è stato eseguito.

long millisecondsStart = System.currentTimeMillis(); 
executeMethod(); 
long timeSpentInMilliseconds = System.currentTimeMillis() - millisecondsStart; 
+10

Tre problemi. 1) il tempo di millisecondo può essere quantizzato; per esempio. fino a 20 ms di granularità. 2) stai misurando il tempo di 'executeMethod()' + il tempo di 'System.currentTimeMillis()'. 3) questo non tiene conto degli effetti di riscaldamento JVM; per esempio. Compilazione JIT. –

1

Utilizzando un profiler è meglio perché si può scoprire i tempi di esecuzione medi e dei colli di bottiglia nella vostra applicazione .

Io uso VisualVM. slick e semplice.

0

Un'altra soluzione su misura potrebbe essere basato sul il seguente post: http://www.mkyong.com/spring/spring-aop-examples-advice/

Allora avete anche la possibilità di utilizzare le utilità in tutto il monitoraggio delle applicazioni & SNMP. Se hai bisogno di "misurare" i tuoi metodi su base regolare in un ambiente di produzione, dovresti considerare l'utilizzo di uno di quegli strumenti SNMP

1

Google Guava has a stopwatch, rende le cose semplici e facili.

Stopwatch stopwatch = Stopwatch.createStarted(); 
myFunctionCall(); 
LOGGER.debug("Time taken by myFunctionCall: " + stopwatch.stop()); 
14

Se il collo di bottiglia è abbastanza grande da essere osservato con un profiler, utilizzare un profilatore.

Se è necessaria una maggiore precisione, il modo migliore per misurare un pezzetto di codice è l'utilizzo di un framework di microbenchmark Java come OpenJDK's JMH o Google's Caliper. Credo che siano semplici da usare come JUnit e non solo otterrai risultati più accurati, ma acquisirai l'esperienza della community per farlo nel modo giusto.

Segue un microbenchmark JMH per misurare il tempo di esecuzione di Math.log():

private double x = Math.PI; 

@Benchmark 
public void myBenchmark() { 
    return Math.log(x) 
} 

Uso della currentMillis() e nanoTime() per misurazione ha molte limitazioni:

  1. Hanno latenza (hanno anche il tempo di esecuzione) che influenzano le tue misurazioni.
  2. Hanno MOLTO limitata precisione, questo significa che è possibile mesure cose da 26ns a 26ns in Linux e 300 o giù di lì in Windows ha descritto here
  3. La fase di riscaldamento non viene preso in considerazione, rendendo le vostre misure fluttuano UN SACCO.

I currentMillis() e nanoTime() metodi in Java possono essere utili, ma devono essere utilizzate con ESTREMA CAUTELA oppure è possibile ottenere misure errate errori like this dove l'ordine dei frammenti misurati influenzare le misure o like this dove l'autore erroneamente concludere che diversi milioni di operazioni sono state eseguite in meno di un ms, quando in realtà il JMV non ha realizzato alcuna operazione e ha inserito il codice, senza alcun codice.

Ecco un video meraviglioso che spiega come microbenchmark la strada giusta: https://shipilev.net/#benchmarking

3

Per i test di misurazione del tempo rapido e sporco, non utilizzare il tempo a muro-clock (System.currentTimeMillis()). Preferisco System.nanoTime() invece:

public static void main(String... ignored) throws InterruptedException { 
    final long then = System.nanoTime(); 
    TimeUnit.SECONDS.sleep(1); 
    final long millis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - then); 
    System.out.println("Slept for (ms): " + millis); // = something around 1000. 
} 
Problemi correlati