Как определить время выполнения метода в Java?

  1. Как узнать время выполнения метода?
  2. Есть ли служебный класс Timer для таких вещей, как определение времени выполнения задачи и т. Д.?

Большинство поисковых запросов в Google возвращают результаты для таймеров, которые планируют потоки и задачи, что мне не нужно.


person Ogre Psalm33    schedule 07.10.2008    source источник
comment
JAMon API - это бесплатный, простой, высокопроизводительный, потокобезопасный Java API, который позволяет разработчикам легко контролировать производительность и масштабируемость производственных приложений. JAMon отслеживает совпадения, время выполнения (общее, среднее, минимальное, максимальное, стандартное отклонение) и многое другое. http://jamonapi.sourceforge.net/ скачать: http://sourceforge.net/project/showfiles.php?group_id=96550   -  person Mike Pone    schedule 08.10.2008
comment
Вы также можете посмотреть ссылку Класс Apache Commons Lang StopWatch. Простой, но полезный служебный класс.   -  person    schedule 05.05.2009
comment
Позже аналогичный вопрос: Как мне написать правильный микротест на Java?   -  person Basil Bourque    schedule 02.07.2016
comment
Да, секундомер отлично подходит для этого.   -  person Shubham Pandey    schedule 01.08.2019
comment
Java 8 с использованием класса Instant: stackoverflow.com/a/30975902/1216775   -  person akhil_mittal    schedule 01.08.2019


Ответы (39)


Всегда есть старомодный способ:

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

long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.
person Diastrophism    schedule 07.10.2008
comment
на самом деле, это по-новому, потому что вы использовали nanoTime, который не был добавлен до java5 - person John Gardner; 08.10.2008
comment
Это (или использование System.currentTimeMillis ()) похоже на то, как это обычно делается в Java ... что я все равно видел. Меня все еще слегка удивляет, что нет удобного встроенного класса, такого как Timer t = new Timer (); Строка s = t.getElapsed (формат); так далее... - person Ogre Psalm33; 08.10.2008
comment
nanoTime не гарантирует лучшей точности, чем currentTimeMillis (), хотя обычно это так. forum.sun.com/thread.jspa?messageID=9460663 и simongbrown.com/blog/2007/08/20/ - person James Schek; 08.10.2008
comment
Конечно, всегда важно помнить о подводных камнях микротестирования, таких как оптимизация компилятора / JVM, которая может исказить результат = 8-) - person Yuval; 07.01.2009
comment
В блоке finally нет необходимости, так как endTime не будет использоваться при возникновении исключения. - person Peter Lawrey; 05.05.2009
comment
Из javadoc для System.currentTimeMillis () ... многие операционные системы измеряют время в единицах десятков миллисекунд. И это правда, в моем окне с Windows это примерно 16 мс. Помните, что там два часа. Поэтому никогда не используйте currentTimeMillis для измерения прошедшего времени. Если вам нужны миллисекунды, просто разделите результат на 1 миллион. - person James Scriven; 25.05.2011
comment
если между временем начала и окончания поток был приостановлен, время окончания фактически также будет отражать время приостановки. поэтому конечным началом не будет фактическое время, потраченное Thread на выполнение. - person Java Spring Coder; 26.03.2013
comment
Хорошо, это хорошо. Но как ОБЪЕДИНИТЬ ТЕСТИРОВАНИЕ этого поведения? т.е. я хочу подтвердить, что метод возвращает время выполнения, которое является разницей между endTime и startTime. - person Adelin; 10.05.2013
comment
@JamesSchek Будьте осторожны со своими формулировками, nanoTime гарантированно будет не менее решительным, чем currentTimeMillis. docs.oracle.com/ javase / 7 / docs / api / java / lang / - person b1nary.atr0phy; 18.05.2013
comment
@ OgrePsalm33 В Java 7 есть класс Timer, но он используется для планирования задач. - person Chthonic Project; 24.07.2013
comment
@ChthonicProject Ну конечно. В моем примере имя класса было просто фиктивным представлением. - person Ogre Psalm33; 25.07.2013
comment
Этот ответ не совсем правильный, проверьте мой ответ, если вы ищете время, затрачиваемое только на ваше приложение. - person TondaCZE; 06.04.2014
comment
Пожалуйста, обратитесь к этому ответу stackoverflow.com/a/3383047/870547, чтобы сделать это на Java 8. - person Kay Gee; 05.12.2014
comment
Это секундомер, который я сделал, он позволяет статически добавлять именованные таймеры. Его очень просто использовать, см. Класс DocBlock. gist.github.com/juanmf/4147a9b7010c7b04c003, который вы хотите поместить в свой пакет утилит. - person juanmf; 09.11.2015
comment
Следует отметить, что System.currentTimeMillis() возвращает то, что ОС считает временем, прошедшим с эпохи Unix. Если ваш пользователь (или сама ОС) изменит время ОС между вызовами на System.currentTimeMillis(), вы можете получить странные результаты. nanoTime не зависит от изменений часов ОС, поэтому он более надежен. - person daiscog; 02.06.2016
comment
Мне пришлось преобразовать endTime в double при делении на 1000000000 (миллиард), чтобы получить секунды: double duration = ((double)endTime - startTime) / 1000000000; - person Sam Malayek; 23.07.2018
comment
позаботьтесь об асинхронных методах с этим, так как вам понадобится интерфейс, чтобы знать, когда эти методы закончатся - person Gastón Saillén; 25.09.2018
comment
также имейте в виду, что число, которое вы получите, немного зависит от времени, необходимого для выполнения вызовов для получения отметок времени. - person jwenting; 01.10.2018
comment
В качестве улучшения лучшим способом извлечения количества пройденных миллисекунд будет следующий: double time = (endTime - startTime) * 1e-6; Он краток, быстрее, чем деление, однозначен в отношении количества десятичных знаков и неявно приведен к двойному с помощью литерала 1e-6 (см. stackoverflow.com/questions/ 15527198 /) - person JJ Brown; 10.12.2018
comment
@JohnGardner Теперь это старомодно. :) - person Kröw; 18.05.2019
comment
@ Kröw был уверен, что это так. старое-старое-новое сейчас? - person John Gardner; 23.05.2019
comment
@JamesSchek В каких ситуациях это могло пойти не так? Вы только заявляете, что это может пойти не так, а затем публикуете 2 неработающие ссылки - person Ferrybig; 01.07.2019

Я согласен с простым ответом. Работает для меня.

long startTime = System.currentTimeMillis();

doReallyLongThing();

long endTime = System.currentTimeMillis();

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

Работает неплохо. Разрешение, очевидно, составляет всего миллисекунды, вы можете добиться большего с помощью System.nanoTime (). Для обоих есть некоторые ограничения (срезы расписания операционной системы и т. Д.), Но это работает довольно хорошо.

Среднее значение за пару прогонов (чем больше, тем лучше), и вы получите неплохое представление.

person MBCook    schedule 07.10.2008
comment
На самом деле System.currentTimeMillis () точен только выше 15 мс. При действительно низких значениях этому нельзя доверять. Решением для этого (как уже упоминалось) является System.nanoTime (); - person Steve g; 08.10.2008
comment
Хорошо, я собирался принять это как официальный ответ, пока не прочитал комментарий Стива Дж. Отличный лакомый кусочек, Стив! - person Ogre Psalm33; 08.10.2008
comment
nanoTime () не гарантирует точности лучше, чем currentTimeMillis, но многие реализации JVM действительно имеют лучшую точность с nanoTime. - person James Schek; 08.10.2008
comment
@JamesSchek Вам действительно нужно следить за своей формулировкой, как я уже упоминал в этом идентичном комментарии в другом месте; nanoTime гарантированно будет не менее решительным, чем currentTimeMillis. docs.oracle.com/ javase / 7 / docs / api / java / lang / - person b1nary.atr0phy; 18.05.2013
comment
Одно небольшое преимущество currentTimeMillis заключается в том, что это фактическая временная метка, и ее можно также использовать для регистрации времени начала / окончания, в то время как nanoTime может использоваться только для измерения прошедшего времени и не имеет отношения к какому-либо другому понятию системы или настенных часов. время. - person Brad Parks; 28.11.2016

Давайте, ребята! Никто не упомянул способ сделать это с помощью Guava (который, возможно, великолепен):

import com.google.common.base.Stopwatch;

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

Приятно то, что Stopwatch.toString () хорошо справляется с выбором единиц времени для измерения. Т.е. если значение маленькое, будет выдано 38 нс, если оно длинное, будет отображаться 5 м 3 с

Еще приятнее:

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

Примечание. Google Guava требует Java 1.6+

person Dmitry Kalashnikov    schedule 13.03.2013
comment
К сожалению, секундомер Guava не является потокобезопасным. Я усвоил это на собственном горьком опыте. - person Dexter Legaspi; 15.12.2014
comment
@DexterLegaspi Был бы очень заинтересован в вашем опыте! Заботиться, чтобы поделиться? - person Siddhartha; 19.01.2015
comment
Параллельное использование секундомера приведет к тому, что вы вызовете start() несколько раз подряд (то же самое для stop()). - person Mingwei Samuel; 16.08.2019

Используя Instant и Duration из нового API Java 8,

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

выходы,

PT5S
person Sufiyan Ghori    schedule 02.02.2015
comment
Спасибо, как я могу вывести результат, не имея ПТ впереди? - person java123999; 16.03.2016
comment
Проблема с методом заключается в том, что Instant не нарушает точность в миллисекундах и наносекундах. Ссылка: stackoverflow.com/questions / 20689055 / - person prashantsunkari; 13.04.2017
comment
@ java123999: Вы можете позвонить Duration.between(start, end).getSeconds(). Duration также имеет методы для преобразования в другие единицы времени, например toMillis(), который преобразуется в миллисекунды. - person Emil Lunde; 29.05.2018

Собрали все возможные пути в одном месте.

Дата

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 ) );

Удобочитаемый формат

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;
}

Гуава: Google Секундомер JAR« Секундомер измеряет прошедшее время в наносекундах.

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 предоставляет удобный API для определения времени.

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 -TIME

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());
}

API даты и времени Java из Java 8 «Продолжительность представляет собой период времени между двумя 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 предоставляет StopWatch служебный класс для измерения прошедшего времени в Java.

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());
}

Выход:

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]
person Yash    schedule 04.12.2015
comment
Секундомер Guava, Apache Commons и Spring Framework не являются потокобезопасными. Небезопасно для производственного использования. - person Deepak Puthraya; 12.06.2018
comment
@DeepakPuthraya, тогда какую библиотеку использовать, которая безопасна для производственного использования? - person Gaurav; 24.09.2019
comment
@DeepakPuthraya, вы можете использовать Java 8, предоставленный API времени Java. Это просто. - person Yash; 24.09.2019
comment
ИМО, этот пост выиграл бы, если бы каждое решение также показывало вывод системных выходов. - person BAERUS; 28.04.2020

Используйте профилировщик (JProfiler, Netbeans Profiler, Visual VM, Eclipse Profiler и т. Д.). Вы получите наиболее точные результаты и наименее навязчивые. Они используют встроенный механизм JVM для профилирования, который также может предоставить вам дополнительную информацию, такую ​​как трассировки стека, пути выполнения и, при необходимости, более подробные результаты.

При использовании полностью интегрированного профилировщика профилировать метод очень просто. Щелкните правой кнопкой мыши, Профилировщик -> Добавить к корневым методам. Затем запустите профилировщик, как если бы вы выполняли тестовый запуск или отладчик.

person James Schek    schedule 07.10.2008
comment
Это также было отличным предложением и одним из тех моментов, когда я прочитал этот ответ. В нашем проекте используется JDeveloper, но я проверил, и, конечно же, у него есть встроенный профилировщик! - person Ogre Psalm33; 08.10.2008
comment
Из java 7 build 40 (я думаю) они включили бывший JRockits Flight Recorder в java (поиск Java Mission Control) - person Niels Bech Nielsen; 17.03.2014
comment
Конечно же, @NielsBechNielsen! oracle.com/technetwork/java/ javaseproducts / mission-control / - person Ogre Psalm33; 07.07.2014
comment
Как, например, получить выполнение метода на Java с помощью Visual VM? - person petertc; 13.11.2014

System.currentTimeMillis(); НЕ ЯВЛЯЕТСЯ хорошим подходом для измерения производительности ваших алгоритмов. Он измеряет общее время, в течение которого вы наблюдаете за экраном компьютера. Сюда также входит время, затрачиваемое на все остальное, работающее на вашем компьютере в фоновом режиме. Это может иметь огромное значение, если на вашей рабочей станции работает много программ.

Правильный подход - использование пакета java.lang.management.

С http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking):

  • «Пользовательское время» - это время, потраченное на выполнение собственного кода вашего приложения.
  • «Системное время» - это время, затрачиваемое на выполнение кода ОС от имени вашего приложения (например, для ввода-вывода).

getCpuTime() метод дает вам сумму из них:

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;
    }

}
person TondaCZE    schedule 06.04.2014
comment
Это определенно хороший момент, поскольку время пользователя (время настенных часов) не всегда является отличным показателем производительности, особенно в многопоточной программе. - person Ogre Psalm33; 07.04.2014
comment
Это ответ, который я ищу. - person ZhaoGang; 06.01.2020

Вероятно, это не то, что вы хотели, чтобы я сказал, но это хорошее применение АОП. Оберните прокси-перехватчик вокруг своего метода и отсчитайте время.

К сожалению, вопрос о том, что, почему и как АОП выходит за рамки этого ответа, но я бы сделал это так.

Изменить: Вот ссылка на Spring AOP, чтобы вы начал, если вам интересно. Это наиболее доступная реализация АОП, которую Iive встречал для java.

Кроме того, учитывая очень простые предложения всех остальных, я должен добавить, что АОП предназначен для случаев, когда вы не хотите, чтобы такие вещи, как время, вторгались в ваш код. Но во многих случаях такой простой и легкий подход подходит.

person skaffman    schedule 07.10.2008
comment
Вот руководство о том, как это сделать с помощью Spring: veerasundar.com/blog/2010/01/ - person David Tinker; 04.01.2011

В Java 8 вы также можете делать что-то подобное со всеми обычными методами:

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

с TimeIt нравится:

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;
}
}

С помощью этого метода вы можете легко измерить время в любом месте вашего кода, не нарушая его. В этом простом примере я просто печатаю время. Можете ли вы добавить переключатель для TimeIt, например только напечатать время в DebugMode или что-то в этом роде.

Если вы работаете с функцией, вы можете сделать что-то вроде этого:

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;
    };
}
person Stefan    schedule 25.11.2015
comment
Это выглядит намного лучше, чем другие решения. Это ближе к Spring AOP, но легче. Правда java 8 способ! +1 Спасибо! - person Amit Kumar; 05.12.2017
comment
Возможно, вам это нравится, потому что Стефан использует новые причудливые java-функции. Но я думаю, что это очень трудно читать и понимать. - person Stimpson Cat; 05.07.2019

Также мы можем использовать класс StopWatch из общего числа Apache для измерения времени.

Образец кода

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());
person Narayan    schedule 03.12.2011

JEP 230: Пакет Microbenchmark

К вашему сведению, JEP 230: Microbenchmark Suite - это OpenJDK для:

Добавьте базовый набор микробенчмарков в исходный код JDK и упростите разработчикам запуск существующих микротестов и создание новых.

Эта функция появилась в Java 12.

Обвязка Java Microbenchmark (JMH)

Для более ранних версий Java ознакомьтесь с Java Microbenchmark Harness (JMH) проект, на котором основан JEP 230.

person Basil Bourque    schedule 01.07.2016

Небольшой поворот, если вы не используете инструменты и хотите синхронизировать методы с низким временем выполнения: выполняйте его много раз, каждый раз удваивая количество раз, когда он выполняется, пока вы не дойдете до секунды или около того. Таким образом, время вызова System.nanoTime и т. Д., А также точность System.nanoTime не сильно влияют на результат.

    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");

Конечно, есть предостережения об использовании настенных часов: влияние JIT-компиляции, нескольких потоков / процессов и т. Д. Таким образом, вам нужно сначала выполнить метод много раз, чтобы JIT компилятор выполняет свою работу, а затем повторяет этот тест несколько раз и занимает наименьшее время выполнения.

person Hans-Peter Störr    schedule 05.11.2008

Для этого мы используем аннотации AspectJ и Java. Если нам нужно знать время выполнения метода, мы просто аннотируем его. Более продвинутая версия может использовать собственный уровень журнала, который можно включать и отключать во время выполнения.

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;
  }
  [...]
}
person Community    schedule 08.10.2008

Действительно хороший код.

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;
  }
person iceberg    schedule 15.06.2012
comment
На самом деле вопрос заключался в том, как рассчитать количество времени, которое требуется для метода, а не в том, как его отформатировать. Однако этот вопрос довольно старый (почти четыре года!). Старайтесь не восстанавливать старые потоки, если ответ не добавит чего-то нового и значительного по сравнению с существующими ответами. - person Leigh; 15.06.2012
comment
И чтобы добавить оставшиеся миллисекунды до конца, внесите следующие изменения: 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); } - person Rick Barkhouse; 24.01.2013

Вы можете использовать Perf4j. Очень классная утилита. Использование простое

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; 
}

Дополнительную информацию можно найти в Руководстве разработчика

Изменить: Проект кажется мертвым

person mergenchik    schedule 26.02.2012
comment
Perf4j также может генерировать хорошую статистику. - person Paaske; 28.03.2012

Spring предоставляет служебный класс org.springframework. util.StopWatch, согласно JavaDoc:

Простой секундомер, позволяющий отсчитывать время для ряда задач, показывая общее время выполнения и время выполнения для каждой названной задачи.

Использование:

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());

Выход:

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

С аспектами:

@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;
}
person Sunil Manheri    schedule 06.08.2015
comment
Можно ли использовать это с AspectJ? - person zygimantus; 20.10.2015

Я написал метод для вывода времени выполнения метода в удобочитаемой форме. Например, чтобы вычислить факториал 1 миллиона, потребуется примерно 9 минут. Таким образом, время выполнения печатается как:

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

Код здесь:

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");
    }
}
person Pratik Patil    schedule 29.10.2018

Использование аннотации AOP / AspectJ и @Loggable из jcabi-sizes, вы можете сделать это легко и компактно:

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

Каждый вызов этого метода будет отправляться в средство ведения журнала SLF4J с DEBUG уровнем ведения журнала. И каждое сообщение журнала будет включать время выполнения.

person yegor256    schedule 06.01.2013

Я в основном делаю варианты этого, но, учитывая, как работает компиляция хотспотов, если вы хотите получить точные результаты, вам нужно выбросить первые несколько измерений и убедиться, что вы используете метод в реальном (читайте для конкретного приложения) приложении.

Если JIT решит скомпилировать его, ваши цифры будут сильно отличаться. так что просто будь в курсе

person luke    schedule 07.10.2008

Есть несколько способов сделать это. Обычно я просто использую что-то вроде этого:

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

или то же самое с System.nanoTime ();

Для чего-то большего, связанного с эталонным тестированием, похоже, также есть это: http://jetm.void.fm/ Но никогда не пробовал.

person Horst Gutmann    schedule 07.10.2008

Если вы хотите настенные часы

long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;
person David Nehme    schedule 07.10.2008

Вы можете использовать библиотеку Metrics, которая предоставляет различные измерительные инструменты. Добавить зависимость:

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

И настройте его для своей среды.

Методы можно аннотировать с помощью @Timed. :

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

или фрагмент кода, обернутый Timer:

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

Агрегированные метрики можно экспортировать в консоль, JMX, CSV или другие.

@Timed пример вывода показателей:

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
person Justinas Jakavonis    schedule 31.07.2017

Как сказал "skaffman", используйте АОП ИЛИ вы можете использовать переплетение байт-кода во время выполнения, точно так же, как инструменты покрытия методов модульного тестирования используют для прозрачного добавления информации о времени в вызываемые методы.

Вы можете посмотреть код, используемый инструментами с открытым исходным кодом, такими как Emma (http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0). Другой инструмент покрытия с открытым исходным кодом - http://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?download.

Если вам в конце концов удастся сделать то, к чему вы стремились, пожалуйста. поделитесь им с сообществом здесь с помощью вашей задачи / jar-файлов.

person anjanb    schedule 07.10.2008

Я изменил код из правильного ответа, чтобы получить результат за секунды:

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);
person Denis Kutlubaev    schedule 27.12.2013

Хорошо, это простой класс, который можно использовать для простого определения времени выполнения ваших функций. Ниже приведен пример.

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");
    }
}

Пример использования:

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;
}

Пример вывода консоли:

Split time for [file to string]: 672 ms
Split time for [parse Json]: 893 ms
Final time for [get Schedule]: 1565 ms
person msysmilu    schedule 27.01.2015

Вы можете использовать класс секундомера из проекта ядра Spring:

Код:

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

Документация для секундомера: Простой секундомер, позволяющий рассчитывать время для ряда задач, показывая общее время выполнения и время выполнения для каждой названной задачи. Скрывает использование System.currentTimeMillis (), улучшая читаемость кода приложения и снижая вероятность ошибок вычислений. Обратите внимание, что этот объект не предназначен для обеспечения многопоточности и не использует синхронизацию. Этот класс обычно используется для проверки производительности во время проверки концепции и в процессе разработки, а не как часть производственных приложений.

person praveen jain    schedule 08.03.2018

Вы можете попробовать этот способ, если хотите знать время.

long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));    
person gifpif    schedule 06.12.2013

В Java 8 представлен новый класс с именем Instant. Согласно документу:

Instant представляет собой начало наносекунды на временной шкале. Этот класс полезен для создания отметки времени, представляющей машинное время. Диапазон мгновенного требует хранения числа больше, чем длинное. Для этого класс хранит long, представляющий эпоху-секунды, и int, представляющий наносекунду секунды, который всегда будет находиться в диапазоне от 0 до 999 999 999. Эпоха-секунды отсчитываются от стандартной эпохи Java 1970-01-01T00: 00: 00Z, где моменты после эпохи имеют положительные значения, а более ранние моменты имеют отрицательные значения. Как для эпохи-секунды, так и для наносекундной части большее значение всегда находится позже на временной шкале, чем меньшее значение.

Это можно использовать как:

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

Он печатает PT7.001S.

person akhil_mittal    schedule 22.06.2015

В Spring framework у нас есть вызов StopWatch (org.springframework.util.StopWatch)

//measuring elapsed time using Spring StopWatch
        StopWatch watch = new StopWatch();
        watch.start();
        for(int i=0; i< 1000; i++){
            Object obj = new Object();
        }
        watch.stop();
        System.out.println("Total execution time to create 1000 objects in Java using StopWatch in millis: "
                + watch.getTotalTimeMillis());
person Bhaskara Arani    schedule 16.05.2020
comment
Из документов: This class is normally used to verify performance during proof-of-concept work and in development, rather than as part of production applications. - person q99; 17.06.2020
comment
@ q99 Правда, такую ​​логику мы не внедряем в производственную среду, прежде чем переносить ее в производственную среду, нам нужно протестировать - person Bhaskara Arani; 19.06.2020

Было бы неплохо, если бы у java была лучшая функциональная поддержка, чтобы действие, которое нужно измерить, можно было бы заключить в блок:

measure {
   // your operation here
}

В java это может быть сделано анонимными функциями, которые выглядят слишком многословно.

public interface Timer {
    void wrap();
}


public class Logger {

    public static void logTime(Timer timer) {
        long start = System.currentTimeMillis();
        timer.wrap();
        System.out.println("" + (System.currentTimeMillis() - start) + "ms");
    }

    public static void main(String a[]) {
        Logger.logTime(new Timer() {
            public void wrap() {
                // Your method here
                timeConsumingOperation();
            }
        });

    }

    public static void timeConsumingOperation() {
        for (int i = 0; i<=10000; i++) {
           System.out.println("i=" +i);
        }
    }
}
person Alexey Pismenskiy    schedule 16.01.2015
comment
Вероятно, можно было бы очистить лямбда-выражения Java 8. drdobbs.com/jvm/lambda-expressions- in-java-8/240166764? pgno = 2 - person Ogre Psalm33; 19.01.2015
comment
Действительно, начиная с Java 8, java.lang.Runnable является @FunctionalInterface, что означает, что вы можете передать лямбда-выражение любому методу, который принимает Runnable в качестве параметра. Ваш timeThisCode(Runnable r) может просто возвращать миллис / нано или более подробное представление прошедшего времени. - person Cornel Masson; 24.04.2015

Вот довольно напечатанная строка, готовая отформатированная, прошедшая секунда, аналогичная времени поиска в Google, затраченному на поиск:

        long startTime = System.nanoTime();
        //  ... methodToTime();
        long endTime = System.nanoTime();
        long duration = (endTime - startTime);
        long seconds = (duration / 1000) % 60;
        // formatedSeconds = (0.xy seconds)
        String formatedSeconds = String.format("(0.%d seconds)", seconds);
        System.out.println("formatedSeconds = "+ formatedSeconds);
        // i.e actual formatedSeconds = (0.52 seconds)
person timxor    schedule 15.12.2016
comment
nonoTime не равно 1000 секунды. ваша математика предполагает getTime, который составляет миллисекунду. лучше сделать / 1e6, чтобы получить миллисекунды. - person simbo1905; 14.02.2018

Я реализовал простой таймер, и считаю, что он действительно полезен:

public class Timer{
    private static long start_time;

    public static double tic(){
        return start_time = System.nanoTime();
    }

    public static double toc(){
        return (System.nanoTime()-start_time)/1000000000.0;
    }

}

Таким образом вы можете рассчитать время для одного или нескольких действий:

Timer.tic();
// Code 1
System.out.println("Code 1 runtime: "+Timer.toc()+" seconds.");
// Code 2
System.out.println("(Code 1 + Code 2) runtime: "+Timer.toc()+"seconds");
Timer.tic();
// Code 3
System.out.println("Code 3 runtime: "+Timer.toc()+" seconds.");
person StationaryTraveller    schedule 29.12.2016

Вы можете использовать javaagent для изменения байтов класса java, динамически добавлять коды монитора. В github есть несколько инструментов с открытым исходным кодом, которые могут сделать это за вас.
Если вы хотите сделать это с помощью вы просто реализуете javaagent, используйте javassist для изменения методов, которые вы хотите отслеживать, и код монитора перед возвратом вашего метода. он чистый, и вы можете отслеживать системы, которые вы даже нет исходного кода.

person dingjsh    schedule 21.09.2015

Измерения производительности на моей машине

  • System.nanoTime() : 750ns
  • System.currentTimeMillis() : 18ns

Как уже упоминалось, считается, что System.nanoTime() измеряет прошедшее время. Просто помните о стоимости при использовании внутри цикла или чего-то подобного.

person leo    schedule 17.09.2014

System.nanoTime() - довольно точная системная утилита для измерения времени выполнения. Но будьте осторожны, если вы работаете в режиме упреждающего планировщика (по умолчанию), эта утилита фактически измеряет время настенных часов, а не время процессора. Таким образом, вы можете заметить разные значения времени выполнения от запуска к запуску, в зависимости от загрузки системы. Если вы посмотрите на процессорное время, я думаю, что запуск вашей программы в режиме реального времени поможет. Вы должны использовать RT linux. ссылка: Программирование в реальном времени с Linux

person hmitcs    schedule 03.07.2013

Стратегия, которая работает для меня в java ee, была:

  1. Создайте класс с методом, помеченным @AroundInvoke;

    @Singleton
    public class TimedInterceptor implements Serializable {
    
        @AroundInvoke
        public Object logMethod(InvocationContext ic) throws Exception {
            Date start = new Date();
            Object result = ic.proceed();
            Date end = new Date();
            System.out.println("time: " + (end.getTime - start.getTime()));
            return result;
        }
    }
    
  2. Отметьте метод, который вы хотите отслеживать:

    @Interceptors(TimedInterceptor.class)
    public void onMessage(final Message message) { ... 
    

Надеюсь, это поможет.

person Maciel Bombonato    schedule 06.07.2017

Для java 8+ другое возможное решение (более общее, в стиле func и без аспектов) могло бы заключаться в создании некоторого служебного метода, принимающего код в качестве параметра

public static <T> T timed (String description, Consumer<String> out, Supplier<T> code) {
    final LocalDateTime start = LocalDateTime.now ();
    T res = code.get ();
    final long execTime = Duration.between (start, LocalDateTime.now ()).toMillis ();
    out.accept (String.format ("%s: %d ms", description, execTime));
    return res;
}

И код вызова может быть что-то вроде этого:

public static void main (String[] args) throws InterruptedException {
    timed ("Simple example", System.out::println, Timing::myCode);
}

public static Object myCode () {
    try {
        Thread.sleep (1500);
    } catch (InterruptedException e) {
        e.printStackTrace ();
    }
    return null;
}
person Aska Fed    schedule 30.09.2019

Чистый код Java SE, нет необходимости добавлять зависимости, используя TimeTracedExecuter:

public static void main(String[] args) {

    Integer square = new TimeTracedExecutor<>(Main::calculateSquare)
                .executeWithInput("calculate square of num",5,logger);

}
public static int calculateSquare(int num){
    return num*num;
}

Результат будет примерно таким:

INFO: It took 3 milliseconds to calculate square of num

Пользовательский многоразовый класс: TimeTracedExecutor

import java.text.NumberFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.function.Function;
import java.util.logging.Logger;

public class TimeTracedExecutor<T,R> {
    Function<T,R> methodToExecute;

    public TimeTracedExecutor(Function<T, R> methodToExecute) {
        this.methodToExecute = methodToExecute;
    }

    public R executeWithInput(String taskDescription, T t, Logger logger){
        Instant start = Instant.now();
        R r= methodToExecute.apply(t);
        Instant finish = Instant.now();
        String format = "It took %s milliseconds to "+taskDescription;
        String elapsedTime = NumberFormat.getNumberInstance().format(Duration.between(start, finish).toMillis());
        logger.info(String.format(format, elapsedTime));
        return r;
    }
}
person Ahmad Hoghooghi    schedule 28.04.2020

person    schedule
comment
Сворачивание собственного простого класса - хороший выбор, если у вас уже настроена система сборки и зависимый OTS, и вы не хотите беспокоиться о добавлении другого пакета OTS, который включает служебный класс таймера. - person Ogre Psalm33; 04.04.2013