Один дефект в том подходе - то, что "реальное" время 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!)
Эта стратегия не прекрасна, но она меньше подвергается изменениям в системной нагрузке.
Код, показанный в вопросе, не является хорошим кодом измерения производительности:
компилятор мог бы принять решение оптимизировать Ваш код путем переупорядочения операторов. Да, это может сделать это. Это означает, что Ваш весь тест мог бы перестать работать. Это может даже принять решение встроить метод под тестом и переупорядочить имеющие размеры операторы в теперь встроенный код.
горячая точка могла бы принять решение переупорядочить Ваши операторы, встроенный код, результаты кэша, выполнение задержки...
Даже принятие компилятора/горячей точки не обманывало Вас, что Вы измеряете, "стенное время". То, что необходимо измерять, является процессорным временем (если Вы не используете ресурсы ОС и хотите включать их также, или Вы измеряете соревнование блокировки в многопоточной среде).
решение? Используйте настоящего профилировщика. Существуют много вокруг, и свободные профилировщики и демонстрации / заблокированные временем пробные версии силы рекламы.
Используя Java Профилировщик является наилучшим вариантом, и он даст Вам все понимание, в котором Вы нуждаетесь в код. то есть Время отклика, Поток CallTraces, Использования памяти, и т.д.
я предложу Вас JENSOR, Профилировщик Java с открытым исходным кодом, для его простоты в употреблении и никаких издержек на ЦП. Вы можете загрузить его, оснастить код и получите всю информацию, в которой Вы нуждаетесь о своем коде.
можно загрузить его с: http://jensor.sourceforge.net /
Следует иметь в виду, что разрешение System.currentTimeMillis()
варьируется между различными операционными системами. Я полагаю, что Windows составляет приблизительно 15 мс. Таким образом, если Ваш doSomething()
выполнения быстрее, чем разрешение времени, Вы получите дельту 0. Вы могли работать doSomething()
в цикле многократно, но тогда JVM может оптимизировать его.
Хорошо это - всего одна часть тестирования производительности. В зависимости от вещи Вы тестируете Вас, вероятно, придется посмотреть на размер "кучи", количество потока, сетевой трафик или большое количество других вещей. Иначе я использую ту технику для простых вещей, которые я просто хочу видеть, сколько времени они берут для выполнения.
Это хорошо, когда Вы сравниваете одну реализацию с другим или пытаетесь найти медленную часть в своем коде (хотя это может быть утомительно). Это - действительно хорошая техника для знания, и Вы будете, вероятно, использовать его больше, чем кто-либо другой, но будете знакомы с профильным инструментом также.
Вы посмотрели на профильные инструменты в netbeans и затмение . Эти инструменты дают Вам лучший дескриптор на том, что ДЕЙСТВИТЕЛЬНО поднимает все время в Вашем коде. Я нашел проблемы, которые я не осознавал при помощи этих инструментов.
Я предположил бы, что Вы захотите к doSomething (), прежде чем Вы начнете синхронизировать также, так, чтобы код был JITted и "подогревший".
Japex может быть полезен для Вас, или как способ быстро создать сравнительные тесты, или как способ изучить проблемы сравнительного тестирования в Java через исходный код.