2009-10-23 17 views
5

¿A qué objeto/método llamaría para obtener la hora actual en milisegundos (o una gran precisión) para ayudar a medir cuánto tardó en ejecutarse un método?Formas rudimentarias de medir el tiempo de ejecución de un método

NSDate's timeIntervalSinceDate devolverá NSInterval que se mide en segundos. Estoy buscando algo más fino, algo similar a System.currentTimeMillis de Java.

¿Hay una versión equivalente en Object-C/CocoaTouch?

+0

La razón por la que estoy usando un tiempo rápido y sucio en mi código es porque quería delimitar un área que parecía problemática y no estaba teniendo suerte obteniendo mucha información después de ejecutar Instruments and Shark. Para evitar quedar atrapado, estaba optando por esta ruta. –

+0

dispatch_benchmark() es una forma: http://nshipster.com/benchmarking/ – LearnCocos2D

Respuesta

9

En realidad, +[NSDate timeIntervalSinceReferenceDate] devuelve NSTimeInterval, que es un typedef para un doble. Los documentos dicen

NSTimeInterval siempre se especifica en segundos; produce precisión de menos de milisegundos en un rango de 10,000 años.

Por lo tanto, es seguro utilizarlo con un tiempo de precisión de milisegundos. Lo hago todo el tiempo.

+0

gracias-He leído mal la documentación. –

+3

Pierdes mucho tiempo simplemente llamando a 'timeIntervalSinceReferenceDate', esto sesga el resultado de una manera impredecible. –

+0

Downvoted porque, de forma experimental, como dice @SchurchSchölly, Apple ha implementado NSDate como * extremadamente lento * (al menos en iOS). Es inútil: sus llamadas al método "timeInterval *" realmente aparecieron en Instruments como el mayor problema de CPU en un proyecto. – Adam

2

timeIntervalSinceReferenceDate está perfectamente bien.

Sin embargo, a menos que sea un método de larga duración, esto no dará mucha fruta. Los tiempos de ejecución pueden variar enormemente cuando se habla de ejecuciones de unos pocos milisegundos. Si su subproceso/proceso se adelanta a mitad de camino, tendrá picos no deterministas. Esencialmente, su tamaño de muestra es demasiado pequeño. Utilice un generador de perfiles o ejecute 100.000 iteraciones para obtener el tiempo total y divida entre 100.000 para obtener un tiempo de ejecución promedio.

25

Para sincronizaciones de grano muy fino en OS X, utilizo mach_absolute_time(), que se define en <mach/mach_time.h>. Se puede utilizar de la siguiente manera:

#include <mach/mach_time.h> 
#include <stdint.h> 

static double ticksToNanoseconds = 0.0; 

uint64_t startTime = mach_absolute_time(); 
// Do some stuff you want to time here 
uint64_t endTime = mach_absolute_time(); 

// Elapsed time in mach time units 
uint64_t elapsedTime = endTime - startTime; 

// The first time we get here, ask the system 
// how to convert mach time units to nanoseconds 
if (0.0 == ticksToNanoseconds) { 
    mach_timebase_info_data_t timebase; 
    // to be completely pedantic, check the return code of this next call. 
    mach_timebase_info(&timebase); 
    ticksToNanoseconds = (double)timebase.numer/timebase.denom; 
} 

double elapsedTimeInNanoseconds = elapsedTime * ticksToNanoseconds; 
1

Si usted está tratando de optimizar el rendimiento de su código, te sería mejor utilizar instrumentos o tiburón para obtener una visión general de donde su aplicación está gastando su tiempo.

4

No utilice NSDate para esto. Pierde mucha precisión para llamar a métodos y crear instancias de objetos, incluso puede liberar algo interno. Simplemente no tienes suficiente control.

Use ya sea time.h o como Stephen Canon como mach/mach_time.h. Ambos son mucho más precisos.

La mejor manera de hacer esto es para encender o Instrumentos tiburón, adjuntarlos a su proceso (funciona incluso si ya está en ejecución) y dejar que ellos miden el tiempo de un método de toma.

Una vez que esté familiarizado con esto, esto lleva incluso menos tiempo que cualquier solución de put-in-mach-time-functions-and-recompile-the-whole-application. Incluso obtienes mucha información extra. No me conformaría con nada menos.

+0

NB: hay casos de uso donde los instrumentos son inútiles. p.ej. una aplicación OpenGL: necesito saber qué sombreadores se están ejecutando rápido frente a lento, y qué métodos de fondo están ocupando la cantidad de tiempo ... en los dispositivos del usuario final. En algunos casos, quiero cambiar dinámicamente a una ruta de representación diferente como resultado. No puedo pedirles que ejecuten Instruments;), y eso evitaría los cambios de tiempo de ejecución de todos modos, así que ... time/mach_time es bueno. – Adam

1

voy a volver a publicar mi respuesta de otro post aquí. Tenga en cuenta que mi solución es cierto simple a este problema complejo y utiliza NSDate NSTimeInterval como su fundamento:


Sé que esto es muy antigua pero incluso me encontré vagando pasado de nuevo, así que pensé en enviar mi propia opción aquí.

La mejor opción es retirar mi blog el siguiente: Timing things in Objective-C: A stopwatch

Básicamente, escribí una clase que hace dejar de ver de una manera muy básica, pero es encapsulado de manera que sólo tendrá que hacer lo siguiente:

[MMStopwatchARC start:@"My Timer"]; 
// your work here ... 
[MMStopwatchARC stop:@"My Timer"]; 

Y se termina con:

MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029] 

en el registro ...

Una vez más, echa un vistazo a mi post de un poco más o descargarlo aquí: MMStopwatch.zip

+0

Como se indicó anteriormente: no debe usar NSDate. Además, esta respuesta realmente no agrega nada, simplemente reempaca el enfoque existente (roto) en la indirección adicional, lo que no ayuda – Adam

+0

Me permito diferir aquí. NSDate está bien para ciertas operaciones. Como dije, es una solución simplista a una pregunta muy difícil. Estoy de acuerdo en que la exactitud de la respuesta elegida es ciertamente una mejor opción. Dicho esto, todavía me gusta usar 2 líneas rápidas de código para tener una idea de los tiempos en mis programas. – bladnman

0

@bladnman Me encanta su cosa cronómetro .. Yo lo uso todo el tiempo .. Aquí hay un pequeño bloque escribí que elimina la necesidad de la llamada de cierre, y lo hace aún más fácil (si eso parecía posible) para usar, jajaja.

+(void)stopwatch:(NSString*)name timing:(void(^)())block { 
    [MMStopwatch start:name]; 
    block(); 
    [MMStopwatch stop: name]; 
} 

a continuación, puedes llamar a donde quiera ..

[MMStopwatch stopwatch:@"slowAssFunction" timing:^{ 
    NSLog(@"%@",@"someLongAssFunction"); 
}]; 

someLongAssFunction

-> Stopwatch: [slowAssFunction] runtime:[0.054435] 

Usted debe enviar ese lechón a github - que la gente pueda encontrarlo fácilmente/contribuir, etc. . es genial. Gracias.

+0

¡Genial! Me gusta. Usarlo en un bloque tiene sentido. Muy genial. – bladnman

Cuestiones relacionadas