Pregunta

Perfilado algunos C ++ número crujido de código con tanto gprof y kcachegrind da resultados similares para las funciones que contribuyen más al tiempo de ejecución (50-80% dependiendo de la entrada), pero para las funciones entre 10-30% estas dos herramientas de dar resultados diferentes . ¿Significa que uno de ellos no es fiable? Lo que sería yo hacer aquí?

¿Fue útil?

Solución

gprof es en realidad bastante primitiva. Esto es lo que hace. 1) Se muestrea el contador de programa a un ritmo constante y registros de cuántas muestras de tierra en cada función (tiempo exclusivo). 2) Se cuenta el número de veces cualquier función A llama a cualquier función B. Desde que se pueda averiguar cuántas veces cada función se llama en total, y lo que es el tiempo promedio era exclusiva. Para obtener el tiempo incluido media de cada función se propaga tiempo exclusivo al alza en el gráfico de llamadas.

Si usted está esperando que esto tenga algún tipo de precisión, se debe tener en cuenta algunas cuestiones. En primer lugar, sólo cuenta la CPU en tiempo-en-proceso, lo que significa que es ciego de E / S o de otras llamadas al sistema. En segundo lugar, la recursividad se confunde. En tercer lugar, la premisa de que las funciones siempre se adhieren a un tiempo promedio de carreras, no importa cuando se les llama o que los llama, es muy sospechoso. En cuarto lugar, la noción de que las funciones (y su gráfico de llamadas) son lo que necesita saber acerca de, en lugar de líneas de código, no es más que una suposición popular, nada más. En quinto lugar, la noción de que la precisión de la medición es aún relevante para la búsqueda de "cuellos de botella" se encuentra a sólo una suposición popular, nada más.

Callgrind puede trabajar a nivel de las líneas - eso es bueno. Lamentablemente comparte los otros problemas.

Si su objetivo es encontrar "cuellos de botella" (en lugar de obtener mediciones generales), se debe echar un vistazo a la pared del reloj muestreadores pila vez que el informe por ciento por línea, como zoom . La razón es simple, pero posiblemente no familiar.

Suponga que tiene un programa con un montón de funciones de llamada entre sí, que se lleva a un total de 10 segundos. Además, hay un muestreador que las muestras, no sólo el contador de programa, sino a toda la pila de llamadas, y lo hace todo el tiempo a una velocidad constante, al igual que 100 veces por segundo. (Ignorar otros procesos por ahora.)

Así que al final tiene 1000 muestras de la pila de llamadas. Escoja cualquier línea de código L que aparece en más de una de ellas. Supongamos que de alguna manera podría optimizar esa línea, evitando que, retirarlo, o haciéndola pasar a un procesador realmente muy rápido.

¿Qué pasaría con esas muestras?

Desde esa línea de código L ahora toma (esencialmente) muy poco tiempo, ninguna de las muestras puede golpear, por lo que las muestras serían simplemente desaparecerá , la reducción del número total de muestras, por lo que el total de ¡hora! De hecho, el tiempo total se reduciría en la fracción de tiempo L que había sido en la pila, que es más o menos la fracción de las muestras que lo contenían.

Yo no quiero ser demasiado estadístico, pero mucha gente que necesita una gran cantidad de muestras, porque creen que la precisión de la medición es importante. No es, si la razón por la que está haciendo esto es averiguar qué se debe corregir para obtener la aceleración. El énfasis está en encontrar qué se debe corregir, no en medición ella. Línea L está en la pila alguna fracción F del tiempo, ¿verdad? Así que cada muestra tiene una probabilidad de golpear F, ¿verdad? Al igual que lanzar una moneda. Hay una teoría de este, llamado el regla de sucesión . Se dice que (en virtud de la simplificación, pero las hipótesis generales), si se lanza una moneda N veces, y ve "cabezas" S veces, se puede estimar la imparcialidad de la moneda F, como (en promedio) (S+1)/(N+2). Por lo tanto, si se toma tan sólo tres muestras, y ve en L dos de ellos, ¿sabes lo que F es? Por supuesto que no. Pero usted no en promedio sabe que es (2 + 1) / (3 + 2) o 60% . De manera que de la cantidad de tiempo que podría ahorrar (en promedio) por "la optimización de distancia" de serie L. Y, por supuesto, las muestras mostraron que la pila exactamente en la línea L (el "cuello de botella" **) es. ¿Realmente importa that Usted no midió a dos o tres cifras decimales?

BTW, es inmune a todos los otros problemas mencionados anteriormente .

** sigo poniendo comillas alrededor de "cuello de botella" porque lo que hace más lento software no tiene nada en común con el cuello de una botella. Una mejor metáfora es una "fuga" -. Algo que simplemente una pérdida de tiempo innecesaria

Otros consejos

gprof's timing data is statistical (read about it in details of profiling docs).

On the other hand, KCacheGrind uses valgrind which actually interprets all the code.

So KCacheGrind can be "more accurate" (at the expense of more overhead) if the CPU modeled by valgrind is close to your real CPU.

Which one to choose also depends on what type of overhead you can handle. In my experience, gprof adds less runtime overhead (execution time that is), but it is more intrusive (i.e. -pg adds code to each and every one of your functions). So depending on the situation, on or the other is more appropriate.

For "better" gprof data, run your code longer (and on as wide a range of test data you can). The more you have, the better the measurements will be statistically.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top