Я хочу провести временные тесты для Java-приложения. Вот чем я сейчас занимаюсь:
long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");
Есть ли что-то «неправильное» в подобном тестировании производительности? Какой способ лучше?
Дубликат: Допустимо ли тестирование секундомера?
Я действительно хочу получить ответы на оба вопроса ... Но больше склоняюсь к "правильному способу сделать это для получения точных результатов"
Не по теме и действительно не решает вашу проблему, поэтому я вставлю это в комментарий. Выступление Джона Бентли в Google «Три красивых быстрых сортировки» - это действительно интересный взгляд на производительность и анализ алгоритмов. Веселая штука. video.google.com/videoplay?docid=-1031789501179533828




Я предполагаю, что вы тоже захотите сделать Something () до того, как начнете отсчет времени, чтобы код был JITter и «разогретым».
Что ж, это лишь часть тестирования производительности. В зависимости от того, что вы тестируете, вам, возможно, придется посмотреть на размер кучи, количество потоков, сетевой трафик или целый ряд других вещей. В противном случае я использую эту технику для простых вещей, которые я просто хочу увидеть, сколько времени они займут.
Имейте в виду, что разрешение System.currentTimeMillis() зависит от операционной системы. Я считаю, что Windows составляет около 15 мсек. Поэтому, если ваш doSomething() работает быстрее, чем разрешение по времени, вы получите дельту 0. Вы можете запускать doSomething() в цикле несколько раз, но тогда JVM может его оптимизировать.
Это хорошо, когда вы сравниваете одну реализацию с другой или пытаетесь найти медленную часть в своем коде (хотя это может быть утомительно). Это действительно хороший метод, и вы, вероятно, будете использовать его чаще, чем любой другой, но вы также должны быть знакомы с инструментом профилирования.
Единственный недостаток этого подхода заключается в том, что время, необходимое doSomething() для выполнения в «реальном» времени, может сильно различаться в зависимости от того, какие другие программы работают в системе и какова их нагрузка. Это делает измерение производительности несколько неточным.
Еще один точный способ отслеживания времени, необходимого для выполнения кода, при условии, что код является однопоточным, - это посмотреть на процессорное время, потребляемое потоком во время вызова. Вы можете сделать это с помощью классов JMX; в частности, с ThreadMXBean. Вы можете получить экземпляр ThreadMXBean из java.lang.management.ManagementFactory, и, если ваша платформа поддерживает его (большинство из них поддерживает), используйте метод getCurrentThreadCpuTime вместо System.currentTimeMillis для проведения аналогичного теста. Имейте в виду, что getCurrentThreadCpuTime сообщает время в наносекундах, а не в миллисекундах.
Вот пример метода (Scala), который можно использовать для измерения:
def measureCpuTime(f: => Unit): java.time.Duration = {
import java.lang.management.ManagementFactory.getThreadMXBean
if (!getThreadMXBean.isThreadCpuTimeSupported)
throw new UnsupportedOperationException(
"JVM does not support measuring thread CPU-time")
var finalCpuTime: Option[Long] = None
val thread = new Thread {
override def run(): Unit = {
f
finalCpuTime = Some(getThreadMXBean.getThreadCpuTime(
Thread.currentThread.getId))
}
}
thread.start()
while (finalCpuTime.isEmpty && thread.isAlive) {
Thread.sleep(100)
}
java.time.Duration.ofNanos(finalCpuTime.getOrElse {
throw new Exception("Operation never returned, and the thread is dead " +
"(perhaps an unhandled exception occurred)")
})
}
(Не стесняйтесь переводить вышесказанное на Java!)
Эта стратегия не идеальна, но она менее подвержена изменениям в загрузке системы.
Этот ответ был бы даже лучше, если бы в нем был образец кода, демонстрирующий, как можно написать тест.
@NoctisSkytower, я добавил образец кода (метод измерения). К сожалению (или к счастью?) Это на Scala; не стесняйтесь переводить и редактировать ответ.
@ Даан ссылка не работает.
Japex может быть вам полезен либо как способ быстрого создания тестов производительности, либо как способ изучения проблем тестирования производительности в Java через исходный код.
Ссылка, должно быть, переехала. Japex сейчас находится по адресу: japex.java.net
Код, показанный в вопросе, не является хорошим кодом для измерения производительности:
Компилятор может оптимизировать ваш код, изменив порядок операторов. Да, он может это сделать. Это означает, что весь ваш тест может провалиться. Он даже может выбрать встроенный тестируемый метод и переупорядочить операторы измерения во встроенном коде.
Точка доступа может изменить порядок ваших операторов, встроенного кода, результатов кеширования, отложить выполнение ...
Даже если предположить, что компилятор / точка доступа не обманули вас, вы измеряете «время стены». Что вы должны измерять, так это процессорное время (если вы не используете ресурсы ОС и не хотите их также включать или вы не измеряете оспаривание блокировок в многопоточной среде).
Решение? Используйте настоящий профайлер. Есть много чего, как бесплатные профилировщики, так и демонстрации / ограниченные по времени испытания сильных рекламных роликов.
Hotspot не только скомпилирует код в какой-то момент и произведет оптимизацию, о которой вы упомянули, но и на самом деле может иметь MUTLITPLE попытки компиляции с разными оптимизациями: т.е. повторения по времени могут означать синхронизацию другого кода! Будьте очень-очень-очень осторожны ...
Не хотелось предлагать какие-либо варианты профилировщика?
@JohnRPerry, поскольку список часто меняется, а те, которые мне нравятся, могут не соответствовать вашим потребностям, безопасно просто загуглить профилировщики Java и выяснить это самостоятельно. Лично мне нравится работать с YourKit для профилирования тяжелого веса и Java Microbenchmark Harness (JMH) для микротестов.
Использование профилировщика Java - лучший вариант, и он даст вам всю необходимую информацию о коде. а именно время отклика, отслеживание вызовов потоков, использование памяти и т. д.
Я предлагаю вам ДЖЕНСОР, Java Profiler с открытым исходным кодом, за его простоту использования и отсутствие накладных расходов на процессор. Вы можете скачать его, обработать код и получить всю необходимую информацию о вашем коде.
Вы можете скачать его по ссылке: http://jensor.sourceforge.net /
Вы спрашиваете, подходит ли бенчмаркинг с использованием секундомера, или вы спрашиваете, правильный ли это способ сделать это?