2010-01-15 21 views
38

Estoy tratando de determinar qué enfoque para eliminar una cadena es el más rápido.¿Cuál es la mejor manera de medir cuánto tiempo tarda el código en ejecutarse?

Simplemente consigo comienzan y final vez y muestran la diferencia.

Pero los resultados son tan variados, p. Ej. como se muestra a continuación, el mismo método puede tomar de 60 ms a 231 ms.

¿Cuál es un mejor método para obtener resultados más precisos?

alt text http://www.deviantsart.com/upload/1q4t3rl.png

using System; 
using System.Collections; 
using System.Collections.Generic; 

namespace TestRemoveFast 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      for (int j = 0; j < 10; j++) 
      { 
       string newone = ""; 
       List<string> tests = new List<string>(); 
       for (int i = 0; i < 100000; i++) 
       { 
        tests.Add("{http://company.com/Services/Types}ModifiedAt"); 
       } 

       DateTime start = DateTime.Now; 
       foreach (var test in tests) 
       { 
        //newone = ((System.Xml.Linq.XName)"{http://company.com/Services/Types}ModifiedAt").LocalName; 
        newone = Clean(test); 
       } 

       Console.WriteLine(newone); 
       DateTime end = DateTime.Now; 
       TimeSpan duration = end - start; 
       Console.WriteLine(duration.ToString()); 
      } 

      Console.ReadLine(); 
     } 

     static string Clean(string line) 
     { 
      int pos = line.LastIndexOf('}'); 
      if (pos > 0) 
       return line.Substring(pos + 1, line.Length - pos - 1); 
       //return line.Substring(pos + 1); 
      else 
       return line; 
     } 
    } 
} 
+1

No creo que haya nada intrínsecamente inexacta sobre los meassurements sí mismos. Lo que probablemente quiere decir es que no esperaba tanta dispersión. Supongo que deberías asegurarte de que ningún otro programa en tu computadora esté usando todo tu tiempo de CPU o memoria. –

+2

Tenga en cuenta que el "tiempo de reloj de pared" medido por DateTime solo es preciso hasta algo así como 30 ms. DateTime es para representar cosas como un reloj en la pared, o la última vez que editó un archivo; no es necesario tener una precisión de nanosegundos, y por lo tanto no es así. –

Respuesta

45

Debe utilizar System.Diagnostics.Stopwatch, y es posible que desee considerar una muestra grande. Por ejemplo, repita esta prueba aproximadamente 10,000 veces y promedie los resultados. Si lo piensas científicamente, tiene sentido. Cuanto mayor sea la muestra, mejor. Puede eliminar muchos casos extremos de esta manera y realmente ver cómo es el rendimiento central.

Otra cosa a considerar es que la compilación de JIT y la creación de objetos definitivamente pueden sesgar los resultados, así que asegúrese de iniciar y detener su cronómetro en los momentos apropiados, y llame a los métodos que desee probar al menos una vez antes de comenzar tus pruebas Intente segregar tanto como sea posible las partes que desea probar del resto de su código.

+0

Además, normalmente me aseguro de haber invocado los métodos para probar para evitar tener tiempos de compilación JIT incluidos en la medición. –

+1

Sí, buen punto, Fredrik. Desea asegurarse de dividir su prueba en solo las partes que desea monitorear. Muchas veces la gente no piensa en cómo crear nuevos objetos y JIT puede sesgar los resultados. –

+0

Definitivamente agregar repetición. En fragmentos de <10s, el sistema que transfiere el tiempo de CPU a otras tareas puede afectar seriamente el rendimiento de la prueba. Una prueba de ~ 10 minutos es más confiable. Además, elimine todos los demás procesos intensivos en disco y que consumen mucha CPU. –

6

Puede usar la clase Stopwatch.

El cronómetro mide el tiempo transcurrido por temporizador de conteo de garrapatas en el mecanismo que subyace temporizador. Si el hardware y el sistema operativo instalados admiten un contador de rendimiento de alta resolución, , entonces la clase Cronómetro usa ese contador para medir el tiempo transcurrido.

var sw = new Stopwatch(); 

sw.Start(); 
// ... 
sw.Stop(); 
0

Puede que tenga que aplicar algunas técnicas estadísticas aquí para limar la varianza. Intente ejecutar el mismo fragmento de código 1000 veces y luego tome el tiempo promedio, y compare eso. Las simulaciones generalmente emplean algún tipo de método para 'limpiar' los números, y este es uno de esos.

3

Si sólo estás preocupado por las pruebas que en su propio código ... utilizar un System.Diagnostics.Stopwatch

Por lo general prefieren romper este tipo de cosas fuera de mi código y el uso de un cierto Profiler como RedGate's Performance Profiler

35

Tres notas simples:

  1. Utilice System.Diagnostics.Stopwatch.

  2. No perfile su código en la misma entrada un millón de veces. Intenta encontrar tu distribución esperada de entradas y perfil sobre eso. Ese es el perfil de la entrada en el mundo real, no la entrada de laboratorio.

  3. Ejecute el método Clean una vez antes de ingresar al ciclo de creación de perfiles para eliminar el tiempo de JITting. A veces esto es importante.

De estas, las notas 1. y 2. son, con mucho, las más importantes.

Sus resultados de generación de perfiles no tienen sentido si no está utilizando un temporizador de alta resolución. Tenga en cuenta que no hacemos time Usain Bolt usando un water clock.

Sus resultados de generación de perfiles no tienen sentido si no está probando en la entrada en el mundo real. Tenga en cuenta que las pruebas de choque estrellan los autos en otros autos a 35 MPH, no en las paredes hechas de marshmellows a 5 MPH.

Por lo tanto:

// expectedInput is string[1000000] 
// populate expectedInput with real-world input 
Clean(expectedInput[0]); 
Stopwatch sw = new Stopwatch(); 
sw.Start(); 
for (int i = 0; i < 1000000; i++) { 
    string t = Clean(expectedInput[i]); 
} 
sw.Stop(); 
Console.WriteLine(sw.Elapsed); 

Una nota complejo:

Si realmente necesita hacer perfiles, obtener un perfilador como ANTS.

+2

No puedo encontrar el método Clean en ninguna parte, tampoco pude encontrarlo en MSDN? –

+3

@didibus: 'Clean 'pasa a ser el nombre del método que el OP es punto de referencia; es por eso que nos referimos a 'Limpiar' aquí. – jason

0

Generalmente: no mire el tiempo de reloj de pared sino el tiempo de CPU consumido por su proceso para determinar cuánto tiempo funcionó. Especialmente para cosas que son solo computación, esto es mucho más confiable porque no se verá afectado por otros procesos que se ejecutan al mismo tiempo.

+0

Esto puede ser problemático, sin embargo, porque el tiempo de CPU tampoco contará cosas como esperar por E/S o por un error de página (?). Estos afectan el rendimiento del sistema real y deben tenerse en cuenta. – sleske

+0

Es por eso que noté que esto es principalmente solo para tareas de computación. – Joey

0

El problema con todos los enfoques basados ​​en reloj es que nunca está seguro de lo que está cronometrando. Usted puede, ya sea que se dé cuenta o no, incluir en su sincronización:

  • retrasos mientras el o/s adelanta su procesador;
  • cambio de contexto
  • se bloquea mientras el programa espera datos;
  • y mucho más.

No estoy diciendo que todos estos se apliquen a este tiempo en particular, sino a los tiempos en general. Por lo tanto, debe complementar cualquier momento que tenga con alguna consideración de cuántas operaciones básicas ejecutan sus códigos alternativos, algunas consideraciones de complejidad que no ignoran (como solemos hacer) los términos constantes.

En su caso particular, debe apuntar a ejecutar ejecuciones mucho más largas; cuando tus tiempos son inferiores a los segundos, es muy probable que el o/s te moleste. Por lo tanto, ejecute 10^6 iteraciones y use el promedio en las corridas suficientes para obtener un cálculo significativo del promedio y la varianza. Y asegúrese, si toma este enfoque, de que no acelere inadvertidamente la segunda prueba teniendo los datos ya cargados después del final de la primera prueba. Debe asegurarse de que cada uno de los 10^6 ensayos haga exactamente lo que hace el primer ensayo.

Diviértete

Marcos

0

voy a tener que recomendar el generador de perfiles altamente incluido en Visual Studio Team Suite or Development Edition (o la próxima Visual Studio 2010 Premium or Ultimate es incluso mejor) como la mejor manera. Es altamente configurable, extremadamente potente, fácil de usar, muy rápido y funciona tanto con código nativo como con código administrado. No estoy familiarizado con el flujo de trabajo de ANTS, pero parece ser otra opción.Sin duda, el uso de un generador de perfiles es la opción única para un desarrollador que se preocupa por el rendimiento de su aplicación. No hay sustituto, y realmente no se puede tomar ningún desarrollador comercial que trabaje en el rendimiento que pasaría a un perfilador en serio.

Sin embargo, si usted está interesado en las mediciones para uno de los siguientes, puede que no tenga acceso a un generador de perfiles tales, en cuyo caso la clase cronómetro puede formar una base para su técnica de medición:

  • Un estudiante o aficionado interesado en el rendimiento de sus proyectos (un generador de perfiles comercial puede estar fuera de su alcance por razones financieras)
  • En una aplicación publicada, es posible que desee cronometrar las secciones de código que se ejecutan en el hilo de la interfaz e informar las estadísticas Asegúrese de que las operaciones nunca causen demoras notables para ninguno de sus usuarios. El equipo de Office utilizó un método como este con enorme éxito (¿alguien de Outlook 2007 SP2?), Y sé que el equipo de Visual Studio tiene este código al menos en la versión de 2010.
+0

Highly profiler? – karlingen

2

Hay mucha actividad bajo el capó del sistema operativo, que es muy probable que estropee sus mediciones de tiempo. Con el fin de mejorar la precisión de los tiempos medidos, debe ejecutar las pruebas varias veces y eliminar el más bajo y el mayor de los resultados finales. Este enfoque excluirá la mayoría de los factores externos que pueden influir en el tiempo de ejecución de su código y le servirá bien en la mayoría de los casos. La clase Stopwatch se usa para medir el tiempo, ya que es mucho más precisa que con DateTime.

Puede hacer fácilmente una clase de prueba para automatizar esto. He publicado one such class in my blog. Puede comparar el rendimiento de dos fragmentos/algoritmos de código C#. Todo lo que tiene que hacer es reemplazar los métodos metodo1 y metodo2 poniendo allí los fragmentos de código que desea probar y usar la clase de prueba como esta:

Test test = new CustomTest(); 
Console.WriteLine("\n=============================="); 
Console.WriteLine(test.Execute()); 
Console.WriteLine("==============================\n"); 
Cuestiones relacionadas