Как рассчитать скорость выполнения Java-программы

85

Как вы рассчитываете время выполнения Java-программы? Я не уверен, какой класс мне следует использовать для этого.

Я как бы ищу что-то вроде:

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

System.out.println("Total execution time: " + totalExecutionTime);
Джордж Мик
источник

Ответы:

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));
буа
источник
2
на самом деле это должно быть nanoTime
Евгений
6
Не должно быть nanoTime. См. Ответ Ру.
fabspro
4
Есть ли какая-то особая причина, по которой вы использовали здесь слово «final»? Что изменилось бы, если бы вы опустили это ключевое слово?
dijxtra
9
Использование @dijxtra finalимеет то преимущество, что вы не можете случайно назначить его (а также другие преимущества, такие как анонимный доступ к классам и т. д.). В этом коде это не имело бы значения. Довольно распространенная практика - все делать finalи finalунифицировать только в случае необходимости.
wchargin
1
Тестируемый код вместе с измерениями времени следует запускать несколько раз, а первый результат следует отбросить. Первый, вероятно, будет включать время загрузки класса и т. Д. Запустив его несколько раз, вы, конечно же, получите среднее значение, которое будет более полезным и надежным.
Арун Рамакришнан
34

Имейте в виду, что есть некоторые проблемы, когда System#nanoTime()их нельзя надежно использовать на многоядерных процессорах для записи прошедшего времени ... каждое ядро ​​поддерживает свой собственный TSC ( счетчик отметок времени ): этот счетчик используется для получения нано-времени (на самом деле это количество тиков с момента загрузки ЦП).

Следовательно, если ОС не выполняет некоторую деформацию времени TSC, чтобы синхронизировать ядра, тогда, если поток планируется на одном ядре, когда выполняется начальное считывание времени, а затем переключается на другое ядро, относительное время может спорадически перемещаться назад и вперед.

Я наблюдал это некоторое время назад на AMD / Solaris, где время, прошедшее между двумя временными точками, иногда возвращалось либо как отрицательные значения, либо как неожиданно большие положительные числа. Для принудительной установки AMD PowerNow! Требовались патч ядра Solaris и настройки BIOS. off, который, похоже, решил эту проблему.

Кроме того, есть (AFAIK) пока еще не исправленная ошибка при использовании java System#nanoTime()в среде VirtualBox; вызывая для нас всевозможные причудливые периодические проблемы с потоками, поскольку большая часть java.util.concurrencyпакета полагается на нано-время.

Смотрите также:

System.nanoTime () совершенно бесполезен? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html

Ру
источник
9

Вы получаете текущее системное время в миллисекундах:

final long startTime = System.currentTimeMillis();

Затем вы делаете то, что собираетесь делать:

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

Тогда вы увидите, сколько времени это заняло:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;
Джонатан Файнберг
источник
Ответ BalusC также верен; это зависит от необходимого разрешения таймера и от того, зачем вам это время.
Джонатан Файнберг,
9

Вы можете использовать System#nanoTime(). Получите это до и после казни и просто посчитайте. Предпочтительно вышеSystem#currentTimeMillis() потому что он обеспечивает лучшую точность. В зависимости от используемого оборудования и платформы, вы можете получить неправильный промежуток времени. Здесь, с Core2Duo в Windows, между 0 и ~ 15 мс фактически ничего нельзя вычислить.

Более продвинутый инструмент - профилировщик .

BalusC
источник
Таймер в Windows по умолчанию не имеет особенно хорошего разрешения. Также есть высокопроизводительный таймер, но его намного сложнее использовать даже из C, а Java (AFAIK) не предоставляет доступ к такому низкому уровню хакерства без JNI thunk.
Donal Fellows,
1
nanoTime()есть одна проблема (по крайней мере, в Windows); метка времени зависит от ядра процессора. У меня была программа, которая имела отрицательное время выполнения, потому что у нее была временная метка «старта» на одном ядре и временная метка «остановки» на другом ядре.
gustafc
3

Для простых вещей может работать System.currentTimeMillis () .

На самом деле это настолько распространено, что моя IDE настроена так, что при вводе «t0» она генерирует следующую строку:

final long t0 = System.currentTimeMillis()

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

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

Синтаксис T3rr0r
источник
+1 за указание кода автогенератора. Я все время использую подобное утверждение и не знал о вставке шаблонов кода. Только что узнал, как это сделать с помощью eclipse, и это определенно поможет!
Джейсон
Все услуги Codehaus прекращены. Ваша ссылка теперь не работает.
naXa 06
2

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

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

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

Егор256
источник
2

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

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

или же

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);
СумиСуджит
источник
1

используйте long startTime=System.currentTimeMillis()для времени начала, в верхней части цикла

положить long endTime= System.currentTimeMillis();за пределы конца петли. Вам нужно будет вычесть значения, чтобы получить время выполнения в миллисекундах.

Если вам нужно время в наносекундах, посмотрите System.nanoTime()

Джейсон
источник
1

Я создал функцию более высокого порядка, которая принимает код, который вы хотите измерить, в / как лямбда:

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

Назовите это так:

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

Вывод:

код 0: 180528 нс
код 1: 12003 нс

Особая благодарность Энди Тернеру, который помог мне сократить избыточность. Смотрите здесь .

Вилли Ментцель
источник
0

Вы также можете попробовать Perf4J. Это изящный способ делать то, что вы ищете, и помогает в агрегированной статистике производительности, такой как среднее, минимальное, максимальное, стандартное отклонение и количество транзакций в секунду за заданный промежуток времени. Выдержка из 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);
}

Вывод:

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
источник
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
источник
0

Использование System.currentTimeMillis () - правильный способ сделать это. Но если вы используете командную строку и хотите приблизительно и быстро рассчитать время всей программы, подумайте о следующем:

time java App

что позволяет не изменять код и время вашего приложения.

MarAja
источник
Это зависит от того, как вы запускаете код. Если это фрагмент кода, запускающий сервер, то вы собираетесь указать время запуска, которое неверно.
Арун Рамакришнан