node.js performance profiling v8 perf

node.js - Eventos desconocidos en nodejs/v8 flamegraph usando perf_events



performance profiling (2)

Intento hacer algunos perfiles de nodejs usando Linux perf_events como lo describe Brendan Gregg here .

El flujo de trabajo es el siguiente:

  1. ejecute nodo> 0.11.13 con --perf-basic-prof , que crea el archivo /tmp/perf-(PID).map donde se escribe la asignación de símbolos JavaScript.
  2. Capture pilas utilizando el perf record -F 99 -p `pgrep -n node` -g -- sleep 30
  3. Doblar pilas usando el script stackcollapse-perf.pl de this repositorio
  4. Genere el gráfico de llama svg usando el script flamegraph.pl

Obtengo el siguiente resultado (que se ve muy bien al principio):

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

¿Cómo resolver este problema?

Estoy usando CentOS 6.5 x64, y ya probé esto con el nodo 0.11.13, 0.11.14 (ambos precompilados y compilados también) sin éxito.


En primer lugar, lo que significa "[desconocido]" es que el muestreador no pudo descifrar el nombre de la función, porque es una función de sistema o biblioteca. Si es así, está bien, no le importa, porque está buscando cosas responsables del tiempo en su código, no el código del sistema.

En realidad, estoy sugiriendo 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. La creación de perfiles de CPU es de poca utilidad en un programa vinculado de E / S

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

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

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

Supongamos que hay alguna función de Foo que realmente está haciendo algo inútil, que si lo supieras, podrías arreglarlo. Supongamos que en el gráfico de la llama, es un color rojo oscuro. Supongamos que se llama desde numerosos lugares en el código, por lo que no se recopila todo en un solo lugar en el gráfico de la llama. Más bien aparece en múltiples lugares pequeños mostrados aquí con contornos negros:

Tenga en cuenta que si se recopilaron todos esos rectángulos, podría ver que representa el 11% del tiempo, lo que significa que vale la pena mirarlo. Si pudiera reducir su tiempo a la mitad, podría ahorrar 5.5% en general. Si lo que está haciendo realmente podría evitarse por completo, podría ahorrar un 11% en general. Cada uno de esos pequeños rectángulos se reduciría a la nada y arrastraría el resto del gráfico hacia la derecha.

Ahora te mostraré el método que uso . Tomo una cantidad moderada de muestras de pila al azar y examino cada una de las rutinas que podrían acelerarse. Eso corresponde a tomar muestras en el gráfico de llamas así:

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

(¿Confundido? Bien, aquí hay una pequeña probabilidad para ti. Si lanzas una moneda 20 veces y tiene un 11% de posibilidades de que salga cara, ¿cuántas caras obtendrías? Técnicamente es una distribución binomial. El número más probable es que sería 2, los siguientes números más probables son 1 y 3. (Si solo obtiene 1, continúe hasta que obtenga 2.) Aquí está la distribución :)

(El número promedio de muestras que debe tomar para ver a Foo dos veces es 2 / 0.11 = 18.2 muestras).

Mirar esas 20 muestras puede parecer un poco desalentador, porque corren entre 20 y 50 niveles de profundidad. Sin embargo, básicamente puede ignorar todo el código que no es suyo . Simplemente examínelos para su código . Verá con precisión cómo está pasando el tiempo y tendrá una medida aproximada de cuánto. Las acumulaciones profundas son malas y buenas noticias: significan que el código puede tener mucho espacio para acelerar y te muestran cuáles son.

Cualquier cosa que vea que pueda acelerar, si la 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 que, si solo lo ve en una muestra, solo sabe que su tiempo no es cero. Si lo ve en más de una muestra, aún no sabe cuánto tiempo lleva, pero sí sabe que no es pequeño. Aquí están las estadísticas.


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

SO insta a la respuesta a hacer lo siguiente:

"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 de 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 así en este caso particular. Aquí hay un problema genuino sobre cómo se procesaron los datos del registro de rendimiento.

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 que el script de perf produzca la salida esperada.

¡Eso es!

Escribiendo algunos guiones nuevos hoy, presiono sobre esto y me dirige a esta pregunta SO.

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 se pueden forzar] http://www.spinics.net/lists/linux-perf-users/msg02588.html