Jak mierzyć szybkość wykonywania programu Java

85

Jak oceniasz czas wykonania programu Java? Nie jestem pewien, jakiej klasy powinienem użyć, aby to zrobić.

Szukam czegoś takiego:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);
George Mic
źródło

Odpowiedzi:

139
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));
bua
źródło
2
właściwie powinno to być nanoTime
Eugene
6
Nie powinien być nanoTime. Zobacz odpowiedź rhu.
fabspro,
4
Czy jest jakiś szczególny powód, dla którego użyłeś tutaj słowa „final”? Co by się zmieniło, gdybyś porzucił to słowo kluczowe?
dijxtra
9
Używanie @dijxtra finalma tę zaletę, że nie można jej przypadkowo przypisać (a także innych korzyści, takich jak anonimowy dostęp do klas itp.). W tym kodzie nie miałoby to znaczenia. Dość powszechną praktyką jest robienie wszystkiego finali finalłączenie go tylko w razie potrzeby.
wchargin
1
Kod do testowania wraz z pomiarem czasu należy uruchomić wiele razy, a pierwszy wynik należy odrzucić. Pierwszy będzie prawdopodobnie obejmował czasy ładowania klasy itp. Uruchamiając go wielokrotnie, również oczywiście otrzymasz średnią, która jest bardziej pomocna i wiarygodna.
Arun Ramakrishnan
34

Należy pamiętać, że istnieją pewne problemy, w przypadku System#nanoTime()których nie można niezawodnie używać na wielordzeniowych procesorach do rejestrowania czasu, który upłynął ... każdy rdzeń ma własny TSC ( licznik znaczników czasu ): ten licznik jest używany do uzyskania czasu nano (tak naprawdę jest liczba taktów od momentu uruchomienia procesora).

W związku z tym, jeśli system operacyjny nie wykona pewnego dopasowania czasu TSC, aby utrzymać synchronizację rdzeni, to jeśli wątek zostanie zaplanowany na jednym rdzeniu, gdy zostanie odczytany początkowy czas, a następnie zostanie przełączony na inny rdzeń, względny czas może sporadycznie wydawać się przeskoczyć wstecz i naprzód.

Zauważyłem to jakiś czas temu na AMD / Solaris, gdzie czasy, które upłynęły między dwoma punktami czasowymi, czasami wracały jako wartości ujemne lub nieoczekiwanie duże liczby dodatnie. Była łatka na jądro Solaris i ustawienie BIOS wymagane do wymuszenia AMD PowerNow! off, który wydawał się go rozwiązać.

Ponadto istnieje (AFAIK) jak dotąd nie naprawiony błąd podczas korzystania z języka Java System#nanoTime()w środowisku VirtualBox; powodując dla nas różnego rodzaju dziwne, sporadyczne problemy z gwintowaniem, ponieważ większość java.util.concurrencypakietu opiera się na nano-czasie.

Zobacz też:

Czy System.nanoTime () jest całkowicie bezużyteczny? http://vbox.innotek.de/pipermail/vbox-trac/2010-J January/135631.html

rhu
źródło
9

Otrzymujesz aktualny czas systemowy w milisekundach:

final long startTime = System.currentTimeMillis();

Następnie robisz to, co masz zamiar zrobić:

for (int i = 0; i < length; i++) {
  // Do something
}

Następnie widzisz, ile czasu to zajęło:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;
Jonathan Feinberg
źródło
Odpowiedź BalusC jest również poprawna; zależy to od potrzebnej rozdzielczości timera i tego, dlaczego potrzebujesz czasu.
Jonathan Feinberg
9

Możesz skorzystać z System#nanoTime(). Zdobądź to przed i po egzekucji i po prostu zrób matematykę. Jest preferowany powyżej, System#currentTimeMillis()ponieważ ma lepszą precyzję. W zależności od używanego sprzętu i platformy, w przeciwnym razie możesz otrzymać nieprawidłową przerwę w upływającym czasie. Tutaj z Core2Duo w systemie Windows, między około 0 a ~ 15 ms właściwie nie można nic obliczyć.

Bardziej zaawansowanym narzędziem jest profiler .

BalusC
źródło
Licznik czasu w systemie Windows nie ma domyślnie szczególnie dobrej rozdzielczości. Jest to zegar zbyt wysokiej wydajności, ale jest dużo trudniejszy w obsłudze nawet z C i Java nie (AFAIK) zapewniają dostęp do tego niski poziom hackery bez JNI Thunk.
Donal Fellows
1
nanoTime()ma jeden problem (przynajmniej w systemie Windows); sygnatura czasowa jest specyficzna dla rdzenia procesora. Miałem program, który miał ujemny czas wykonania, ponieważ miał znacznik czasu „start” na jednym rdzeniu i znacznik czasu „stop” na innym rdzeniu.
gustafc
3

W przypadku prostych rzeczy może działać System.currentTimeMillis () .

Właściwie jest tak często, że moje IDE jest skonfigurowane tak, że po wpisaniu "t0" generuje mi następujący wiersz:

final long t0 = System.currentTimeMillis()

Ale w przypadku bardziej skomplikowanych rzeczy prawdopodobnie będziesz chciał użyć statystycznych pomiarów czasu, jak tutaj (przewiń w dół i spójrz na wyrażone pomiary czasu, w tym odchylenia standardowe itp.):

http://perf4j.codehaus.org/devguide.html

Składnia T3rr0r
źródło
+1 za wskazanie kodu automatycznego generatora. Cały czas używam podobnego oświadczenia i nie wiedziałem o wstawianiu szablonów kodu. Właśnie dowiedziałem się, jak to zrobić z zaćmieniem i na pewno pomoże!
Jason
Wszystkie usługi Codehaus zostały zakończone. Twój link jest teraz uszkodzony.
naXa
2

Używając AOP / AspectJ i @Loggableadnotacji z jcabi-Aspekty , możesz to zrobić łatwo i kompaktowo:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

Każde wywołanie tej metody będzie wysyłane do narzędzia logowania SLF4J z DEBUGpoziomem logowania. Każdy komunikat dziennika będzie zawierał czas wykonania.

yegor256
źródło
2

Oto kilka sposobów na znalezienie czasu wykonania w Javie:

1) System.nanoTime ()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2) System.currentTimeMillis ()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3) Instant.now ()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

lub

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4) Date.getTime ()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);
SumiSujith
źródło
1

użyj długiego startTime=System.currentTimeMillis()czasu rozpoczęcia, na górze pętli

umieścić long endTime= System.currentTimeMillis();poza końcem pętli. Będziesz musiał odjąć wartości, aby uzyskać czas działania w milisekundach.

Jeśli chcesz mieć czas w nanosekundach, sprawdź System.nanoTime()

Jason
źródło
1

Stworzyłem funkcję wyższego rzędu, która przyjmuje kod, który chcesz zmierzyć w / jako lambdę:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

Nazwij to tak:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

Wynik:

kod 0: 180528 ns
kod 1: 12003 ns

Specjalne podziękowania dla Andy'ego Turnera, który pomógł mi zmniejszyć liczbę zwolnień. Zobacz tutaj .

Willi Mentzel
źródło
0

Możesz także wypróbować Perf4J. Jest to zgrabny sposób robienia tego, czego szukasz, i pomaga w zagregowanych statystykach wydajności, takich jak średnia, minimalna, maksymalna, odchylenie standardowe i liczba transakcji na sekundę w określonym przedziale czasu. Wyciąg z http://perf4j.codehaus.org/devguide.html :

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

Wynik:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
dotrc
źródło
0
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}
luis.espinal
źródło
0

Użycie System.currentTimeMillis () jest właściwym sposobem zrobienia tego. Ale jeśli używasz wiersza poleceń i chcesz w przybliżeniu i szybko ustawić czas dla całego programu, pomyśl o:

time java App

co pozwala nie modyfikować kodu i czasu aplikacji.

MarAja
źródło
Zależy to od sposobu uruchomienia kodu. Jeśli jest to fragment kodu, który uruchamia serwer, dołączasz niepoprawny czas uruchamiania.
Arun Ramakrishnan