Más allá de Stack Sampling: Perfiladores C ++

Un cuento de hacker

La fecha es 12/02/10. Los días previos a la Navidad están goteando y he llegado a un gran bloque de carreteras como progtwigdor de Windows. He estado usando AQTime, he probado sueño, brillo y tengo mucho sueño, y mientras hablamos, VTune se está instalando. Intenté usar el generador de perfiles VS2008, y ha sido muy castigador y a menudo insensible. He usado la técnica de pausa aleatoria. He examinado los árboles de llamada. He disparado los rastros de funciones. Pero el triste hecho doloroso del asunto es que la aplicación con la que estoy trabajando es más de un millón de líneas de código, probablemente con otras millones de líneas de aplicaciones de terceros.

Necesito mejores herramientas. He leído los otros temas. Probé cada perfilador que figura en cada tema. Simplemente tiene que haber algo mejor que estas opciones caprichosas y caras, o cantidades ridículas de trabajo casi sin ganancia. Para complicar aún más las cosas, nuestro código tiene muchos subprocesos y ejecuta una serie de bucles de eventos Qt, algunos de los cuales son tan frágiles que chocan bajo instrumentación pesada debido a retrasos en el tiempo. No me preguntes por qué estamos ejecutando múltiples bucles de eventos. Nadie me puede decir

¿Hay alguna opción más en la línea de Valgrind en un entorno de Windows?
¿Hay algo mejor que la larga franja de herramientas rotas que ya he probado?
¿Hay algo diseñado para integrarse con Qt, quizás con una útil visualización de eventos en la cola?

Una lista completa de las herramientas que probé, con las que fueron realmente útiles en cursiva:

  • AQTime: bastante bien! Tiene algunos problemas con la recursión profunda, pero el gráfico de llamadas es correcto en estos casos y se puede usar para aclarar cualquier confusión que pueda tener. No es una herramienta perfecta, pero vale la pena probarlo. Puede adaptarse a sus necesidades, y sin duda fue lo suficientemente bueno para mí la mayor parte del tiempo.
  • Ataque de Pausa Aleatoria en modo de depuración: No hay suficiente información suficiente del tiempo.
    Una buena herramienta pero no una solución completa.
  • Parallel Studios: la opción nuclear. Obtrusivo, raro y locamente poderoso. Creo que deberías ir a la evaluación de 30 días y descubrir si encaja bien. Es simplemente genial, también.
  • Codeanalista de AMD: Maravilloso, fácil de usar, propenso a colisiones, pero creo que eso es algo del entorno. Recomiendo probarlo, ya que es gratis.
  • Luke Stackwalker: Funciona bien en proyectos pequeños, es un poco tratando de hacerlo funcionar en los nuestros. Algunos buenos resultados, sin embargo, reemplazan a Sleepy para mis tareas personales.
  • PurifyPlus: No es compatible con entornos Win-x64, el más prominente es Windows 7. De lo contrario, es excelente. Varios de mis colegas en otros departamentos lo juran.
  • Perfilador VS2008: Produce salida en el rango de 100 + gigs en el modo de rastreo de funciones a la resolución requerida. En el lado positivo, produce resultados sólidos.
  • GProf: Requiere que GCC sea incluso moderadamente efectivo.
  • VTune: el W7 de VTune admite fronteras criminales. De lo contrario excelente
  • PIN: Tendría que hackear mi propia herramienta, así que esto es una especie de último recurso.
  • Sleepy \ VerySleepy: Útil para aplicaciones más pequeñas, pero fallando aquí.
  • EasyProfiler: no está mal si no te importa un poco de código de inyección manual para indicar dónde instrumentar.
  • Valgrind: * nix solamente, pero muy bueno cuando estás en ese entorno.
  • OProfile: solo Linux.
  • Proffy: Disparan caballos salvajes.

Herramientas sugeridas que no he probado:

  • XPerf:
  • Glowcode:
  • Devpartner:

Notas: entorno Intel en este momento. VS2008, aumenta las bibliotecas. Qt 4+. Y el humdinger miserable de todos ellos: la integración de Qt / MFC a través de trolltech.


Ahora: casi dos semanas después, parece que mi problema está resuelto. Gracias a una variedad de herramientas, que incluyen casi todo en la lista y algunos de mis trucos personales, encontramos los principales cuellos de botella. Sin embargo, voy a seguir probando, explorando y probando nuevos perfiladores y nuevas tecnologías. ¿Por qué? Porque se lo debo a ustedes, porque ustedes rockearon. Reduce un poco la línea de tiempo, pero todavía estoy muy emocionado de seguir probando nuevas herramientas.

Sinopsis
Entre muchos otros problemas, varios componentes se cambiaron recientemente al modelo de subprocesamiento incorrecto, causando graves problemas debido al hecho de que el código subyacente de repente ya no era multiproceso. No puedo decir más porque viola mi NDA, pero puedo decirle que esto nunca se habría encontrado mediante una inspección casual o incluso mediante una revisión normal del código. Sin perfiladores, callgraphs y pausas aleatorias en conjunto, todavía estaríamos gritando nuestra furia en el hermoso arco azul del cielo. Afortunadamente, trabajo con algunos de los mejores hackers que he conocido, y tengo acceso a un increíble ‘verso lleno de excelentes herramientas y grandes personas.

Gentlefolk, aprecio esto tremendamente, y solo lamento que no tengo suficiente representante para recompensar a cada uno de ustedes con una recompensa. Sigo pensando que esta es una pregunta importante para obtener una mejor respuesta de la que obtuvimos hasta ahora.

Como resultado, cada semana durante las próximas tres semanas, voy a poner la mayor recompensa que me puedo permitir, y adjudicarla a la respuesta con la mejor herramienta que creo que no es de conocimiento común. Después de tres semanas, esperamos haber acumulado un perfil definitivo de los perfiladores, si perdonas mis juegos de palabras.

Para llevar
Use un perfilador. Son lo suficientemente buenos para Ritchie, Kernighan, Bentley y Knuth. No me importa quién crees que eres. Use un perfilador. Si el que tienes no funciona, encuentra otro. Si no puede encontrar uno, codifique uno. Si no puede codificar uno, o es un pequeño cuelgue, o simplemente está bloqueado, use la pausa aleatoria. Si todo lo demás falla, contrata a algunos estudiantes de posgrado para sacar un generador de perfiles.


Una vista más larga
Entonces, pensé que sería bueno escribir un poco de una retrospectiva. Opté por trabajar extensamente con Parallel Studios, en parte porque en realidad está construido sobre la herramienta PIN. Habiendo tenido relaciones académicas con algunos de los investigadores involucrados, sentí que esta era probablemente una marca de cierta calidad. Afortunadamente, tenía razón. Si bien la GUI es un poco espantosa, encontré que IPS es increíblemente útil, aunque no puedo recomendarlo cómodamente para todos. Críticamente, no hay una forma obvia de obtener recuentos de aciertos a nivel de línea, algo que AQT y otros perfiladores proporcionan, y me ha resultado muy útil para examinar la tasa de selección de sucursales, entre otras cosas. En red, también he disfrutado usando AQ Time, y he encontrado que su apoyo es realmente receptivo. Una vez más, tengo que calificar mi recomendación: muchas de sus características no funcionan tan bien, y algunas de ellas son francamente propensas a los lockings en Win7x64. XPerf también se desempeñó admirablemente, pero es agonizantemente lento para los detalles de muestreo necesarios para obtener buenas lecturas en ciertos tipos de aplicaciones.

En este momento, tendría que decir que no creo que haya una opción definitiva para crear un perfil de código C ++ en un entorno W7x64, pero ciertamente hay opciones que simplemente no pueden realizar ningún servicio útil.

Primero:

Los perfiladores de muestreo de tiempo son más robustos que los perfiladores de muestreo de CPU. No estoy muy familiarizado con las herramientas de desarrollo de Windows, así que no puedo decir cuáles son cuáles. La mayoría de los perfiladores son muestras de CPU.

Un perfilador de muestreo de CPU toma un rastro de stack cada N instrucciones.
Esta técnica revelará porciones de su código que están vinculadas a la CPU. Lo cual es increíble si ese es el cuello de la botella en su aplicación. No es tan bueno si los hilos de su aplicación pasan la mayor parte de su tiempo peleando por un mutex.

Un perfilador de muestreo de tiempo captura un rastreo de stack cada N microsegundos.
Esta técnica se centrará en el código “lento” . Si la causa está vinculada a la CPU, bloqueando IO bound, mutex bound o cache thrashing secciones de código. En resumen, lo que cada vez que el código está ralentizando su aplicación se destacará.

Por lo tanto, utilice un perfilador de muestreo de tiempo si es posible, especialmente cuando perfila código enhebrado.

Segundo:

Los perfiladores de muestreo generan cantidades de datos. La información es extremadamente útil, pero a menudo es demasiado para ser fácilmente útil. Un visualizador de datos de perfil ayuda tremendamente aquí. La mejor herramienta que he encontrado para la visualización de datos de perfil es gprof2dot . No deje que el nombre lo engañe, maneja todo tipo de resultados del generador de perfiles (AQtime, Sleepy, XPerf, etc.). Una vez que la visualización ha señalado la (s) función (es) ofensiva (s), regrese a los datos brutos del perfil para obtener mejores pistas sobre cuál es la verdadera causa.

La herramienta gprof2dot genera una descripción de gráfico de puntos que luego ingresa en una herramienta graphviz . La salida es básicamente un callgraph con funciones codificadas por color por su impacto en la aplicación. texto alternativo

Algunos consejos para obtener gprof2dot para generar un buen resultado.

  • Utilizo un --skew de 0.001 en mis gráficos para que pueda ver fácilmente las rutas de los códigos de acceso. De lo contrario, int main() domina el gráfico.
  • Si estás haciendo algo loco con las plantillas de C ++, probablemente quieras agregar --strip . Esto es especialmente cierto con Boost.
  • Yo uso OProfile para generar mis datos de muestreo. Para obtener un buen resultado, necesito configurarlo para cargar los símbolos de depuración de mis bibliotecas de terceros y del sistema. Asegúrate de hacer lo mismo, de lo contrario verás que CRT está tomando el 20% del tiempo de tu aplicación cuando lo que realmente está sucediendo es que malloc está destrozando el montón y comiendo un 15%.

¿Qué pasó cuando intentaste pausar al azar? Lo uso todo el tiempo en una aplicación de monstruos. Dijiste que no proporcionabas suficiente información y que sugeriste que necesitas una resolución alta. A veces las personas necesitan un poco de ayuda para entender cómo usarlo.

Lo que hago, en VS, es configurar la pantalla de la stack para que no me muestre los argumentos de la función, porque eso hace que la pantalla de la stack sea totalmente ilegible, IMO.

Luego tomo aproximadamente 10 muestras presionando “pausa” durante el tiempo que me hace esperar . Yo uso ^ A, ^ C y ^ V para copiarlos en el bloc de notas, como referencia. Luego estudio cada uno, para tratar de descubrir qué era lo que estaba tratando de lograr en ese momento.

Si estaba tratando de lograr algo en 2 o más muestras, y eso no es estrictamente necesario, entonces he encontrado un problema en vivo, y sé aproximadamente cuánto lo va a ahorrar.

Hay cosas que realmente no necesita saber, como porcentajes precisos que no son importantes, y lo que sucede dentro del código de terceros no es importante, porque no puede hacer nada al respecto. De lo que puede hacer algo es con el amplio conjunto de puntos de llamada en el código que puede modificar que se muestran en cada muestra de stack. Esa es tu tierra de caza feliz.

Ejemplos de los tipos de cosas que encuentro:

  • Durante el inicio, puede tener unas 30 capas de profundidad, en el proceso de tratar de extraer cadenas de caracteres internacionalizadas de recursos de DLL. Si se examinan las cadenas reales, puede resultar que las cadenas realmente no necesitan ser internacionalizadas, como cadenas que el usuario nunca ve realmente.

  • Durante el uso normal, algún código establece inocentemente una propiedad Modificada en algún objeto. Ese objeto proviene de una superclase que captura el cambio y activa notificaciones que se propagan a lo largo de toda la estructura de datos, manipulando la interfaz de usuario, creando y deshaciendo obedeciendo de maneras difíciles de prever. Esto puede pasar mucho, las consecuencias inesperadas de las notificaciones.

  • Completar una hoja de trabajo fila por fila, celda por celda. Resulta que si construyes la fila de una vez, a partir de una matriz de valores, es mucho más rápido.

PD: si tiene varios subprocesos, cuando lo pausa, todos los subprocesos se detienen. Eche un vistazo a la stack de llamadas de cada hilo. Lo más probable es que solo uno de ellos sea el verdadero culpable, y los otros estén al ralentí.

He tenido cierto éxito con AMD CodeAnalyst .

¿Tiene una función MFC OnIdle? En el pasado, tuve que arreglar una aplicación casi en tiempo real que arrojaba paquetes seriales cuando se configuraba a una velocidad de 19.2K que un PentiumD debería haber podido mantener al día. La función OnIdle era lo que estaba matando cosas. No estoy seguro de si QT tiene ese concepto, pero también verificaría eso.

Re the VS Profiler: si está generando archivos tan grandes, ¿quizás su intervalo de muestreo es demasiado frecuente? Intenta bajarlo, ya que probablemente tengas suficientes muestras de todos modos.

E idealmente, asegúrese de no recolectar muestras hasta que esté ejercitando el área problemática. Comience con la colección detenida, haga que su progtwig haga su “actividad lenta” y luego comience la recostackción. Solo necesitas como máximo 20 segundos de colección. Detener la colección después de esto.

Esto debería ayudar a reducir el tamaño de los archivos de muestra y solo capturar lo que es necesario para su análisis.

He utilizado con éxito PurifyPlus para Windows. Aunque no es barato, IBM ofrece una versión de prueba que está ligeramente paralizada. Todo lo que necesita para perfilar con cuantificar son los archivos pdb y los enlaces con / FIJO: NO. Único inconveniente: Sin soporte para Win7 / 64.

Easyprofiler : no lo he visto mencionar aquí todavía, así que no estoy seguro si ya lo has visto. Se necesita un enfoque ligeramente diferente en la forma en que recostack datos métricos. Una desventaja del uso de su enfoque de perfil en tiempo de comstackción es que debe realizar cambios en la base de código. Por lo tanto, deberá tener alguna idea de dónde podría estar la lentitud e insertar allí el código de perfil.

Sin embargo, siguiendo con tus últimos comentarios, parece que al menos estás avanzando un poco . Quizás esta herramienta pueda proporcionarle algunas métricas útiles. Si nada más tiene algunas tablas y gráficos realmente purdy: P

Dos sugerencias de herramientas más.

Luke Stackwalker tiene un lindo nombre (aunque sea un poco difícil para mi gusto), no le costará nada y obtendrá el código fuente. Afirma que también es compatible con progtwigs multihilo. Por lo tanto, sin duda vale la pena dar un giro.

http://lukestackwalker.sourceforge.net/

También Glowcode, que me han indicado que vale la pena usar:

http://www.glowcode.com/

Desafortunadamente no he hecho ningún trabajo de PC por un tiempo, así que no he probado ninguno de estos. Espero que las sugerencias sean de ayuda de todos modos.

Checkout XPerf

Este es un generador de perfiles gratuito, no invasivo y extensible ofrecido por MS. Fue desarrollado por Microsoft para perfilar Windows.

Si sospecha del ciclo de eventos, ¿podría anular QCoreApplication :: notify () y dosome manual profiling (uno o dos mapas de remitentes / eventos a count / time)?

Estoy pensando que primero registra la frecuencia de tipos de eventos, luego examina esos eventos con más cuidado (qué objeto lo envía, qué contiene, etc.). Las señales entre subprocesos se ponen en cola implícitamente, por lo que terminan en el bucle de evento (y también en las conexiones en cola explícitas, obviamente).

Lo hemos hecho para atrapar e informar excepciones en nuestros controladores de eventos, así que realmente, cada evento pasa por allí.

Solo una idea.

Editar: ahora veo que mencionaste esto en tu primera publicación. Maldita sea, nunca pensé que sería ese tipo.

Puede usar Pin para instrumentar su código con una granularidad más fina. Creo que Pin te dejaría crear una herramienta para contar cuántas veces ingresas a una función o cuántos controles de reloj pasas allí, emulando más o menos algo como VTune o CodeAnalyst. Luego, podría desvincular las funciones que se instrumentarán hasta que desaparezcan los problemas de sincronización.

Puedo decirte lo que uso todos los días.

a) Analista de código AMD

  • Es fácil, y le dará una visión general rápida de lo que está sucediendo. Estará bien la mayor parte del tiempo.
  • Con las CPU AMD, le informará sobre la tubería de la CPU, pero solo necesita esto si tiene bucles pesados, como en motores gráficos, códecs de video, etc.

b) VTune.

  • Está muy bien integrado en vs2008

  • una vez que conozca las zonas interactivas, necesita muestrear no solo el tiempo, sino otras cosas como fallas en la memoria caché y el uso de la memoria. Esto es muy importante Configure una sesión de muestreo y edite las propiedades. Siempre tomo muestras de tiempo, memoria de lectura / escritura y fallas de caché (tres ejecuciones diferentes)

Pero más que la herramienta, necesita obtener experiencia con la creación de perfiles. Y eso significa entender cómo funciona la CPU / memoria / PCI … entonces, esta es mi tercera opción

c) Pruebas unitarias

Esto es muy importante si está desarrollando una gran aplicación que necesita un gran rendimiento. Si no puede dividir la aplicación en algunas piezas, será difícil hacer un seguimiento del uso de la CPU. No pruebo todos los casos y clases, pero tengo ejecuciones codificadas y archivos de entrada con características importantes.

Mi consejo es usar muestreo aleatorio en varias pruebas pequeñas e intentar estandarizar una estrategia de perfil.

Acabo de terminar la primera versión utilizable de CxxProf , una biblioteca portátil de perfiles instrumentados para C ++.

Cumple los siguientes objectives:

  • Fácil integración
  • Elimine fácilmente la lib durante el tiempo de comstackción
  • Elimine fácilmente la lib durante el tiempo de ejecución
  • Soporte para aplicaciones multiproceso
  • Soporte para sistemas distribuidos
  • Mantenga el impacto en un mínimo

Estos puntos fueron extraídos de la wiki del proyecto , eche un vistazo allí para más detalles.

Descargo de responsabilidad: soy el principal desarrollador de CxxProf

Uso xperf / ETW para todas mis necesidades de creación de perfiles. Tiene una curva de aprendizaje empinada pero es increíblemente poderosa. Si está perfilando en Windows, entonces debe saber xperf. Con frecuencia uso este generador de perfiles para encontrar problemas de rendimiento en mi código y en el código de otras personas.

En la configuración que lo uso:

  • xperf toma muestras de CPU de cada núcleo que está ejecutando código cada ms. La velocidad de muestreo se puede boost a 8 KHz y las muestras incluyen el modo de usuario y el código del núcleo. Esto permite descubrir qué está haciendo un subproceso mientras se está ejecutando
  • xperf registra cada cambio de contexto (permitiendo una reconstrucción perfecta de cuánto tiempo usa cada hilo), más stacks de llamadas para cuando se conectan los hilos, más stacks de llamadas para el hilo preparado para otro hilo, permitiendo el seguimiento de cadenas de espera y descubriendo por qué un hilo no está funcionando
  • xperf registra todas las E / S de archivos de todos los procesos
  • xperf registra todas las E / S de disco de todos los procesos
  • xperf registra qué ventana está activa, la frecuencia de la CPU, el estado de la CPU, las demoras de la interfaz de usuario, etc.
  • xperf también puede registrar todas las asignaciones de heap de un proceso, todas las asignaciones virtuales de todos los procesos y mucho más.

Eso es una gran cantidad de datos, todos en una línea de tiempo, para todos los procesos. Ningún otro generador de perfiles en Windows puede hacer eso.

He escrito mucho sobre cómo usar xperf / ETW. Estas publicaciones de blog y algunos videos de capacitación de calidad profesional se pueden encontrar aquí: http://randomascii.wordpress.com/2014/08/19/etw-training-videos-available-now/

Si quieres saber qué pasaría si no usas xperf, lee estas publicaciones en el blog: http://randomascii.wordpress.com/category/investigative-reporting/ Estas son historias de problemas de rendimiento que he encontrado en el código de otras personas , eso debería haber sido encontrado por los desarrolladores. Esto incluye la carga de mshtml.dll en el comstackdor de VC ++, la denegación de servicio en los archivos de búsqueda de VC ++, el estrangulamiento térmico en un sorprendente número de máquinas cliente, el lento paso único en Visual Studio, una asignación de 4 GB en un disco rígido controlador de disco, un error de rendimiento de PowerPoint y más.

Solo para tirarlo, aunque no es un generador de perfiles en toda regla: si lo único que buscas son los lazos de eventos colgados que tardan mucho en procesarse un evento, una herramienta ad-hoc es algo simple en Qt. Ese enfoque podría ampliarse fácilmente para realizar un seguimiento de cuánto tiempo llevó procesar cada evento, y cuáles fueron esos eventos, y así sucesivamente. No es un generador de perfiles universal, sino un evento centrado en el bucle de eventos.

En Qt, todas las llamadas de ranura de señal entre hilos se entregan a través del bucle de evento, al igual que los temporizadores, las notificaciones de puerto de red y serie, y todas las interacciones del usuario. Por lo tanto, observar los bucles de eventos es un gran paso hacia la comprensión de dónde está gastando su tiempo la aplicación.

DevPartner, originalmente desarrollado por NuMega y ahora distribuido por MicroFocus, fue una vez la solución preferida para el análisis de perfiles y códigos (por ejemplo, pérdidas de memoria y de recursos). No lo he probado recientemente, así que no puedo asegurarle que lo ayudará; pero una vez tuve excelentes resultados, por lo que esta es una alternativa que considero para volver a instalar en nuestro proceso de calidad de código (proporcionan una prueba de 14 días)

aunque tu sistema operativo es win7, el progtwig no puede ejecutarse bajo xp? ¿Qué hay de perfil en virtud de xp y el resultado debe ser una pista para win7.

Hay muchos perfiladores enumerados aquí y he probado algunos de ellos, sin embargo, terminé escribiendo el mío basado en esto:

http://code.google.com/p/high-performance-cplusplus-profiler/

Por supuesto, requiere que modifiques la base de código, pero es perfecto para reducir los cuellos de botella, debería funcionar en todos los x86 (podría ser un problema con los cuadros de varios núcleos, es decir, usa rdtsc, sin embargo, esto es puramente indicativo de todos modos – así que creo que es suficiente para mis necesidades …)