Pergunta

Como você escreve (e executar) um micro-referência correto em Java?

Eu estou procurando alguns exemplos de código e comentários que ilustram várias coisas em que pensar.

Exemplo: Caso o tempo de medida de referência / iteração ou iterações / hora, e por

relacionadas: é cronômetro aferição aceitável

?
Foi útil?

Solução

Dicas sobre como escrever micro benchmarks dos criadores de Java HotSpot :

Regra 0: Leia um papel respeitável na JVMs e micro-benchmark. Uma boa é Brian Goetz, 2005 . Não espere muito do micro-benchmarks; eles medem apenas uma gama limitada de características de desempenho da JVM.

Regra 1: Sempre inclua uma fase de aquecimento que corre o kernel teste durante todo o tempo, o suficiente para acionar todas as inicializações e compilações antes da fase timing (s). (Iterações Menos é OK na fase de aquecimento. A regra de ouro é várias dezenas de milhares de iterações do loop interno.)

Regra 2:. Sempre executar com -XX:+PrintCompilation, -verbose:gc, etc., para que possa verificar se o compilador e outras partes da JVM não estão fazendo um trabalho inesperado durante a sua fase de sincronismo

Regra 2.1:. Imprimir mensagens no início e no final das fases de tempo e de aquecimento, para que possa verificar que não há saída do Regra 2 durante a fase de sincronismo

Regra 3: Esteja ciente da diferença entre -client e -server e OSR e compilações regulares. A bandeira -XX:+PrintCompilation relata compilações OSR com um sinal de arroba para denotar o ponto de entrada não-inicial, por exemplo: Trouble$1::run @ 2 (41 bytes). Prefere servidor para o cliente, e regular para OSR, se você estiver após o melhor desempenho.

Regra 4: Esteja ciente dos efeitos de inicialização. Não imprimir pela primeira vez durante a sua fase de tempo, uma vez que a impressão carrega e inicializa classes. Não carregue novas classes fora da fase de aquecimento (ou fase final de relatórios), a menos que você está testando o carregamento de classe especificamente (e, nesse caso, a carga apenas as classes de teste). Regra 2 é a sua primeira linha de defesa contra tais efeitos.

Regra 5: Esteja ciente dos efeitos deoptimization e recompilação. Não tome qualquer caminho de código pela primeira vez na fase de sincronismo, porque o compilador pode lixo e recompilar o código, com base em uma suposição otimista anteriormente que o caminho não estava indo para ser usado em tudo. Regra 2 é a sua primeira linha de defesa contra tais efeitos.

Regra 6: Usar ferramentas apropriadas para ler a mente do compilador, e esperar para ser surpreendido pelo código que produz. Inspecionar o código você mesmo antes de formar teorias sobre o que faz algo mais rápido ou mais lento.

Regra 7: Reduzir o ruído em suas medições. Executar o seu ponto de referência em uma máquina silenciosa e executá-lo várias vezes, descartando valores discrepantes. Use -Xbatch para serializar o compilador com o aplicativo, e considerar a criação -XX:CICompilerCount=1 para evitar o compilador de correr em paralelo com a própria. Tente o seu melhor para reduzir GC sobrecarga, Xmx set (grande o suficiente) é igual Xms e usar UseEpsilonGC se está disponível.

Regra 8: Use uma biblioteca para o seu ponto de referência, uma vez que é, provavelmente, mais eficiente e já foi depurado para este único propósito. Tais como JMH , Caliper ou Bill e de Paulo Excelente UCSD Benchmarks para Java .

Outras dicas

Eu sei que esta questão tem sido marcada como respondida, mas eu queria mencionar duas bibliotecas que nos ajudam a escrever micro benchmarks

Caliper do Google

Introdução tutoriais

  1. http://codingjunkie.net/micro-benchmarking-with-caliper/
  2. http://vertexlabs.co.uk/blog/caliper

JMH do OpenJDK

Introdução tutoriais

  1. Evitando benchmarking Armadilhas na JVM
  2. http://nitschinger.at/Using-JMH-for-Java-Microbenchmarking
  3. http://java-performance.info/jmh/

coisas importantes para benchmarks Java são:

  • Aqueça o JIT primeiro executando o código várias vezes antes do tempo que
  • Certifique-se de executá-lo por tempo suficiente para ser capaz de medir os resultados em segundos, ou (melhor) dezenas de segundos
  • Embora você não pode chamar System.gc() entre iterações, é uma boa idéia para executá-lo entre os testes, de modo que cada teste, esperamos obter um espaço de memória "limpa" para trabalhar. (Sim, gc() é mais uma dica do que uma garantia, mas é muito provável que ele realmente vai coleta de lixo na minha experiência.)
  • Eu gosto de iterações de exibição e tempo, e uma pontuação de tempo / iteração que pode ser dimensionado de tal forma que o "melhor" algoritmo recebe uma pontuação de 1,0 e os outros são marcados de uma forma relativa. Isto significa que você pode executar todas algoritmos para um momento comprido, variando tanto o número de iterações e tempo, mas ainda assim obter resultados comparáveis.

Eu sou apenas no processo de blogar sobre a concepção de um quadro de benchmarking em .NET. Eu tenho um casal de anteriormente mensagens que pode ser capaz de lhe dar algumas idéias - nem tudo será apropriado, é claro, mas alguns dos que podem ser

.

jmh é uma adição recente ao OpenJDK e foi escrito por alguns engenheiros de desempenho da Oracle. Certamente vale uma olhada.

O jmh é um arnês de Java para a construção, execução e análise nano / micro / benchmarks macro escrito em Java e outras linguagens o objectivo da JVM.

peças muito interessantes de informações enterradas em os testes de amostras comentários .

Veja também:

Caso a referência medida do tempo / iteração ou iterações / hora, e por quê?

Depende o que você está tentando teste.

Se você está interessado em latência , o tempo de uso / iteração e se você estiver interessado em taxa de transferência , de uso iterações / hora.

Certifique-se de alguma forma utilizar os resultados que são computados no código aferido. Caso contrário, seu código pode ser otimizado de distância.

Se você está tentando comparar dois algoritmos, fazer pelo menos dois pontos de referência para cada, alternando a ordem. ou seja:.

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

Eu encontrei algumas diferenças visíveis (5-10% às vezes) no tempo de execução do mesmo algoritmo em diferentes passes ..

Além disso, certifique-se de que n é muito grande, de modo que o tempo de execução de cada ciclo é, no mínimo, 10 segundos ou assim. Os mais iterações, as figuras mais significativas no seu tempo de referência eo mais confiável que os dados estão.

Existem muitas armadilhas possíveis para escrever micro-benchmarks em Java.

Primeiro: você tem que calcular com todos os tipos de eventos que levam tempo mais ou menos aleatória:. Coleta de lixo, efeitos (de OS para arquivos e de CPU para a memória) cache, IO etc

Em segundo lugar:. Você não pode confiar na precisão dos tempos medidos para intervalos muito curtos

Terceiro: O JVM otimiza seu código durante a execução. Então corridas diferentes no mesmo JVM instância se tornará mais e mais rápido.

As minhas recomendações: Faça a sua referência executar alguns segundos, que é mais confiável do que um tempo de execução mais de milissegundos. Aquecer as JVM (meios que executam o valor de referência, pelo menos uma vez sem medição, que a JVM pode executar optimizações). E executar o seu ponto de referência várias vezes (talvez 5 vezes) e tomar o valor mediano. Executar a cada micro-referência em uma nova JVM-instância (chamada para cada ponto de referência novo Java), caso contrário otimização efeitos da JVM pode influenciar testes mais tarde em execução. Não execute as coisas, que não são executadas na fase de aquecimento (como isso poderia desencadear classe de carga e recompilação).

Além disso, deve-se notar que ele também pode ser importante para analisar os resultados do micro referência quando se comparam diferentes implementações. Portanto, um significado teste deve ser feita.

Isso ocorre porque implementação A pode ser mais rápido durante a maior parte das corridas do benchmark de B implementação. Mas A também pode ter um spread mais elevado, de modo que o benefício de desempenho medido de A não será de qualquer significado quando comparado com B.

Por isso, também é importante para escrever e executar um micro referência corretamente, mas também para analisá-lo corretamente.

http://opt.sourceforge.net/ benchmark Java Micro - tarefas de controle necessário para determinar o comparativa características de desempenho do sistema de computador em diferentes plataformas. Pode ser usado para orientar as decisões de otimização e comparar diferentes implementações de Java.

Para adicionar para o outro conselho excelente, eu também estar atentos ao seguinte:

Para alguns processadores (por exemplo Intel Core i5 gama com TurboBoost), a temperatura (e o número de núcleos actualmente a ser utilizados, bem como ao melhor por cento de utilização) afecta a velocidade do relógio. Desde CPUs estão com clock dinamicamente, isso pode afetar seus resultados. Por exemplo, se você tiver um aplicativo single-threaded, a velocidade máxima de clock (com TurboBoost) é maior do que para uma aplicação utilizando todos os núcleos. Isto pode, portanto, interferir com as comparações de desempenho única e multi-threaded em alguns sistemas. Tenha em mente que a temperatura e volatages também afetar o tempo de freqüência Turbo é mantida.

Talvez um aspecto mais fundamental importância que você tem controle direto sobre: ??Certifique-se que você está medindo a coisa certa! Por exemplo, se você estiver usando System.nanoTime() de referência um pouco de código específico, colocar as chamadas para a atribuição de lugares que faz sentido para evitar medir as coisas que você não está interessado em, por exemplo, não fazer:.

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

O problema é que você não está imediatamente ficando o tempo do fim quando o código foi concluída. Em vez disso, tente o seguinte:

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top