2009-05-20 48 views
14

¿Qué tipos de herramientas usa para determinar la eficiencia del código? ¿Utiliza aplicaciones de cosecha propia que ejecutan una cantidad estadísticamente significativa de pruebas o algún producto comercial? ¿Utiliza su propio conocimiento para probar ciertas áreas de su código, o alguna herramienta que analiza su código para detectar puntos débiles?Analizando el Código de Eficiencia?

Respuesta

17

Esto se llama profiling. Hay muchas herramientas listas para usar disponibles para ayudarlo a determinar dónde se encuentran los cuellos de botella en sus aplicaciones, para todo tipo de idiomas. Por ejemplo, el conjunto de herramientas TPTP para Java puede mostrarle dónde están los cuellos de botella de rendimiento hasta el nivel de método individual, si así lo desea. Por supuesto, a veces todo lo que realmente necesita es un par de lecturas del temporizador del sistema para obtener una idea general sobre una sección de código.

0

Para .NET Yo recomendaría NDepend.

+0

Pensé que NDepend era más para el análisis de código estático. ¿Ahora tiene instrumentación de rendimiento en tiempo de ejecución? – MikeJ

+0

@MikeJ, tienes razón NDepend hace análisis para código estático. No es que la pregunta sea específica del tiempo de ejecución. BTW, en mi trabajo usamos ANTS Performance Profiler (http://www.red-gate.com/products/ants_performance_profiler/index.htm) para el análisis del tiempo de ejecución. – Vadim

3

perfiladores son muy útiles para ver qué código que pasa la mayoría del tiempo. Hay muchas herramientas de perfilado por ahí, por lo general son específicos para el entorno de la plataforma/el desarrollo que se encuentra.

Para los casos pequeñas I han utilizado temporizadores simples en el código (tiempo del sistema al final de la acción - tiempo del sistema al inicio de la acción).

Una regla importante: nunca supongas que la optimización del rendimiento que acabas de ejecutar se ejecutará realmente más rápido. ¡Siempre verifica!

2

Uso herramientas para ese trabajo. De lo contrario, me resultó bastante difícil hacerlo por mis propias manos ... (bueno, es mi opinión, nunca lo intenté realmente)

En Linux utilizo Valgrind que se entrega con algunas herramientas útiles para perfilar el código. En cuanto a la página de inicio de Valgrind:

Se ejecuta en las siguientes plataformas: X86/Linux, AMD64/Linux, PPC32/Linux, PPC64/Linux.

.. y es gratis (como en cerveza gratis) y de código abierto.

Si bien no los he usado tanto, en otra plataforma puede usar Purify/Quantify (productos de IBM). Son herramientas comerciales. Como Will lo informó, se entregan en el paquete PurifyPlus, y Quantify lo ayudará a crear un perfil de su aplicación.

Eso es todo lo que he usado ... :-)

+0

Creo que Purify está vinculado con Quantify, que es un generador de perfiles. Aunque no estoy seguro, pero ambos son parte de PurifyPlus. –

+0

Buen punto. ¡Thnx Will! Actualizo la pregunta con tu comentario. –

2

Honestamente, yo uso NUnit. Si tengo un código que lleva demasiado tiempo o no parece escalar, escribo una prueba que simula la parte de la aplicación que tiene un rendimiento bajo. Luego busco hacer sustituciones de strenth en el código para reducir el tiempo de ejecución y verificar que no haya roto nada.

Si esto todavía no le da lo que necesita, entonces necesita encontrar y aplicar un generador de perfiles, pero al menos tendrá un caso de prueba en el que puede probar sus suposiciones sin tener que abrir/cargar la aplicación, rastrear llamadas a elementos de la aplicación que no son consecuencia de la tarea en cuestión.

+1

Puede usar MbUnit que da tiempo exacto de cuánto tiempo tomó ejecutar cada prueba. Sin embargo, para el análisis del tiempo de ejecución ANTS Performance Profiler es mucho más eficiente que cualquier marco de prueba de la unidad. – Vadim

+0

Sí. Estoy de acuerdo en que necesitas ambos. Una para identificar los puntos de acceso y otra para asegurar que los cambios para reducir el esfuerzo computacional no den como resultado un funcionamiento incorrecto. – MikeJ

1

La pregunta es ambigua. ¿Eficiente desde el punto de vista del tiempo de ejecución o la memoria? El contexto en el que se ejecuta una pieza de código en particular, la arquitectura de la aplicación y los datos que pueden arrojarse sobre ella son también factores.

BTW, alguien ha mencionado Purify; también está su producto hermano Quantify.

26

INSERTADO: Veamos "significación estadística".

Supongamos que hay una instrucción de llamada de función en alguna parte. No necesariamente puede verlo: una clase, una macro o el compilador pueden haberlo deslizado. Hay otras llamadas a la misma función cerca, pero esta llamada está en un bucle, o sus argumentos son tales como hacer esta llamada lleva mucho tiempo. Tanto tiempo de hecho, que si se pudiera hacer que esta llamada tomara tiempo cero, entonces el tiempo total de ejecución se reduciría en cierta cantidad, digamos 90%. (¿Imposible? No del todo.) ¿Lo marcaría el tiempo? No. ¿Un gráfico de llamadas lo señalaría? No. ¿Los conteos de llamadas lo señalarían? No. Porque el problema no está en el nivel de función, sino en el nivel de instrucción de llamada.

De alguna manera el programa se detiene aleatoriamente en un punto en el tiempo, y se examina su estado. ¿Se habrá detenido en ese 90% del tiempo que se guardaría si la instrucción se pudiera "poner a cero"? Por supuesto, con un 90% de probabilidad, y la instrucción será identificada en la pila esperando que se complete su "trabajo".

De hecho, si lo detiene al azar 20 veces, esa instrucción estará en la pila un promedio de 18 veces, con una desviación estándar de +/- 1.3 veces.

¿Eso es estadísticamente significativo? Usted apuesta que sí.
¿Necesitabas una gran cantidad de muestras? Apuesto a que no.

Supongamos que el porcentaje es pequeño, como 10% o 5%. Se aplica el mismo principio.

De hecho, no importa qué tan pocas muestras se tomen, cualquier instrucción que esté en> 1 muestra es estadísticamente significativa, y es un "punto caliente", "cuello de botella" o como quiera llamarlo. Si puede eliminarlo, llamarlo menos, o de alguna manera reducirlo, ahorrará mucho tiempo. (Algunos no pueden, como "llamar a _main", pero otros pueden hacerlo. Solo necesita encontrarlos.)

Por supuesto mi código nunca sería tan estúpido, ¿verdad? Bueno, entonces, probarlo.

OK, volviendo ahora a la historia. . .

RESPUESTA ORIGINAL: Había oído hablar de perfiladores, hace mucho tiempo, y pensé que debían ser bastante pulcros, pero no tenía acceso a ellos/it. Estaba trabajando en un procesador integrado (un chip Intel 8086) que parecía tomarse un tiempo tremendo pintando algunos números de punto flotante en una pantalla. Los chicos del hardware sugirieron que provean de su abundancia, agregando chips de temporizador para poder ver cuánto tiempo están tomando las cosas. Sin embargo, un fin de semana lo encendí con un emulador en circuito Intel "Blue Box" y lo puse en funcionamiento. Mientras estaba siendo lento, me pregunté "¿Qué diablos está haciendo?". Así que solo lo detuve para descubrirlo. La PC estaba en la biblioteca de coma flotante (no había chip FP). Eso no fue una sorpresa, ya que estaba pintando números en coma flotante, pero quería saber más. Así que (laboriosamente) leo la memoria hexadecimal para seguir la pila de llamadas. ¿Adivina qué? Estaba en el proceso de tomar el número para pintar, dividirlo por 10, convertirlo a entero, convertir de nuevo a flotante, restar, y así sucesivamente, solo para obtener el siguiente dígito para pintar. Huelga decir que hay mejores formas de hacer que, lo que resulta en una aceleración de alrededor de 10 veces. que se encontró con una (1) muestra!

En otra ocasión, en un chip 68K, hubo cierta lentitud. Una vez más, un generador de perfiles no estaba disponible, pero el depurador "adb" era, así que mientras estaba siendo lento, lo detuve un par de veces. La PC estaba en la biblioteca matemática, en realidad en la rutina de multiplicar de 32 bits enteros. Mirando hacia arriba la pila, me encontré con este código:

struct {...} a[...]; 

int i; 
for (i = 0; i < ...; ++i){ ... a[i] ... } 

No hay ninguna llamada a multiplicarse en allí - ¿qué está pasando? Resulta que, para a[i], el compilador tiene que multiplicar i por el tamaño del elemento de la matriz. Dado que i es de 32 bits (en ese compilador) genera una llamada a la rutina de multiplicación de 32 bits, y la pila señala esa instrucción de llamada. ¡Al declarar i como short, el ciclo se triplicó en velocidad!

¿Cuál es el punto? Si toma muestras en momentos aleatorios mientras el programa es lento, la PC le dirá lo que está haciendo, pero la pila de llamadas le dirá por qué, y lo llevará directamente al problema. Ahora, a menos que el problema sea realmente malo, es posible que deba tomar varias muestras. Cualquier declaración que aparezca en> 1 muestra es de la que puede sospechar. Observe que señala declaraciones, instrucciones incluso, no grandes fragmentos de código como funciones. This technique puede ser "rápido y sucio", pero es muy efectivo.

AGREGADO: Si hace esto repetidamente, puede resolver problema tras problema en el mismo software. Por ejemplo, si obtiene una aceleración de 3 veces, los pequeños problemas de rendimiento que pueden haber sido insignificantes ahora consumen 3 veces más del tiempo restante. Eso hace que sea mucho más fácil golpear con muestras. Puede que tenga que agregar un bucle exterior temporal para que se ejecute el tiempo suficiente para muestrear. De esta manera, he visto factores de aceleración compuestos de more than 40 times.

+7

Esta técnica es ciertamente efectiva. Lo descubrí esta semana en otra publicación de Stack Overflow, http://stackoverflow.com/questions/375913, y lo probé en una de mis aplicaciones utilizadas por muchos usuarios internos y externos. El resultado fue una aceleración total de 7 veces (!) En la primera iteración, de 16.5 minutos a 2.2 minutos en un conjunto de datos (típico) en particular. –

+1

@ Peter: ¿Cuántas muestras de pila tuvo que tomar para encontrar el problema? Si obtuviste una aceleración de 7 veces, eso implica que cada muestra tenía (al menos) una probabilidad de 6/7 de mostrarlo. –

+2

@Mike Dunlavey: Solo necesitaba 3-4. Ya estaba claro para entonces. En la siguiente iteración, tomé 20 y me dio la idea de un cambio que condujo a una aceleración de 3.3 veces para otro modo de operación (de hecho, con mucho, el más lento de toda la aplicación) en mi aplicación (http://msquant.sourceforge.net/). –

2

Uso Valgrind y su herramienta Callgrind. Es una gran herramienta. Valgrind es básicamente una máquina virtual:

valgrind es en esencia una máquina virtual usando justo a tiempo (JIT) técnicas de compilación, incluyendo recompilación dinámica. Nada desde el programa original se ejecuta alguna vez directamente en el procesador host. En su lugar, Valgrind primero traduce el programa en un formulario temporal, más simple llamado Representación intermedia (IR), que es un formulario basado en SSA, , neutral al procesador. Después de la conversión, una herramienta (ver abajo) es libre de hacer cualesquiera transformaciones que desee en el IR, antes de que Valgrind traduzca el IR al código de la máquina y permita que el procesador host lo ejecute. Aunque podría utilizar la traducción dinámica (que es, los procesadores host y de destino son desde diferentes arquitecturas), no. Valgrind recompila el código binario para ejecutar en el host y el destino (o simulado) CPU de la misma arquitectura .

Callgrind es un generador de perfil sobre eso. El principal beneficio es que no tiene que ejecutar su aplicación durante horas para obtener un resultado confiable.Pocos segundos son suficientes, porque Callgrind es un perfilador no sondeante,

Otra herramienta construida sobre Valgrind es Massif. Lo uso para perfilar el uso de memoria de montón. Funciona muy bien, le da instantáneas del uso de la memoria: información detallada QUÉ contiene qué porcentaje de memoria y quién lo puso allí.

Una herramienta más Valgrind - DRD (y Helgrind). Los uso para rastrear bloqueos muertos y carreras de datos en mi código, así como también para el uso indebido de API.

1

He oído buenas palabras sobre Yourkit para perfiles de Java. Para los sitios web, probé JMeter que tiene una funcionalidad básica para el perfilado parametrizado simple.