¿Cuál es una forma estándar de perfilar las llamadas al método Scala?
Lo que necesito son ganchos en torno a un método, que puedo usar para iniciar y detener temporizadores.
En Java uso la programación de aspectos, aspectJ, para definir los métodos a perfilar e inyectar bytecode para lograr lo mismo.
¿Existe una forma más natural en Scala, donde puedo definir un montón de funciones para ser llamadas antes y después de una función sin perder ninguna escritura estática en el proceso?
Respuestas:
¿Quiere hacer esto sin cambiar el código para el que quiere medir tiempos? Si no le importa cambiar el código, puede hacer algo como esto:
fuente
t1
dentro de unafinally
cláusuladef time[R](label: String)(block: => R): R = {
luego agregue la etiqueta alprintln
Además de la respuesta de Jesper, puede ajustar automáticamente las invocaciones de métodos en el REPL:
Ahora - envuelvamos cualquier cosa en esto
OK, tenemos que estar en modo de energía
Envolver
No tengo idea de por qué eso imprimió 5 veces
Actualización a partir de la 2.12.2:
fuente
:wrap
función se eliminó del REPL: - \Hay tres bibliotecas de evaluación comparativa para Scala de las que puede hacer uso.
Dado que es probable que cambien las URL del sitio vinculado, a continuación pegaré el contenido relevante.
SPerformance : marco de pruebas de rendimiento destinado a comparar automáticamente las pruebas de rendimiento y trabajar dentro de Simple Build Tool.
scala-benchmarking-template : proyecto de plantilla SBT para crear (micro) puntos de referencia Scala basados en Caliper.
Métricas : captura de métricas de JVM y de nivel de aplicación. Entonces sabes lo que esta pasando
fuente
Esto es lo que uso:
fuente
testing.Benchmark
podría ser útil.fuente
Tomé la solución de Jesper y le agregué algo de agregación en múltiples ejecuciones del mismo código
Suponga que desea cronometrar dos funciones
counter_new
ycounter_old
el siguiente es el uso:Espero que esto sea útil
fuente
Utilizo una técnica que es fácil de mover en bloques de código. El quid es que la misma línea exacta inicia y finaliza el temporizador, por lo que es realmente una simple copia y pegado. La otra cosa buena es que puedes definir lo que significa la sincronización para ti como una cadena, todo en la misma línea.
Uso de ejemplo:
El código:
Pros:
Contras:
fuente
Timelog.timer("timer name/description")
:?ScalaMeter es una buena biblioteca para realizar evaluaciones comparativas en Scala
A continuación se muestra un ejemplo sencillo
Si ejecuta el fragmento de código anterior en la hoja de trabajo de Scala, obtiene el tiempo de ejecución en milisegundos
fuente
Me gusta la simplicidad de la respuesta de @ wrick, pero también quería:
el perfilador maneja el bucle (para mayor consistencia y conveniencia)
sincronización más precisa (usando nanoTime)
tiempo por iteración (no tiempo total de todas las iteraciones)
solo devuelve ns / iteración, no una tupla
Esto se logra aquí:
Para una mayor precisión, una simple modificación permite un ciclo de calentamiento de JVM Hotspot (no cronometrado) para cronometrar pequeños fragmentos:
fuente
El enfoque recomendado para la evaluación comparativa del código Scala es a través de sbt-jmh
Este enfoque es adoptado por muchos de los principales proyectos de Scala, por ejemplo,
El temporizador de contenedor simple basado en no
System.nanoTime
es un método confiable de evaluación comparativa:Además, consideraciones como el calentamiento de JIT , la recolección de basura, los eventos de todo el sistema, etc. pueden introducir imprevisibilidad en las mediciones:
Basado en la respuesta de Travis Brown, aquí hay un ejemplo de cómo configurar el punto de referencia JMH para Scala
project/plugins.sbt
build.sbt
añadir
src/main/scala/bench/VectorAppendVsListPreppendAndReverse.scala
Los resultados son
lo que parece indicar que anteponer a a
List
y luego invertirlo al final es un orden de magnitud más rápido que seguir añadiendo a aVector
.fuente
Mientras está de pie sobre los hombros de gigantes ...
Una biblioteca sólida de terceros sería más ideal, pero si necesita algo rápido y basado en una biblioteca estándar, la siguiente variante proporciona:
.
También vale la pena señalar que puede usar el
Duration.toCoarsest
método para convertir a la unidad de tiempo más grande posible, aunque no estoy seguro de cuán amigable es esto con una pequeña diferencia de tiempo entre ejecuciones, por ejemplofuente
Puede utilizar
System.currentTimeMillis
:Uso:
nanoTime te lo mostrará
ns
, por lo que será difícil de ver. Entonces sugiero que pueda usar currentTimeMillis en lugar de él.fuente