Qual é a maneira padrão de criar perfil de chamadas de método Scala?
O que eu preciso são ganchos em torno de um método, usando o qual posso usar para iniciar e parar os cronômetros.
Em Java, eu uso a programação de aspecto, aspectJ, para definir os métodos a serem traçados e injetar bytecode para conseguir o mesmo.
Existe uma maneira mais natural em Scala, onde posso definir um monte de funções a serem chamadas antes e depois de uma função sem perder qualquer tipo de estática no processo?
Respostas:
Deseja fazer isso sem alterar o código para o qual deseja medir os tempos? Se você não se importa em alterar o código, pode fazer algo assim:
fonte
t1
dentro de umafinally
cláusuladef time[R](label: String)(block: => R): R = {
seguida, adicione o rótulo aoprintln
Além da resposta de Jesper, você pode envolver automaticamente invocações de método no REPL:
Agora - vamos embrulhar qualquer coisa neste
OK - precisamos estar no modo de energia
Embrulhar
Não tenho ideia do por que isso imprimiu 5 vezes
Atualização a partir de 2.12.2:
fonte
:wrap
recurso foi removido do REPL: - \Existem três bibliotecas de benchmarking para Scala que você pode aproveitar.
Como os URLs do site vinculado provavelmente serão alterados, estou colando o conteúdo relevante abaixo.
SPerformance - framework de teste de desempenho que tem como objetivo comparar os testes de desempenho de forma automática e mágica e trabalhar dentro da ferramenta Simple Build.
scala-benchmarking-template - Projeto de template SBT para a criação de benchmarks Scala (micro) baseados no Caliper.
Métricas - captura de métricas de nível de aplicativo e JVM. Então você sabe o que está acontecendo
fonte
Isso é o que eu uso:
fonte
testing.Benchmark
pode ser útil.fonte
Peguei a solução de Jesper e adicionei alguma agregação a ela em várias execuções do mesmo código
Suponha que você queira cronometrar duas funções
counter_new
ecounter_old
, o seguinte é o uso:Espero que isso seja útil
fonte
Eu uso uma técnica que é fácil de mover em blocos de código. O ponto crucial é que a mesma linha exata inicia e termina o cronômetro - portanto, é realmente um simples copiar e colar. A outra coisa boa é que você consegue definir o que o tempo significa para você como uma string, tudo na mesma linha.
Exemplo de uso:
O código:
Prós:
Contras:
fonte
Timelog.timer("timer name/description")
:?ScalaMeter é uma boa biblioteca para realizar benchmarking em Scala
Abaixo está um exemplo simples
Se você executar o trecho de código acima na planilha Scala, você obterá o tempo de execução em milissegundos
fonte
Gosto da simplicidade da resposta de @wrick, mas também queria:
o criador de perfil lida com o loop (para consistência e conveniência)
tempo mais preciso (usando nanoTime)
tempo por iteração (não o tempo total de todas as iterações)
apenas retorna ns / iteração - não uma tupla
Isso é feito aqui:
Para ainda mais precisão, uma modificação simples permite um loop de aquecimento JVM Hotspot (não cronometrado) para cronometrar pequenos snippets:
fonte
A abordagem recomendada para comparar o código do Scala é via sbt-jmh
Essa abordagem é adotada por muitos dos principais projetos Scala, por exemplo,
O temporizador de invólucro simples baseado em não
System.nanoTime
é um método confiável de comparação:Além disso, considerações como aquecimento JIT , coleta de lixo, eventos de todo o sistema, etc. podem introduzir imprevisibilidade nas medições:
Com base na resposta de Travis Brown, aqui está um exemplo de como configurar o benchmark JMH para Scala
project/plugins.sbt
build.sbt
adicionar à
src/main/scala/bench/VectorAppendVsListPreppendAndReverse.scala
Os resultados são
o que parece indicar que preceder a a
List
e então invertê-lo no final é uma ordem de magnitude mais rápido do que continuar acrescentando a aVector
.fonte
Enquanto estava sobre os ombros de gigantes ...
Uma biblioteca de terceiros sólida seria mais ideal, mas se você precisar de algo rápido e baseado em biblioteca padrão, a seguinte variante fornece:
.
Também vale a pena notar que você pode usar o
Duration.toCoarsest
método para converter para a maior unidade de tempo possível, embora eu não tenha certeza de como isso é amigável com uma pequena diferença de tempo entre as execuções, por exemplofonte
Você pode usar
System.currentTimeMillis
:Uso:
nanoTime irá mostrar a você
ns
, então será difícil de ver. Portanto, sugiro que você possa usar currentTimeMillis em vez dele.fonte