Eventos desconocidos en el flamógrafo nodejs / v8 utilizando perf_events

Intento hacer algunos perfiles de nodejs usando perf_events de Linux, tal como lo describe Brendan Gregg aquí .

El flujo de trabajo está siguiendo:

  1. Ejecute el nodo> 0.11.13 con --perf-basic-prof , que crea el archivo /tmp/perf-(PID).map donde se escriben los mapas de símbolos de JavaScript.
  2. Capturar stacks usando el perf record -F 99 -p `pgrep -n node` -g -- sleep 30
  3. Dobla las stacks usando el script stackcollapse-perf.pl de este repository
  4. Generar un gráfico de llama svg usando la flamegraph.pl comandos flamegraph.pl

Obtengo el resultado siguiente (que se ve muy bien al principio): enter image description here

El problema es que hay muchos elementos [unknown] , que supongo que deberían ser las llamadas a mi función nodejs. Supongo que todo el proceso falla en algún punto del punto 3, donde los datos de perforación deben plegarse usando mapeos generados por node / v8 ejecutado con --perf-basic-prof . /tmp/perf-PID.map archivo /tmp/perf-PID.map y se escriben algunas asignaciones durante la ejecución del nodo.

¿Cómo resolver este problema?

Estoy usando CentOS 6.5 x64, y ya lo intenté con el nodo 0.11.13, 0.11.14 (tanto prebuild como comstackdo) sin éxito.

En primer lugar, lo que “[desconocido]” significa es que la muestra no pudo determinar el nombre de la función, porque es un sistema o función de biblioteca. Si es así, está bien, no te importa, porque estás buscando cosas responsables del tiempo en tu código, no del código del sistema.

En realidad, sugiero que esta es una de esas preguntas XY . Incluso si obtiene una respuesta directa a lo que preguntó, es probable que sea de poca utilidad. Estas son las razones por qué:

1. El perfil de CPU es de poca utilidad en un progtwig de E / S enlazado

Las dos torres a la izquierda en su gráfico de llamas están haciendo E / S, por lo que probablemente les tome mucho más tiempo de pared que el montón grande a la derecha. Si este gráfico de llama se derivó de muestras de pared, en lugar de muestras de tiempo de CPU, podría parecerse más al segundo gráfico a continuación, que le dice a dónde va realmente el tiempo:

enter image description here

Lo que era una gran stack de aspecto jugoso en la derecha se ha reducido, por lo que no es para nada tan significativo. Por otro lado, las torres de E / S son muy amplias. Cualquiera de esas franjas anaranjadas anchas, si está en su código, representa una oportunidad de ahorrar mucho tiempo, si se pudiera evitar algo de E / S.

2. Ya sea que el progtwig esté vinculado a CPU o E / S, las oportunidades de aceleración pueden ocultarse fácilmente de los gráficos de llamas

Supongamos que hay alguna función Foo que realmente está haciendo algo inútil, que si lo supiera, podría arreglarlo. Supongamos que en el gráfico de llamas, es un color rojo oscuro. Supongamos que se llama desde numerosos lugares en el código, por lo que no se recostack en un solo punto en el gráfico de llama. Más bien aparece en varios lugares pequeños que se muestran aquí con líneas negras:

enter image description here

Tenga en cuenta que, si se recogieron todos esos rectangularjs, podría ver que representan el 11% del tiempo, lo que significa que vale la pena mirar. Si pudieras reducir su tiempo a la mitad, podrías ahorrar un 5.5% en total. Si lo que está haciendo en realidad podría evitarse por completo, podría ahorrar un 11% en general. Cada uno de esos pequeños rectangularjs se reduciría a nada y arrastraría el rest del gráfico, a la derecha, con él.

Ahora te mostraré el método que uso . Tomo una cantidad moderada de muestras de conjuntos aleatorios y examino cada una de las rutinas que pueden acelerarse. Eso corresponde a tomar muestras en el gráfico de llama de esta manera:

enter image description here

Las líneas verticales delgadas representan veinte muestras de astackmiento en tiempo aleatorio. Como puede ver, tres de ellos están marcados con una X. Esos son los que pasan por Foo . Ese es aproximadamente el número correcto, porque 11% por 20 es 2.2.

(¿Confuso? Bien, aquí hay una pequeña probabilidad para ti. Si lanzas una moneda 20 veces y tienes un 11% de posibilidades de ganar cabeza, ¿cuántas cabezas obtendrías? Técnicamente es una distribución binomial. El número más probable es obtendría es 2, los siguientes números más probables son 1 y 3. (Si solo obtienes 1, sigues hasta obtener 2.) Aquí está la distribución 🙂

enter image description here

(La cantidad promedio de muestras que debe tomar para ver a Foo dos veces es 2 / 0.11 = 18.2 muestras).

Ver esas 20 muestras puede parecer un poco desalentador, ya que tienen una profundidad de entre 20 y 50 niveles. Sin embargo, básicamente puedes ignorar todo el código que no es tuyo . Solo examínalos por tu código . Verá exactamente cómo está pasando el tiempo, y tendrá una medida muy aproximada de cuánto. Los stacks profundos son malas noticias y buenas noticias; significan que el código puede tener mucho espacio para las aceleraciones, y te muestran cuáles son.

Cualquier cosa que vea que pueda acelerar, si lo ve en más de una muestra , le dará una aceleración saludable, garantizada. La razón por la que necesita verlo en más de una muestra es, si solo lo ve en una muestra, solo sabe que su tiempo no es cero. Si lo ves en más de una muestra, aún no sabes cuánto tiempo lleva, pero sabes que no es pequeño. Aquí están las estadísticas.

En términos generales, es una mala idea no estar de acuerdo con un experto en la materia, pero (con el mayor respeto) ¡aquí vamos!

SO solicita la respuesta para hacer lo siguiente:

“Por favor, asegúrese de responder la pregunta. Proporcione detalles y comparta su investigación”.

Entonces, la pregunta era, al menos mi interpretación de esto es, ¿por qué hay marcos [desconocidos] en la salida del script perf (y cómo convierto estos marcos [desconocidos] en nombres significativos)? Esta pregunta podría ser sobre “cómo mejorar el rendimiento de mi sistema” pero no lo veo de esa manera en este caso particular. Aquí hay un problema genuino acerca de cómo los datos de registro de perforación se han procesado posteriormente.

La respuesta a la pregunta es que, aunque la configuración de requisitos previos es correcta: la versión de nodo correcta, el argumento correcto estaba presente para generar los nombres de las funciones (–perf-basic-prof), el archivo de mapa de rendimiento generado debe ser propiedad de root para perf script para producir el resultado esperado.

¡Eso es!

Al escribir algunos guiones nuevos hoy, apunto a apon que esto me dirige a esta pregunta ASÍ.

Aquí hay un par de referencias adicionales:

https://yunong.io/2015/11/23/generating-node-js-flame-graphs/

https://github.com/jrudolph/perf-map-agent/blob/d8bb58676d3d15eeaaf3ab3f201067e321c77560/bin/create-java-perf-map.sh#L22

[Los archivos no root a veces pueden forzarse] http://www.spinics.net/lists/linux-perf-users/msg02588.html