Perfilando Ruby Code
profiling profiler (4)
Esta es mi propia pregunta, pero encontré una herramienta que es tan sorprendente para crear perfiles que tengo que agregarla aquí:
http://samsaffron.com/archive/2013/03/19/flame-graphs-in-ruby-miniprofiler
Los flamígrafos hacen que la fuente de problemas de rendimiento sea sorprendentemente obvia , en relación con los retrocesos.
Además de ruby-prof y la clase principal de Benchmark, ¿qué usas para perfilar tu código de Ruby? En particular, ¿cómo encuentra los cuellos de botella en su código? Casi siento que necesito trabajar en mi propia pequeña herramienta solo para descubrir en qué parte del código se está gastando todo el tiempo.
Me doy cuenta de que ruby-prof proporciona esto, pero la salida es francamente muy confusa y no hace que sea fácil descubrir qué bloques reales de su propio código son la fuente del problema (le informa sobre qué método tomó las llamadas más tiempo) aunque). Así que realmente no estoy sacando tanto de lo que me gustaría, y realmente no he podido usarlo.
Tal vez lo estoy haciendo mal? ¿Hay alternativas? Las búsquedas en Google no me muestran nada.
Muchos perfiladores son así. Lo que necesita saber no es dónde el programa gasta su tiempo, sino por qué . ¿Alguna referencia en Dynamic Code Analysis?
AÑADIDO: Así es como encuentro "cuellos de botella" en mi código. (Odio esa palabra.) Aquí hay una lista de razones por las que.
Es perfectamente natural suponer que para encontrar "cuellos de botella" hay que medir mucho. Es tan natural que casi todos los perfiladores se basan en ello.
En realidad, encontrar y medir no son el mismo problema. Es necesario medir para ver si lo que encontró (y reparó) hizo una diferencia. Encontrar qué arreglar, para mí, es más como depurar que medir.
La forma más sencilla de explicarlo es comenzar desde un bucle infinito o casi infinito. ¿Cómo lo encuentras? Lo detienes y miras la pila, ¿verdad? porque sabes que el problema está en algún lugar de la pila. Solo necesita pausarlo una vez, y luego necesita estudiar el código en la pila. Pausa unas cuantas veces si quieres estar seguro de haberlo encontrado.
Supongamos que el código solo toma el doble del tiempo necesario. Eso significa que cuando lo pausas, hay un 50% de probabilidad de que lo veas haciendo algo innecesario. Si lo pausas y lo miras 10 veces, lo atraparás en el acto aproximadamente 5 veces. De hecho, tan pronto como lo ve haciendo algo que puede optimizar en tan solo 2 muestras, ha encontrado un "cuello de botella". Repárelo, mida la aceleración, muéstrelo y repita.
Incluso si su mayor problema no es muy grande, este método eventualmente lo encontrará. Además, hay un fenómeno de ampliación, donde los problemas pequeños se vuelven más fáciles de encontrar después de haber eliminado los más grandes. Eso te permite continuar hasta que el código sea casi óptimo.
PD: después de haber hecho esto, es posible que todavía haya oportunidades para acelerar. Por ejemplo, los algoritmos de optimización pueden depender de la estabilidad numérica. Las arquitecturas dirigidas por mensajes pueden hacer que sea más difícil rastrear por qué se está ejecutando el código. En el software en tiempo real, un problema de rendimiento solo puede ocurrir ocasionalmente y ser menos fácil de probar. Esto requiere más inteligencia. Caer de nuevo en la medición no lo hace.
Para realmente profundizar en su código, pruebe stackprof .
Aquí hay una solución rápida sobre cómo usarlo: Instale la gema: gem install stackprof
. En su código, agregue: require ''stackprof''
y rodee la parte que desea verificar con esto:
StackProf.run(mode: :cpu, out: ''stackprof-output.dump'') do {YOUR_CODE} end
Después de ejecutar su script ruby, verifique la salida en el terminal con stackprof stackprof.dump
:
Mode: cpu(1000)
Samples: 9145 (1.25% miss rate)
GC: 448 (4.90%)
TOTAL (pct) SAMPLES (pct) FRAME
236 (2.6%) 231 (2.5%) String#blank?
546 (6.0%) 216 (2.4%) ActiveRecord::ConnectionAdapters::Mysql2Adapter#select
212 (2.3%) 199 (2.2%) Mysql2::Client#query_with_timing
190 (2.1%) 155 (1.7%) ERB::Util#html_escape``
Aquí puedes ver todos tus métodos que requieren mucho tiempo. Ahora, la parte más stackprof stackprof.dump --method String#blank?
: ¿Para obtener detalles solo haga stackprof stackprof.dump --method String#blank?
y obtienes la salida para el método específico:
String#blank? (lib/active_support/core_ext/object/blank.rb:80)
samples: 231 self (2.5%) / 236 total (2.6%)
callers:
112 ( 47.5%) Object#present?
code:
| 80 | def blank?
187 (2.0%) / 187 (2.0%) | 81 | self !~ /[^[:space:]]/
| 82 | end
Y puede descubrir fácilmente qué parte de su código tarda mucho tiempo en ejecutarse.
Si desea obtener una salida visual, stackprof stackprof.dump --graphviz >> stackprof.dot
y use graphviz ( brew install graphviz
) dot- T pdf -o stackprof.pdf stackprof.dot
obtenga un hermoso PDF, que resalta Métodos que tardan mucho tiempo en ejecutarse.
También hay ruby -rprofile
o equivalente de la fuente de Ruby, require ''profile''
Documentación:
https://ruby-doc.org/stdlib-2.1.0/libdoc/profiler/rdoc/Profiler__.html