2012-03-22 10 views
11

Parece que no hay perfiles de rendimiento * .NET gratuitos que puedan perfilar línea por línea. Por lo tanto, estoy buscando usar Cronómetro para perfilar.Creación de perfiles de aplicaciones .NET con Cronómetro

* gratis como en libertad, es decir, la licencia incluye aplicaciones comerciales.

EDITAR: En respuesta a los que me dijeron "compre un perfilador", me gustaría, pero si pudiera gastar tanto dinero, lo gastaría en otra cosa. Traté de convencer a mi jefe de que un perfilador lo vale, pero no tuve mucha suerte. Esta pregunta se basa principalmente en la curiosidad. Nunca consideraría a Cronómetro como un reemplazo para un generador de perfiles real.

Tengo una pequeña aplicación de prueba (escrita en C#) que mide las diferencias de rendimiento cuando se usa un cronómetro por línea. El código de prueba es la siguiente:

int n = 100; 
BigInteger f = 1; 
for (int i = n; i > 1; i--) 
{ 
    f *= i; 
} 

Aquí está el código completo: http://pastebin.com/AvbQmT32

Tengo un cronómetro para cada línea de código. Este es mi 'generador de perfiles'. También tengo un cronómetro para todo el programa. Este es mi 'profiler profiler'.

Tengo el programa configurado como Modo de liberación, Cualquier CPU (en una máquina x64) y las optimizaciones están deshabilitadas.

Cuando ejecuto el programa con el perfilador desactivado, me sale algo como esto:

   Line    | Ticks 
------------------------------|---------- 
           | 
Total time:     |  359 

Cuando corro con activar el generador de perfiles, me sale algo como esto:

   Line    | Ticks 
------------------------------|---------- 
           | 
int n = 100;     |   3 
BigInteger f = 1;    |  12 
for (int i = n; i > 1; i--) |  325 
{        | 
    f *= i;     |  539 
}        | 
           | 
Total time:     |  1710 
Stopwatch overhead:   |  831 

Idealmente , el tiempo dedicado al código debe ser igual en ambos casos, pero parece que los cronómetros tienen una sobrecarga que aparece dentro de su propio tiempo transcurrido.

Ahora, a menudo no tiene sentido tener que perfilar cada línea de un programa, ya que generalmente funciona mejor con un enfoque de dividir y vencer. Por lo general, puede comenzar describiendo trozos de código y reduciendo cualquier problema de rendimiento.

Además, en la mayoría de las aplicaciones, la línea de código promedio será mucho más lenta que las del programa de prueba. Esto significa que habrá menos sobrecarga del cronómetro.

Sin embargo, todavía hay sobrecarga al usar los Cronómetros, especialmente si usa mucho.

Así reduce a la pregunta:

Cuál es la forma más eficaz de utilizar cronómetros para el perfilado? ¿Cómo puedo minimizar la sobrecarga? ¿Vale la pena envolver un cronómetro alrededor de una sola declaración?

Les agradezco su comentario.

+6

Personalmente, los perfiladores que compré (ANTS Profiler) valieron cada centavo. Nunca volvería a pensar en el perfil "manual" de nuevo. –

+1

Lo siento por preguntar, pero ¿por qué no utilizar algunas de las clases System.Diagnostics? Creo que contiene clases para ver el uso de CPU y Ram, por ejemplo. – Eon

+1

La versión gratuita de Eqatec Profiler permite su uso en un proyecto comercial: http://www.eqatec.com/Profiler/LicenseTerms.aspx – ken2k

Respuesta

2

Lo primero es lo primero: los resultados no son sorprendentes. Si utilizó un perfilador comercial, vería algo similar: su programa tardará mucho más en ejecutarse cuando está siendo perfilado que cuando no lo está. Cuanto más granular establezca el generador de perfiles, más tiempo puede esperar que tome. Cuando considera que las declaraciones como "i> 1" e "i--" probablemente se ejecutarán como instrucciones de un único procesador, resulta obvio por qué perfilar el tiempo de ejecución de una línea en particular puede llevar mucho más tiempo que ejecutar la línea en sí.

El hecho de que la creación de perfiles esté aumentando el tiempo total de ejecución de su programa no debería ser una preocupación; como varios otros han mencionado, lo que importa no es la cantidad absoluta de tiempo que el programa se ejecuta, sino que compara el tiempo de ejecución de las partes individuales entre sí para encontrar el cuello de botella. Pero hay otra preocupación. Cronómetro utilizará el temporizador de alta frecuencia del sistema operativo subyacente si hay uno disponible; pero incluso eso puede no ser lo suficientemente alto. El temporizador de alta frecuencia en mi Windows 7 64-bit i5-2400 (Quad core 3.10 GHz) marca 3,020,556 veces por segundo. Eso suena mucho; pero a ese ritmo, el procesador podría ejecutar mil instrucciones entre tics. Eso significa que si estás tratando de medir el tiempo que lleva ejecutar una sola instrucción, estás yendo demasiado por debajo o demasiado por encima.

Será mejor que perfile en el nivel de método. Incluso entonces se encontrará con problemas de frecuencia, particularmente si tiene métodos pequeños bien factorizados. Pero los resultados serán más confiables que a nivel de línea; y una vez que haya identificado el método que está causando el cuello de botella, puede examinarlo directamente para determinar cómo optimizarlo y obtener un mejor rendimiento.

Todo esto deja de lado las muchas advertencias que van junto con el perfil de rendimiento en general, que estaría fuera del alcance de esta publicación. Asegúrese de realizar investigaciones adicionales sobre el tema para comprender cómo debe interpretar los resultados que obtenga. Como un ejemplo rápido, su perfil puede revelar que la mayoría de las veces en su programa se gasta en un método particular; pero ¿significa eso que el método en sí es el problema o que otros métodos lo están llamando con frecuencia? Responder a ese tipo de pregunta es donde radica la verdadera dificultad de los perfiles.

1

¿Ha comparado el tiempo total sin su generador de perfiles con su perfil en modo de depuración? Mi primera suposición es que el tiempo extra está apareciendo porque las declaraciones adicionales para el cronómetro están impidiendo la optimización de registro o bucle. Por lo tanto, el tiempo adicional puede provenir de una optimización faltante y no de una pérdida de tiempo inherente al cronómetro.

Sin embargo, dicho esto, aunque el cronómetro tiene una alta resolución, creo que notaría algún error de tiempo midiendo cosas tan pequeñas como una línea de código. Por ejemplo, 'int n = 100' es una línea en el ensamblaje, por lo que en términos técnicos, creo que sería solo 1 tick. ¿Cuánta variación observas en tus números desde la ejecución hasta la ejecución? Si obtiene una variación que es un porcentaje significativo de su valor promedio, entonces ese valu realmente no le está dando tanta información.

+0

Las optimizaciones están desactivadas, por lo que no será un problema. A veces veo una variación de aproximadamente 1/3 del valor promedio, en ambos casos. –

+0

Con las optimizaciones desactivadas, cambiar al modo de depuración probablemente no revele el problema, pero aún es posible que la ralentización sea causada por la sobrecarga adicional de las llamadas al cronómetro. Las llamadas al cronómetro usan varias variables internamente que pueden forzar a su código principal a hacer cosas como volver a cargar registros después de las llamadas al cronómetro, por ejemplo. – Sogger

+0

Ah, y en términos de la variación de 1/3, depende de lo que está tratando de determinar el número, pero una variación tan grande significa que el número solo será bueno para las comparaciones de orden de magnitud (en términos de otras respuestas aquí están diciendo, solo es bueno para comparaciones relativas). Piense en una persona de 6 pies de altura que se mide con un margen de error de 1/3, 'Oh, tiene entre 4 y 8 pies de altura'. Es un gran problema. – Sogger

4

Teniendo en cuenta que a menudo intuitivamente programa Single responsibility principle, no sólo en lo que se refiere de tipos, pero las funciones también, yo diría que no hay ningún sentido del perfilado de aplicación línea por línea. Estará más interesado en perfilar una "responsabilidad única" que en cada línea.

Hay casos, naturalmente, cuando necesita para tener información también. Pero no lo use en todas las aplicaciones, sino en una sola parte de una función o una sola función. En este caso, StopWatch es la mejor opción. Tenga en cuenta que StopWatch es .NET Class, por lo que tiene es incluso mínima sobrecarga. No debe mirar en absoluto, pero en valores relativos.

Espero que esto ayude.

2

No debería estar mirando los números exactos, debería buscar las diferencias relativas. Para que pueda identificar áreas problemáticas Está buscando lugares para optimizar que resuelvan su problema de rendimiento.

Si está desarrollando código a un nivel donde el rendimiento es realmente un problema y necesita crear un perfil para encontrar el código ofensivo, entonces comprar una herramienta para realizar esta tarea será más que pagar por sí mismo en el tiempo salvado. El generador de perfiles que viene con Visual Studio Premium es lo que recomendaría.

0

Tal vez debería pensar en términos de tiempos de llamadas al método de creación de perfiles, y no en líneas individuales. Después de todo, una llamada a un método suele ser una sola línea en el código de llamada. También un enfoque interesante es el uso de una biblioteca de registro para registrar la entrada y salidas método, por ejemplo, como esto (usando log4net como el registrador de elección):

public string MyMethod(string arg) 
{ 
    string result = null; 

    if (logger.IsDebugEnabled) logger.Debug("->MyMethod(" + arg + ")"); 

    // do stuff 
    result = "Hello world!"; 

    if (logger.IsDebugEnabled) logger.Debug("<-MyMethod(" + arg + ") = " + result); 

    return result; 
} 

Esto creará un archivo de registro que es realmente útil para ver lo que está haciendo su aplicación, y tiene la ventaja de marcar cada línea escrita en el registro, para que pueda ver si un método en particular está llevando mucho tiempo. Con log4net puede cambiar fácilmente la configuración para desactivar el inicio de sesión, de modo que cuando no lo necesite no pague ninguna penalización de rendimiento.

2

¿Has probado mirar CInject: http://codeinject.codeplex.com/documentation? Básicamente inyecta código en una DLL. Al salir de la caja, parece tener monitoreo de rendimiento, pero también te permite crear tu propio código para inyectar. Parece perfecto para lo que estás tratando de hacer.

Cuestiones relacionadas