Подтвердить что ты не робот

Тестирование производительности Java

Я хочу сделать некоторые тесты времени в приложении Java. Это то, что я сейчас делаю:

long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");

Есть ли что-то "неправильное" при тестировании производительности? Что лучше?

Дубликат: Допустимы ли тесты в секундомере?

4b9b3361

Ответ 1

Единственным недостатком этого подхода является то, что "реальное" время 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!)

Эта стратегия не идеальна, но она менее подвержена изменениям в загрузке системы.

Ответ 2

Код, показанный в вопросе, не является хорошим кодом измерения производительности:

  • Компилятор может выбрать оптимизацию кода путем переопределения операторов. Да, он может это сделать. Это означает, что весь ваш тест может потерпеть неудачу. Он может даже выбрать встроенный метод проверки и изменить порядок измерений в теперь встроенный код.

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

  • Даже если предположить, что компилятор/точка доступа не обманывали вас, то, что вы измеряете, - это "время на стене". То, что вы должны измерять, - это время процессора (если вы не используете ресурсы ОС и не хотите включать их, или вы измеряете блокировку в многопоточной среде).

Решение? Используйте реальный профилировщик. Существует множество возможностей, как для бесплатных профилировщиков, так и для демонстрационных/задержек с проверкой прочности рекламных роликов.

Ответ 3

Использование Java Profiler - лучший вариант, и он даст вам все понимание, которое вам нужно в коде. viz Response Times, Thread CallTraces, Утилиты памяти и т.д.

Я предлагаю вам JENSOR, открытый Java-профайлер с открытым исходным кодом, для простоты использования и нет накладных расходов на процессор. Вы можете загрузить его, использовать код и получить всю необходимую информацию о своем коде.

Вы можете скачать его из: http://jensor.sourceforge.net/

Ответ 4

Помните, что разрешение System.currentTimeMillis() зависит от разных операционных систем. Я считаю, что Windows составляет около 15 мс. Поэтому, если ваш doSomething() работает быстрее разрешения по времени, вы получите дельта 0. Вы можете запустить doSomething() в цикле несколько раз, но тогда JVM может оптимизировать его.

Ответ 5

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

Ответ 6

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

Ответ 7

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

Ответ 8

Вы просмотрели инструменты профилирования в netbeans и eclipse. Эти инструменты помогут вам лучше справиться с тем, что ДЕЙСТВИТЕЛЬНО занимает все время в вашем коде. Я нашел проблемы, которые я не понимал, используя эти инструменты.

Ответ 9

Japex может быть вам полезен, как способ быстрого создания контрольных показателей, или как способ изучения проблем с бенчмаркингом в Java через исходный код.