Test delle prestazioni Java

Voglio fare alcuni test di temporizzazione su un’applicazione Java. Questo è quello che sto facendo attualmente:

long startTime = System.currentTimeMillis(); doSomething(); long finishTime = System.currentTimeMillis(); System.out.println("That took: " + (finishTime - startTime) + " ms"); 

C’è qualcosa di “sbagliato” nel test delle prestazioni come questo? Qual è un modo migliore?

Duplicato : il benchmark del cronometro è accettabile?

    L’unica pecca in questo approccio è che il tempo “reale” che doSomething() richiede per eseguire può variare in modo selvaggio a seconda di quali altri programmi sono in esecuzione sul sistema e quale è il suo carico. Ciò rende la misurazione delle prestazioni un po ‘imprecisa.

    Un modo più accurato di tracciare il tempo necessario per eseguire il codice, supponendo che il codice sia a thread singolo, consiste nell’esaminare il tempo di CPU consumato dal thread durante la chiamata. Puoi farlo con le classi JMX; in particolare, con ThreadMXBean . È ansible recuperare un’istanza di ThreadMXBean da java.lang.management.ManagementFactory e, se la piattaforma lo supporta (la maggior parte), utilizzare il metodo getCurrentThreadCpuTime al posto di System.currentTimeMillis per eseguire un test simile. getCurrentThreadCpuTime presente che getCurrentThreadCpuTime riporta il tempo in nanosecondi, non in millisecondi.

    Ecco un metodo di esempio (Scala) che potrebbe essere utilizzato per eseguire una misurazione:

     def measureCpuTime(f: => Unit): java.time.Duration = { import java.lang.management.ManagementFactory.getThreadMXBean if (!getThreadMXBean.isThreadCpuTimeSupported) throw new UnsupportedOperationException( "JVM does not support measuring thread CPU-time") var finalCpuTime: Option[Long] = None val thread = new Thread { override def run(): Unit = { f finalCpuTime = Some(getThreadMXBean.getThreadCpuTime( Thread.currentThread.getId)) } } thread.start() while (finalCpuTime.isEmpty && thread.isAlive) { Thread.sleep(100) } java.time.Duration.ofNanos(finalCpuTime.getOrElse { throw new Exception("Operation never returned, and the thread is dead " + "(perhaps an unhandled exception occurred)") }) } 

    (Sentiti libero di tradurre quanto sopra in Java!)

    Questa strategia non è perfetta, ma è meno soggetta a variazioni nel carico del sistema.

    Il codice mostrato nella domanda non è un buon codice di misurazione delle prestazioni:

    1. Il compilatore potrebbe scegliere di ottimizzare il codice riordinando le istruzioni. Sì, può farlo. Ciò significa che l’intero test potrebbe non riuscire. Può persino scegliere di allineare il metodo in prova e riordinare le istruzioni di misurazione nel codice ora in linea.

    2. L’hotspot potrebbe scegliere di riordinare le istruzioni, il codice inline, i risultati della cache, l’esecuzione ritardata …

    3. Anche supponendo che il compilatore / hotspot non ti abbia ingannato, ciò che misuri è “wall time”. Quello che dovresti misurare è il tempo della CPU (a meno che tu non usi le risorse del sistema operativo e desideri includerle o tu misuri la contest lock in un ambiente multi-thread).

    La soluzione? Usa un vero profiler. Ci sono molte cose in giro, sia profiler gratuiti che demo / prove cronometrate di quelli della forza commerciale.

    L’utilizzo di un Java Profiler è l’opzione migliore e ti darà tutte le informazioni necessarie nel codice. viz Tempi di risposta, Thread CallTraces, Memory Utilisations, ecc

    Ti suggerirò JENSOR , un Java Profiler open source, per la sua facilità d’uso e nessun overhead sulla CPU. Puoi scaricarlo, instrumentare il codice e ottenere tutte le informazioni necessarie sul tuo codice.

    Puoi scaricarlo da: http://jensor.sourceforge.net /

    Tenere presente che la risoluzione di System.currentTimeMillis() varia tra i diversi sistemi operativi. Credo che Windows sia di circa 15 msec. Quindi se doSomething() viene eseguito più velocemente della risoluzione temporale, otterrai un delta pari a 0. È ansible eseguire doSomething() in un ciclo più volte, ma la JVM potrebbe ottimizzarlo.

    Bene, questa è solo una parte dei test delle prestazioni. A seconda della cosa che stai testando, potresti dover considerare la dimensione dell’heap, il numero di thread, il traffico di rete o tutta una serie di altre cose. Altrimenti uso questa tecnica per cose semplici che voglio solo vedere quanto tempo impiegano per correre.

    Ciò è positivo quando si confronta un’implementazione con un’altra o si cerca di trovare una parte lenta nel codice (anche se può essere noioso). È una tecnica davvero buona da conoscere e probabilmente la userai più di ogni altra, ma avrai anche familiarità con uno strumento di profilazione.

    Hai esaminato gli strumenti di profilazione di netbeans ed eclipse . Questi strumenti ti danno una migliore gestione di ciò che è REALMENTE occupando tutto il tempo nel tuo codice. Ho riscontrato problemi che non avevo realizzato utilizzando questi strumenti.

    Immagino che vorresti fare Qualcosa () prima di iniziare anche il cronometraggio, in modo che il codice sia JITted e “scaldato”.

    Japex può essere utile per te, sia come metodo per creare rapidamente benchmark, sia come metodo per studiare i problemi di benchmarking in Java attraverso il codice sorgente.