Teste de desempenho Java [duplicado]

esta pergunta já tem uma resposta aqui:

  • O benchmarking do cronómetro é aceitável? 13 Respostas
Quero fazer alguns testes de tempo numa aplicação Java. Isto é o que estou fazendo atualmente:

long startTime = System.currentTimeMillis();
doSomething();
long finishTime = System.currentTimeMillis();
System.out.println("That took: " + (finishTime - startTime) + " ms");
Há algo de errado com testes de desempenho como este? O que é uma maneira melhor?

Duplicate : O benchmarking do cronómetro é aceitável?

Author: Chris W., 2009-01-15

9 answers

A única falha nessa abordagem é que o tempo "real" doSomething() leva para executar pode variar muito dependendo de quais outros programas estão a correr no sistema e qual é a sua carga. Isto torna a medição de desempenho um pouco imprecisa.

Uma maneira mais precisa de rastrear o tempo que leva para executar o código, assumindo que o código é de simples thread, é olhar para o tempo de CPU consumido pela thread durante a chamada. Você pode fazer isso com as classes JMX; em particular, com ThreadMXBean. Você pode obter uma instância de ThreadMXBean de java.lang.management.ManagementFactory, e, se a sua plataforma que o suporta (a maioria), use o getCurrentThreadCpuTime método no lugar de System.currentTimeMillis para fazer um teste semelhante. Tenha em mente que getCurrentThreadCpuTime relata tempo em nanossegundos, não milisegundos.

Aqui está um método de amostra (Scala) que pode ser usado para realizar uma medição:

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

(Sinta-se à vontade para traduzir o acima para Java!)

Esta estratégia não é perfeita, mas está menos sujeita a variações na carga do sistema.
 30
Author: MattK, 2017-11-17 21:01:20

O código indicado na pergunta não é um bom código de medição de desempenho:

  1. O compilador pode optar por otimizar o seu código através da reordenação de declarações. Sim, pode fazer isso. Isso significa que todo o teu teste pode falhar. Ele pode até mesmo optar por alinhar o método sob teste e reordenar as declarações de medição no código agora alinhado.

  2. O hotspot pode optar por reordenar suas declarações, código de entrada, resultados de cache, atraso execucao...

  3. Mesmo assumindo que o compilador/hotspot não te enganou, o que Medes é "tempo de parede". O que você deve estar medindo é o tempo da CPU (a menos que você use os recursos do OS e queira incluí-los também ou você medir a contestação da fechadura em um ambiente multi-threaded).

A solução? Usa um verdadeiro profiler. Há muitas ao redor, tanto profilers gratuitos e demonstrações / tempo-locked ensaios de comerciais fortes uns.
 16
Author: Ran Biron, 2009-01-15 20:23:44

Usar um compilador Java é a melhor opção e dar-lhe-á toda a informação que necessita sobre o código. tempos de resposta do viz, ligações por fio, Utilisações de memória, etc

Vou sugerir-te JENSOR, um compilador Java open source, por sua facilidade de uso e sem overheads na CPU. Você pode baixá-lo, instrumentalizar o código e obter todas as informações que você precisa sobre o seu código.

Você pode baixá-lo de: http://jensor.sourceforge.net/

 2
Author: M.N, 2009-01-24 06:40:12

Tenha em mente que a resolução de System.currentTimeMillis() varia entre diferentes sistemas operacionais. Acho que o Windows é por volta de 15 msec. Então, se o seu doSomething() correr mais rápido do que a resolução do tempo, você terá um delta de 0. Você poderia executar doSomething() em um loop várias vezes, mas então o JVM pode otimizá-lo.

 1
Author: Steve Kuo, 2009-01-15 17:49:43
Bem, isso é apenas uma parte dos testes de desempenho. Dependendo da coisa que você está testando você pode ter que olhar para o tamanho do heap, número de linhas, tráfego de rede ou uma série inteira de outras coisas. Caso contrário, uso essa técnica para coisas simples que só quero ver quanto tempo demoram a correr.
 0
Author: Josh Harris, 2009-01-15 17:46:49
Isso é bom quando você está comparando uma implementação com outra ou tentando encontrar uma parte lenta em seu código (embora possa ser tedioso). É uma técnica muito boa para saber e você provavelmente vai usá-lo mais do que qualquer outro, mas estar familiarizado com uma ferramenta de perfis também.
 0
Author: Bill K, 2009-01-15 17:53:46

Já olhaste para as ferramentas de perfis emnetbeans eeclipse . Estas ferramentas dão-lhe um controle melhor sobre o que está realmente tomando todo o tempo em seu código. Eu encontrei problemas que eu não percebi usando essas ferramentas.

 0
Author: Milhous, 2009-01-15 18:06:46
Imagino que queiras fazer alguma coisa antes de começares a cronometrar também, para que o código seja misturado e "aquecido".
 0
Author: Kent Boogaart, 2011-09-28 00:03:02

Japex pode ser útil para você, seja como uma forma de criar benchmarks rapidamente, ou como uma forma de estudar questões de benchmarking em Java através do código fonte.

 0
Author: Rich Apodaca, 2015-09-04 22:04:46