Jak określić czas wykonania metody w Javie?

834
  1. Jak uzyskać czas wykonania metody?
  2. Czy istnieje Timerklasa użyteczności dla takich rzeczy, jak czas, ile czasu zajmuje zadanie itp.?

Większość wyszukiwań w Google zwraca wyniki dla liczników, które planują wątki i zadania, czego nie chcę.

Ogre Psalm 33
źródło
JAMon API jest darmowym, prostym, wysokowydajnym, bezpiecznym dla wątków, Java API, który pozwala programistom łatwo monitorować wydajność i skalowalność aplikacji produkcyjnych. JAMon śledzi trafienia, czasy wykonania (całkowite, średnie, minimalne, maksymalne, standardowe std) i inne. http://jamonapi.sourceforge.net/ pobierz: http://sourceforge.net/project/showfiles.php?group_id=96550
Mike Pone
1
Możesz także przyjrzeć się klasie Apache Commons Lang StopWatch . Prosta, ale przydatna klasa użyteczności.
Później podobne pytanie: Jak napisać poprawny mikroprocesor w Javie?
Basil Bourque,
Tak, StopWatch jest do tego świetny.
Shubham Pandey
Java 8 przy użyciu Instantklasy: stackoverflow.com/a/30975902/1216775
akhil_mittal

Odpowiedzi:

1207

Zawsze jest staromodny sposób:

long startTime = System.nanoTime();
methodToTime();
long endTime = System.nanoTime();

long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.
Diastrofizm
źródło
233
w rzeczywistości jest to „nowomodny”, ponieważ użyłeś nanoTime, który został dodany dopiero w java5
John Gardner,
11
To (lub użycie System.currentTimeMillis ()) wydaje się być sposobem, w jaki zwykle robi się to w Javie ... i tak widziałem. Nadal lekko mnie zaskakuje, że nie ma żadnej wbudowanej bzdurnej klasy, takiej jak Timer t = new Timer (); Ciąg s = t.getElapsed (format); itd ...
Ogre Psalm33
18
nanoTime nie gwarantuje dokładności lepszej niż currentTimeMillis (), choć zwykle tak jest. forums.sun.com/thread.jspa?messageID=9460663 i simongbrown.com/blog/2007/08/20/…
James Schek
10
Oczywiście zawsze ważne jest, aby pamiętać o pułapkach mikro-benchmarkingu, takich jak optymalizacje kompilatora / JVM, które mogą zniekształcać wynik = 8-)
Yuval
18
Nie ma potrzeby blokowania w końcu, ponieważ endTime nie będzie używany, jeśli zostanie zgłoszony wyjątek.
Peter Lawrey,
197

Idę z prostą odpowiedzią. Pracuje dla mnie.

long startTime = System.currentTimeMillis();

doReallyLongThing();

long endTime = System.currentTimeMillis();

System.out.println("That took " + (endTime - startTime) + " milliseconds");

Działa całkiem dobrze. Rozdzielczość jest oczywiście tylko z dokładnością do milisekundy, można to zrobić lepiej za pomocą System.nanoTime (). Istnieją pewne ograniczenia obu (wycinki harmonogramu systemu operacyjnego itp.), Ale działa to całkiem dobrze.

Średnia z kilku przebiegów (im więcej, tym lepiej), a otrzymasz porządny pomysł.

MBCook
źródło
51
W rzeczywistości System.currentTimeMillis () ma dokładność powyżej 15 ms. W przypadku naprawdę niskich wartości nie można ufać. Rozwiązaniem tego (jak wspomniano) jest System.nanoTime ();
Steve g
Ok, miałem zamiar zaakceptować to jako oficjalną odpowiedź, dopóki nie przeczytam komentarza Steve'a G. Świetny smakołyk, Steve!
Ogre Psalm33
4
nanoTime () nie gwarantuje dokładności lepszej niż currentTimeMillis, ale wiele implementacji JVM ma lepszą dokładność z nanoTime.
James Schek
5
@JamesSchek Naprawdę musisz uważać na swoje sformułowania, jak już wspomniałem w tym samym komentarzu gdzie indziej; nanoTimegwarantuje, że będzie co najmniej tak samo stanowczy jak currentTimeMillis. docs.oracle.com/javase/7/docs/api/java/lang/…
b1nary.atr0phy
Jedyną niewielką zaletą currentTimeMillisjest to, że jest to rzeczywisty znacznik czasu i może być również używany do rejestrowania czasów rozpoczęcia / zakończenia, podczas gdy nanoTime„może być używany tylko do pomiaru upływającego czasu i nie jest związany z żadnym innym pojęciem czasu systemowego lub zegara ściennego . ”
Brad Parks
177

Dawajcie ludzie! Nikt nie wspominał o sposobie Guawy (co jest prawdopodobnie niesamowite):

import com.google.common.base.Stopwatch;

Stopwatch timer = Stopwatch.createStarted();
//method invocation
LOG.info("Method took: " + timer.stop());

Zaletą jest to, że Stopwatch.toString () wykonuje dobrą robotę, wybierając jednostki czasu do pomiaru. To znaczy, jeśli wartość jest mała, wyniesie 38 ns, jeśli jest długa, pokaże 5m 3s

Jeszcze ładniej:

Stopwatch timer = Stopwatch.createUnstarted();
for (...) {
   timer.start();
   methodToTrackTimeFor();
   timer.stop();
   methodNotToTrackTimeFor();
}
LOG.info("Method took: " + timer);

Uwaga: Google Guava wymaga Java 1.6+

Dmitrij Kałasznikow
źródło
21
Niestety stoper Guava nie jest bezpieczny dla wątków. nauczyłem się tego na własnej skórze.
Dexter Legaspi,
6
@DexterLegaspi Byłbym bardzo zainteresowany twoimi doświadczeniami! Chcesz się podzielić?
Siddhartha,
1
Używanie stopera równolegle doprowadziłoby do start()wielokrotnego dzwonienia z rzędu (tak samo dla stop()).
Mingwei Samuel
141

Używając Instant i Duration z nowego API Java 8,

Instant start = Instant.now();
Thread.sleep(5000);
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

wyjścia,

PT5S
Sufiyan Ghori
źródło
2
Dzięki, jak mogę wydrukować wynik bez posiadania PT z przodu?
java123999,
1
Problem z metodą polega na tym, że Instant nie ma problemu z precyzją w milionach i nanosekundach. Ref: stackoverflow.com/questions/20689055/…
prashantsunkari
8
@ java123999: Możesz zadzwonić Duration.between(start, end).getSeconds(). Durationma również metody konwersji na inne jednostki czasu, np. toMillis()które konwertują na milisekundy.
Emil Lunde
100

Zebraliśmy wszystkie możliwe sposoby razem w jednym miejscu.

Data

Date startDate = Calendar.getInstance().getTime();
long d_StartTime = new Date().getTime();
Thread.sleep(1000 * 4);
Date endDate = Calendar.getInstance().getTime();
long d_endTime = new Date().getTime();
System.out.format("StartDate : %s, EndDate : %s \n", startDate, endDate);
System.out.format("Milli = %s, ( D_Start : %s, D_End : %s ) \n", (d_endTime - d_StartTime),d_StartTime, d_endTime);

System. currentTimeMillis ()

long startTime = System.currentTimeMillis();
Thread.sleep(1000 * 4);
long endTime = System.currentTimeMillis();
long duration = (endTime - startTime);  
System.out.format("Milli = %s, ( S_Start : %s, S_End : %s ) \n", duration, startTime, endTime );
System.out.println("Human-Readable format : "+millisToShortDHMS( duration ) );

Format czytelny dla człowieka

public static String millisToShortDHMS(long duration) {
    String res = "";    // java.util.concurrent.TimeUnit;
    long days       = TimeUnit.MILLISECONDS.toDays(duration);
    long hours      = TimeUnit.MILLISECONDS.toHours(duration) -
                      TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes    = TimeUnit.MILLISECONDS.toMinutes(duration) -
                      TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds    = TimeUnit.MILLISECONDS.toSeconds(duration) -
                      TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    long millis     = TimeUnit.MILLISECONDS.toMillis(duration) - 
                      TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration));

    if (days == 0)      res = String.format("%02d:%02d:%02d.%04d", hours, minutes, seconds, millis);
    else                res = String.format("%dd %02d:%02d:%02d.%04d", days, hours, minutes, seconds, millis);
    return res;
}

Guava: Google Stopwatch JAR «Celem Stopwatch jest pomiar upływającego czasu w nanosekundach.

com.google.common.base.Stopwatch g_SW = Stopwatch.createUnstarted();
g_SW.start();
Thread.sleep(1000 * 4);
g_SW.stop();
System.out.println("Google StopWatch  : "+g_SW);

Apache Commons Lang JAR « StopWatch zapewnia wygodny interfejs API do pomiaru czasu.

org.apache.commons.lang3.time.StopWatch sw = new StopWatch();
sw.start();     
Thread.sleep(1000 * 4);     
sw.stop();
System.out.println("Apache StopWatch  : "+ millisToShortDHMS(sw.getTime()) );

JODA- CZAS

public static void jodaTime() throws InterruptedException, ParseException{
    java.text.SimpleDateFormat ms_SDF = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
    String start = ms_SDF.format( new Date() ); // java.util.Date

    Thread.sleep(10000);

    String end = ms_SDF.format( new Date() );       
    System.out.println("Start:"+start+"\t Stop:"+end);

    Date date_1 = ms_SDF.parse(start);
    Date date_2 = ms_SDF.parse(end);        
    Interval interval = new org.joda.time.Interval( date_1.getTime(), date_2.getTime() );
    Period period = interval.toPeriod(); //org.joda.time.Period

    System.out.format("%dY/%dM/%dD, %02d:%02d:%02d.%04d \n", 
        period.getYears(), period.getMonths(), period.getDays(),
        period.getHours(), period.getMinutes(), period.getSeconds(), period.getMillis());
}

Interfejs API daty i czasu Java z Java 8 «Obiekt Duration reprezentuje okres między dwoma obiektami Instant .

Instant start = java.time.Instant.now();
    Thread.sleep(1000);
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.println( between ); // PT1.001S
System.out.format("%dD, %02d:%02d:%02d.%04d \n", between.toDays(),
        between.toHours(), between.toMinutes(), between.getSeconds(), between.toMillis()); // 0D, 00:00:01.1001 

Spring Framework zapewniaklasę narzędzia StopWatch do pomiaru upływu czasu w Javie.

StopWatch sw = new org.springframework.util.StopWatch();
sw.start("Method-1"); // Start a named task
    Thread.sleep(500);
sw.stop();

sw.start("Method-2");
    Thread.sleep(300);
sw.stop();

sw.start("Method-3");
    Thread.sleep(200);
sw.stop();

System.out.println("Total time in milliseconds for all tasks :\n"+sw.getTotalTimeMillis());
System.out.println("Table describing all tasks performed :\n"+sw.prettyPrint());

System.out.format("Time taken by the last task : [%s]:[%d]", 
        sw.getLastTaskName(),sw.getLastTaskTimeMillis());

System.out.println("\n Array of the data for tasks performed « Task Name: Time Taken");
TaskInfo[] listofTasks = sw.getTaskInfo();
for (TaskInfo task : listofTasks) {
    System.out.format("[%s]:[%d]\n", 
            task.getTaskName(), task.getTimeMillis());
}

Wynik:

Total time in milliseconds for all tasks :
999
Table describing all tasks performed :
StopWatch '': running time (millis) = 999
-----------------------------------------
ms     %     Task name
-----------------------------------------
00500  050%  Method-1
00299  030%  Method-2
00200  020%  Method-3

Time taken by the last task : [Method-3]:[200]
 Array of the data for tasks performed « Task Name: Time Taken
[Method-1]:[500]
[Method-2]:[299]
[Method-3]:[200]
Yash
źródło
Stoper Guava, Apache Commons i Spring Framework nie są bezpieczne dla wątków. Nie jest bezpieczny do użytku produkcyjnego.
Deepak Puthraya
@DeepakPuthraya, to z której biblioteki korzystać, która jest bezpieczna do użytku produkcyjnego?
gaurav
1
@DeepakPuthraya można korzystać z interfejsu API Java Time Time API pod warunkiem java 8. Co jest proste.
Yash
IMO post ten skorzystałby, gdyby każde rozwiązanie pokazywało również wyniki działania systemu.
BAERUS
87

Użyj profilera (JProfiler, Netbeans Profiler, Visual VM, Eclipse Profiler itp.). Otrzymasz najdokładniejsze wyniki i jest najmniej ingerujący. Korzystają z wbudowanego mechanizmu JVM do profilowania, który może również dostarczyć dodatkowych informacji, takich jak ślady stosu, ścieżki wykonania i, w razie potrzeby, bardziej wyczerpujące wyniki.

Podczas korzystania z w pełni zintegrowanego profilera profilowanie metody jest banalnie proste. Kliknij prawym przyciskiem myszy, Profiler -> Dodaj do metod rootowania. Następnie uruchom profiler tak samo, jak robiłeś test lub debugger.

James Schek
źródło
To także była świetna sugestia i jeden z tych momentów żarówek, kiedy czytam tę odpowiedź. Nasz projekt korzysta z JDeveloper, ale sprawdziłem i na pewno ma on wbudowany profiler!
Ogre Psalm33
2
Od wersji java 7 kompilacja 40 (myślę, że) obejmowały dawny rejestrator lotów JRockits do wersji java (poszukiwanie Java Mission Control)
Niels Bech Nielsen
Na pewno @NielsBechNielsen! oracle.com/technetwork/java/javaseproducts/mission-control/…
Ogre Psalm33
Jak na przykład uzyskać wykonanie metody w Javie przez Visual VM?
okwap
41

Prawdopodobnie nie chciałem tego powiedzieć, ale jest to dobre wykorzystanie AOP. Uderz przechwytywacz proxy wokół swojej metody i dokonaj pomiaru czasu.

Co, dlaczego i jak AOP jest raczej poza zakresem tej odpowiedzi, niestety, ale tak właśnie to zrobiłbym.

Edycja: Oto link do Spring AOP, aby zacząć, jeśli chcesz. Jest to najbardziej dostępna implementacja AOP, którą Iive spotkało w Javie.

Ponadto, biorąc pod uwagę bardzo proste sugestie wszystkich innych, powinienem dodać, że AOP jest na wypadek, gdy nie chcesz, aby inwazja kodu miała czas. Ale w wielu przypadkach takie proste i łatwe podejście jest w porządku.

skaffman
źródło
3
Oto samouczek, jak to zrobić w Spring: veerasundar.com/blog/2010/01/…
David Tinker
39

System.currentTimeMillis();NIE JEST dobrym podejściem do pomiaru wydajności twoich algorytmów. Mierzy całkowity czas spędzany przez użytkownika podczas oglądania ekranu komputera. Obejmuje to również czas zużywany przez wszystko inne uruchomione na komputerze w tle. Może to mieć ogromną różnicę, jeśli na stacji roboczej działa wiele programów.

Prawidłowe podejście polega na użyciu java.lang.managementpakietu.

Ze strony http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking :

  • „Czas użytkownika” to czas poświęcony na uruchomienie własnego kodu aplikacji.
  • „Czas systemowy” to czas spędzony na uruchomieniu kodu systemu operacyjnego w imieniu aplikacji (np. We / wy).

getCpuTime() metoda daje sumę tych:

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

public class CPUUtils {

    /** Get CPU time in nanoseconds. */
    public static long getCpuTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadCpuTime( ) : 0L;
    }

    /** Get user time in nanoseconds. */
    public static long getUserTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            bean.getCurrentThreadUserTime( ) : 0L;
    }

    /** Get system time in nanoseconds. */
    public static long getSystemTime( ) {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
        return bean.isCurrentThreadCpuTimeSupported( ) ?
            (bean.getCurrentThreadCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L;
    }

}
TondaCZE
źródło
4
To zdecydowanie dobra uwaga, że ​​„czas użytkownika” (czas zegara ściennego) nie zawsze jest doskonałą miarą wydajności, szczególnie w programie wielowątkowym.
Ogre Psalm33
Oto odpowiedź, której szukam.
ZhaoGang,
30

W Javie 8 możesz zrobić coś takiego za pomocą każdej normalnej metody :

Object returnValue = TimeIt.printTime(() -> methodeWithReturnValue());
//do stuff with your returnValue

z TimeIt lubi:

public class TimeIt {

public static <T> T printTime(Callable<T> task) {
    T call = null;
    try {
        long startTime = System.currentTimeMillis();
        call = task.call();
        System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s");
    } catch (Exception e) {
        //...
    }
    return call;
}
}

Dzięki tej metodzie możesz łatwo dokonywać pomiaru czasu w dowolnym miejscu kodu, nie przerywając go. W tym prostym przykładzie po prostu wydrukowałem czas. Możesz dodać Switch for TimeIt, np. Aby wydrukować czas tylko w trybie debugowania lub coś takiego.

Jeśli pracujesz z funkcją , możesz zrobić coś takiego:

Function<Integer, Integer> yourFunction= (n) -> {
        return IntStream.range(0, n).reduce(0, (a, b) -> a + b);
    };

Integer returnValue = TimeIt.printTime2(yourFunction).apply(10000);
//do stuff with your returnValue

public static <T, R> Function<T, R> printTime2(Function<T, R> task) {
    return (t) -> {
        long startTime = System.currentTimeMillis();
        R apply = task.apply(t);
        System.out.print((System.currentTimeMillis() - startTime) / 1000d
                + "s");
        return apply;
    };
}
Stefan
źródło
Wygląda to znacznie lepiej niż inne rozwiązania. Jest bliżej Spring AOP, a jednocześnie lżejszy. True Java 8 sposób! +1 dzięki!
Amit Kumar,
Być może wygląda to dobrze, ponieważ Stefan używa fantazyjnych nowych funkcji Java. Ale myślę, że igłowanie jest trudne do odczytania i zrozumienia.
Stimpson Cat
18

Możemy również użyć klasy wspólnych apache StopWatch do pomiaru czasu.

Przykładowy kod

org.apache.commons.lang.time.StopWatch sw = new org.apache.commons.lang.time.StopWatch();

System.out.println("getEventFilterTreeData :: Start Time : " + sw.getTime());
sw.start();

// Method execution code

sw.stop();
System.out.println("getEventFilterTreeData :: End Time : " + sw.getTime());
Narayan
źródło
15

Mały zwrot akcji, jeśli nie używasz narzędzi i chcesz mierzyć czas metodami o niskim czasie wykonania: wykonaj go wiele razy, za każdym razem podwajając liczbę wykonań aż do sekundy lub mniej więcej. Tak więc czas wywołania System.nanoTime i tak dalej, ani dokładność System.nanoTime nie wpływa znacząco na wynik.

    int runs = 0, runsPerRound = 10;
    long begin = System.nanoTime(), end;
    do {
        for (int i=0; i<runsPerRound; ++i) timedMethod();
        end = System.nanoTime();
        runs += runsPerRound;
        runsPerRound *= 2;
    } while (runs < Integer.MAX_VALUE / 2 && 1000000000L > end - begin);
    System.out.println("Time for timedMethod() is " + 
        0.000000001 * (end-begin) / runs + " seconds");

Oczywiście mają zastosowanie zastrzeżenia dotyczące korzystania z zegara ściennego: wpływy kompilacji JIT, wiele wątków / procesów itp. Dlatego najpierw musisz wykonać tę metodę wiele razy, aby kompilator JIT działał, a następnie powtórz ten test wiele razy i weź najkrótszy czas wykonania.

Hans-Peter Störr
źródło
13

W tym celu używamy adnotacji AspectJ i Java. Jeśli potrzebujemy znać czas wykonania metody, po prostu ją opatrzymy adnotacją. Bardziej zaawansowana wersja może korzystać z własnego poziomu dziennika, który można włączać i wyłączać w czasie wykonywania.

public @interface Trace {
  boolean showParameters();
}

@Aspect
public class TraceAspect {
  [...]
  @Around("tracePointcut() && @annotation(trace) && !within(TraceAspect)")
  public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) {

    Object result;
    // initilize timer

    try { 
      result = jp.procced();
    } finally { 
      // calculate execution time 
    }

    return result;
  }
  [...]
}

źródło
11

Naprawdę dobry kod.

http://www.rgagnon.com/javadetails/java-0585.html

import java.util.concurrent.TimeUnit;

long startTime = System.currentTimeMillis();
........
........
........
long finishTime = System.currentTimeMillis();

String diff = millisToShortDHMS(finishTime - startTime);


  /**
   * converts time (in milliseconds) to human-readable format
   *  "<dd:>hh:mm:ss"
   */
  public static String millisToShortDHMS(long duration) {
    String res = "";
    long days  = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration)
                   - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration)
                     - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration)
                   - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
    if (days == 0) {
      res = String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }
    else {
      res = String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
    }
    return res;
  }
góra lodowa
źródło
3
W rzeczywistości chodziło o to, jak obliczyć czas potrzebny na metodę, a nie jak ją sformatować. To pytanie jest jednak dość stare (prawie cztery lata!). Staraj się unikać wskrzeszania starych wątków, chyba że odpowiedź doda coś nowego i znaczącego w stosunku do istniejących odpowiedzi.
Leigh,
1
I aby dodać pozostałe milis na końcu, wprowadź następujące zmiany: long millis = TimeUnit.MILLISECONDS.toMillis(duration) - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); if (days == 0) { res = String.format("%02d:%02d:%02d.%02d", hours, minutes, seconds, millis); } else { res = String.format("%dd%02d:%02d:%02d.%02d", days, hours, minutes, seconds, millis); }
Rick Barkhouse
10

Możesz użyć Perf4j . Bardzo fajne narzędzie. Użycie jest proste

String watchTag = "target.SomeMethod";
StopWatch stopWatch = new LoggingStopWatch(watchTag);
Result result = null; // Result is a type of a return value of a method
try {
    result = target.SomeMethod();
    stopWatch.stop(watchTag + ".success");
} catch (Exception e) {
    stopWatch.stop(watchTag + ".fail", "Exception was " + e);
    throw e; 
}

Więcej informacji można znaleźć w Przewodniku dla programistów

Edycja: Projekt wydaje się martwy

scalenchik
źródło
1
Perf4j może również generować ładne statystyki .
Paaske
8
new Timer(""){{
    // code to time 
}}.timeMe();



public class Timer {

    private final String timerName;
    private long started;

    public Timer(String timerName) {
        this.timerName = timerName;
        this.started = System.currentTimeMillis();
    }

    public void timeMe() {
        System.out.println(
        String.format("Execution of '%s' takes %dms.", 
                timerName, 
                started-System.currentTimeMillis()));
    }

}
Maciek Kreft
źródło
1
Rzuć własną prostą klasą to dobry wybór, jeśli masz już skonfigurowany system kompilacji i zależny OTS, i nie chcesz zawracać sobie głowy pobieraniem innego pakietu OTS, który zawiera klasę timera użytkowego.
Ogre Psalm33
7

Zasadniczo robię różne warianty tego, ale biorąc pod uwagę, jak działa kompilacja hotspotów, jeśli chcesz uzyskać dokładne wyniki, musisz wyrzucić kilka pierwszych pomiarów i upewnić się, że używasz tej metody w rzeczywistej aplikacji (czytaj specyficznej dla aplikacji).

Jeśli JIT zdecyduje się go skompilować, twoje liczby będą się znacznie różnić. więc po prostu bądź świadomy

Łukasz
źródło
7

Używając AOP / AspectJ i @Loggableadnotacji z aspektów jcabi , 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 funkcji rejestrowania SLF4J z DEBUGpoziomem rejestrowania. I każdy komunikat dziennika będzie zawierał czas wykonania.

yegor256
źródło
7

Spring udostępnia klasę narzędziową org.springframework.util.StopWatch , zgodnie z JavaDoc:

Prosty stoper, pozwalający na określenie czasu szeregu zadań, odsłaniający całkowity czas działania i czas wykonywania każdego nazwanego zadania.

Stosowanie:

StopWatch stopWatch = new StopWatch("Performance Test Result");

stopWatch.start("Method 1");
doSomething1();//method to test
stopWatch.stop();

stopWatch.start("Method 2");
doSomething2();//method to test
stopWatch.stop();

System.out.println(stopWatch.prettyPrint());

Wynik:

StopWatch 'Performance Test Result': running time (millis) = 12829
-----------------------------------------
ms     %     Task name
-----------------------------------------
11907  036%  Method 1
00922  064%  Method 2

Z aspektami:

@Around("execution(* my.package..*.*(..))")
public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    Object retVal = joinPoint.proceed();
    stopWatch.stop();
    log.info(" execution time: " + stopWatch.getTotalTimeMillis() + " ms");
    return retVal;
}
Sunil Manheri
źródło
Czy można tego używać z AspectJ?
zygimantus,
7

Napisałem metodę drukowania czasu wykonania metody w bardzo czytelnej formie. Na przykład, aby obliczyć silnię 1 milion, zajmuje to około 9 minut. Czas wykonania zostanie wydrukowany jako:

Execution Time: 9 Minutes, 36 Seconds, 237 MicroSeconds, 806193 NanoSeconds

Kod jest tutaj:

public class series
{
    public static void main(String[] args)
    {
        long startTime = System.nanoTime();

        long n = 10_00_000;
        printFactorial(n);

        long endTime = System.nanoTime();
        printExecutionTime(startTime, endTime);

    }

    public static void printExecutionTime(long startTime, long endTime)
    {
        long time_ns = endTime - startTime;
        long time_ms = TimeUnit.NANOSECONDS.toMillis(time_ns);
        long time_sec = TimeUnit.NANOSECONDS.toSeconds(time_ns);
        long time_min = TimeUnit.NANOSECONDS.toMinutes(time_ns);
        long time_hour = TimeUnit.NANOSECONDS.toHours(time_ns);

        System.out.print("\nExecution Time: ");
        if(time_hour > 0)
            System.out.print(time_hour + " Hours, ");
        if(time_min > 0)
            System.out.print(time_min % 60 + " Minutes, ");
        if(time_sec > 0)
            System.out.print(time_sec % 60 + " Seconds, ");
        if(time_ms > 0)
            System.out.print(time_ms % 1E+3 + " MicroSeconds, ");
        if(time_ns > 0)
            System.out.print(time_ns % 1E+6 + " NanoSeconds");
    }
}
Pratik Patil
źródło
6

Można to zrobić na kilka sposobów. Zwykle wracam do korzystania z czegoś takiego:

long start = System.currentTimeMillis();
// ... do something ...
long end = System.currentTimeMillis();

lub to samo z System.nanoTime ();

Wydaje się, że istnieje coś więcej po stronie testów porównawczych: http://jetm.void.fm/ Nigdy tego nie próbowałem.

Horst Gutmann
źródło
6

Możesz użyć biblioteki Metrics, która zawiera różne przyrządy pomiarowe. Dodaj zależność:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-core</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

I skonfiguruj go dla swojego środowiska.

Metody można opatrywać adnotacjami @Timed :

@Timed
public void exampleMethod(){
    // some code
}

lub fragment kodu zawinięty w Timer :

final Timer timer = metricsRegistry.timer("some_name");
final Timer.Context context = timer.time();
// timed code
context.stop();

Zagregowane dane można wyeksportować do konsoli, JMX, CSV lub innych.

@Timed przykładowy wynik pomiaru:

com.example.ExampleService.exampleMethod
             count = 2
         mean rate = 3.11 calls/minute
     1-minute rate = 0.96 calls/minute
     5-minute rate = 0.20 calls/minute
    15-minute rate = 0.07 calls/minute
               min = 17.01 milliseconds
               max = 1006.68 milliseconds
              mean = 511.84 milliseconds
            stddev = 699.80 milliseconds
            median = 511.84 milliseconds
              75% <= 1006.68 milliseconds
              95% <= 1006.68 milliseconds
              98% <= 1006.68 milliseconds
              99% <= 1006.68 milliseconds
            99.9% <= 1006.68 milliseconds
Tak jak
źródło
5

Jeśli chcesz czas naścienny

long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;
David Nehme
źródło
5

Jak powiedział „skaffman”, użyj AOP LUB możesz użyć tkania kodu bajtowego w czasie wykonywania, tak jak narzędzia do pokrywania metod testów jednostkowych używają do przezroczystego dodawania informacji o czasie do wywoływanych metod.

Możesz spojrzeć na kod używany przez narzędzia narzędzi open source, takie jak Emma ( http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0 ). Drugim narzędziem pokrycia OpenSource jest http://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download .

Jeśli w końcu uda ci się zrobić to, co zaplanowałeś, proszę. udostępnij go społeczności tutaj ze swoim zadaniem / słoikami na mrówki.

anjanb
źródło
4
long startTime = System.currentTimeMillis();
// code goes here
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime; // elapsed time in milliseconds
Ryan Rodemoyer
źródło
4

Zmodyfikowałem kod z poprawnej odpowiedzi, aby uzyskać wynik w kilka sekund:

long startTime = System.nanoTime();

methodCode ...

long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / (Math.pow(10, 9));
Log.v(TAG, "MethodName time (s) = " + duration);
Denis Kutlubaev
źródło
4

Możesz użyć klasy stopera z wiosennego projektu rdzenia:

Kod:

StopWatch stopWatch = new StopWatch()
stopWatch.start();  //start stopwatch
// write your function or line of code.
stopWatch.stop();  //stop stopwatch
stopWatch.getTotalTimeMillis() ; ///get total time

Dokumentacja dla stopera: Prosty stoper, pozwalający na określenie czasu szeregu zadań, odsłaniający całkowity czas działania i czas wykonywania każdego nazwanego zadania. Ukrywa użycie System.currentTimeMillis (), poprawiając czytelność kodu aplikacji i zmniejszając prawdopodobieństwo błędów obliczeniowych. Zauważ, że ten obiekt nie został zaprojektowany jako bezpieczny dla wątków i nie używa synchronizacji. Ta klasa jest zwykle używana do sprawdzania wydajności podczas weryfikacji koncepcji i rozwoju, a nie jako część aplikacji produkcyjnych.

praveen jain
źródło
3

Możesz spróbować w ten sposób, jeśli chcesz znać czas.

long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));    
gifpif
źródło
3

Ok, to jest prosta klasa, której można użyć do prostego pomiaru czasu twoich funkcji. Poniżej znajduje się przykład.

public class Stopwatch {
    static long startTime;
    static long splitTime;
    static long endTime;

    public Stopwatch() {
        start();
    }

    public void start() {
        startTime = System.currentTimeMillis();
        splitTime = System.currentTimeMillis();
        endTime = System.currentTimeMillis();
    }

    public void split() {
        split("");
    }

    public void split(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Split time for [" + tag + "]: " + (endTime - splitTime) + " ms");
        splitTime = endTime;
    }

    public void end() {
        end("");
    }
    public void end(String tag) {
        endTime = System.currentTimeMillis();
        System.out.println("Final time for [" + tag + "]: " + (endTime - startTime) + " ms");
    }
}

Przykład zastosowania:

public static Schedule getSchedule(Activity activity_context) {
        String scheduleJson = null;
        Schedule schedule = null;
/*->*/  Stopwatch stopwatch = new Stopwatch();

        InputStream scheduleJsonInputStream = activity_context.getResources().openRawResource(R.raw.skating_times);
/*->*/  stopwatch.split("open raw resource");

        scheduleJson = FileToString.convertStreamToString(scheduleJsonInputStream);
/*->*/  stopwatch.split("file to string");

        schedule = new Gson().fromJson(scheduleJson, Schedule.class);
/*->*/  stopwatch.split("parse Json");
/*->*/  stopwatch.end("Method getSchedule"); 
    return schedule;
}

Próbka wyjścia konsoli:

Split time for [file to string]: 672 ms
Split time for [parse Json]: 893 ms
Final time for [get Schedule]: 1565 ms
msysmilu
źródło
3

W Javie 8 wprowadzono nową klasę o nazwie Instant. Zgodnie z dokumentem:

Natychmiastowe oznacza początek nanosekundy na linii czasu. Ta klasa jest przydatna do generowania znacznika czasu reprezentującego czas maszyny. Zasięg chwili wymaga przechowywania liczby większej niż długa. Aby to osiągnąć, klasa przechowuje długą reprezentującą sekundę epoki i liczbę wewnętrzną reprezentującą nanosekundę sekundy, która zawsze będzie wynosić od 0 do 999,999,999. Epoki sekund są mierzone od standardowej epoki Java z lat 1970-01-01T00: 00: 00Z, gdzie chwile po epoce mają wartości dodatnie, a wcześniejsze chwile mają wartości ujemne. Zarówno w przypadku części drugiej, jak i nanosekundowych, większa wartość jest zawsze później na osi czasu niż mniejsza wartość.

Może to być użyte jako:

Instant start = Instant.now();
try {
    Thread.sleep(7000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end));

Drukuje PT7.001S.

akhil_mittal
źródło