¿Cómo registrar el tiempo de ejecución de un método exactamente en milisegundos?

¿Hay alguna manera de determinar cuánto tiempo necesita ejecutar un método (en milisegundos)?

NSDate *methodStart = [NSDate date]; /* ... Do whatever you need to do ... */ NSDate *methodFinish = [NSDate date]; NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart]; NSLog(@"executionTime = %f", executionTime); 

Rápido:

 let methodStart = NSDate() /* ... Do whatever you need to do ... */ let methodFinish = NSDate() let executionTime = methodFinish.timeIntervalSinceDate(methodStart) print("Execution time: \(executionTime)") 

Swift3:

 let methodStart = Date() /* ... Do whatever you need to do ... */ let methodFinish = Date() let executionTime = methodFinish.timeIntervalSince(methodStart) print("Execution time: \(executionTime)") 

Fácil de usar y tiene una precisión de menos de milisegundos.

Aquí hay dos macros de una línea que uso:

 #define TICK NSDate *startTime = [NSDate date] #define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow]) 

Úselo así:

 TICK; /* ... Do Some Work Here ... */ TOCK; 

Para una sincronización mach_absolute_time( ) en OS X, debe usar mach_absolute_time( ) declarado en :

 #include  #include  // Do some stuff to setup for timing const uint64_t startTime = mach_absolute_time(); // Do some stuff that you want to time const uint64_t endTime = mach_absolute_time(); // Time elapsed in Mach time units. const uint64_t elapsedMTU = endTime - startTime; // Get information for converting from MTU to nanoseconds mach_timebase_info_data_t info; if (mach_timebase_info(&info)) handleErrorConditionIfYoureBeingCareful(); // Get elapsed time in nanoseconds: const double elapsedNS = (double)elapsedMTU * (double)info.numer / (double)info.denom; 

Por supuesto, se aplican las advertencias habituales sobre medidas de grano fino; Probablemente sea mejor que invoques la rutina bajo prueba muchas veces, promediando / tomando un mínimo / alguna otra forma de procesamiento.

Además, tenga en cuenta que puede resultarle más útil perfilar su aplicación ejecutándose con una herramienta como Shark. Esto no le proporcionará la información de tiempo exacta, pero le indicará qué porcentaje del tiempo de la aplicación se está gastando, lo que a menudo es más útil (aunque no siempre).

En Swift, estoy usando:

En mi Macros.swift acabo de agregar

 var startTime = NSDate() func TICK(){ startTime = NSDate() } func TOCK(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__){ println("\(function) Time: \(startTime.timeIntervalSinceNow)\nLine:\(line) File: \(file)") } 

ahora puedes simplemente llamar a cualquier parte

 TICK() // your code to be tracked TOCK() 
  • este código se basa en el código de Ron se traduce a Swift, él tiene los créditos
  • Estoy usando la fecha de inicio a nivel mundial, cualquier sugerencia para mejorar es bienvenida

Sé que esta es una antigua, pero incluso me encontré deambulando por ella nuevamente, así que pensé en enviar mi propia opción aquí.

La mejor apuesta es consultar la publicación de mi blog sobre esto: Cosas de tiempo en Objective-C: un cronómetro

Básicamente, escribí una clase que deja de mirar de una manera muy básica, pero está encapsulada, por lo que solo necesita hacer lo siguiente:

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

Y terminas con:

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

en el registro …

De nuevo, revisa mi publicación por un poco más o descárgala aquí: MMStopwatch.zip

Yo uso macros basadas en la solución de Ron .

 #define TICK(XXX) NSDate *XXX = [NSDate date] #define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow]) 

Para líneas de código:

 TICK(TIME1); /// do job here TOCK(TIME1); 

Veremos en la consola algo así como: TIME1: 0.096618

Puede obtener un tiempo realmente bueno (segundos.parts de segundos) usando esta clase de cronómetro. Utiliza el temporizador de alta precisión en el iPhone. El uso de NSDate solo le proporcionará una (s) segunda (s) precisión. Esta versión está diseñada específicamente para liberación automática y objective-c. También tengo una versión en C ++ si es necesario. Puede encontrar la versión de c ++ aquí .

StopWatch.h

 #import  @interface StopWatch : NSObject { uint64_t _start; uint64_t _stop; uint64_t _elapsed; } -(void) Start; -(void) Stop; -(void) StopWithContext:(NSString*) context; -(double) seconds; -(NSString*) description; +(StopWatch*) stopWatch; -(StopWatch*) init; @end 

StopWatch.m

 #import "StopWatch.h" #include  @implementation StopWatch -(void) Start { _stop = 0; _elapsed = 0; _start = mach_absolute_time(); } -(void) Stop { _stop = mach_absolute_time(); if(_stop > _start) { _elapsed = _stop - _start; } else { _elapsed = 0; } _start = mach_absolute_time(); } -(void) StopWithContext:(NSString*) context { _stop = mach_absolute_time(); if(_stop > _start) { _elapsed = _stop - _start; } else { _elapsed = 0; } NSLog([NSString stringWithFormat:@"[%@] Stopped at %f",context,[self seconds]]); _start = mach_absolute_time(); } -(double) seconds { if(_elapsed > 0) { uint64_t elapsedTimeNano = 0; mach_timebase_info_data_t timeBaseInfo; mach_timebase_info(&timeBaseInfo); elapsedTimeNano = _elapsed * timeBaseInfo.numer / timeBaseInfo.denom; double elapsedSeconds = elapsedTimeNano * 1.0E-9; return elapsedSeconds; } return 0.0; } -(NSString*) description { return [NSString stringWithFormat:@"%f secs.",[self seconds]]; } +(StopWatch*) stopWatch { StopWatch* obj = [[[StopWatch alloc] init] autorelease]; return obj; } -(StopWatch*) init { [super init]; return self; } @end 

La clase tiene un método estático de stopWatch que devuelve un objeto liberado automáticamente.

Una vez que llame al start , use el método de seconds para obtener el tiempo transcurrido. Llamar a start nuevamente para reiniciarlo. O stop para detenerlo. Todavía puede leer la hora ( seconds llamada) en cualquier momento después de llamar a stop .

Ejemplo en una función (llamada de ejecución de tiempo)

 -(void)SomeFunc { StopWatch* stopWatch = [StopWatch stopWatch]; [stopWatch Start]; ... do stuff [stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]]; } 

Utilizo una implementación de clase de una página muy mínima inspirada en el código de esta publicación de blog :

 #import  @interface DBGStopwatch : NSObject + (void)start:(NSString *)name; + (void)stop:(NSString *)name; @end @implementation DBGStopwatch + (NSMutableDictionary *)watches { static NSMutableDictionary *Watches = nil; static dispatch_once_t OnceToken; dispatch_once(&OnceToken, ^{ Watches = @{}.mutableCopy; }); return Watches; } + (double)secondsFromMachTime:(uint64_t)time { mach_timebase_info_data_t timebase; mach_timebase_info(&timebase); return (double)time * (double)timebase.numer / (double)timebase.denom / 1e9; } + (void)start:(NSString *)name { uint64_t begin = mach_absolute_time(); self.watches[name] = @(begin); } + (void)stop:(NSString *)name { uint64_t end = mach_absolute_time(); uint64_t begin = [self.watches[name] unsignedLongLongValue]; DDLogInfo(@"Time taken for %@ %gs", name, [self secondsFromMachTime:(end - begin)]); [self.watches removeObjectForKey:name]; } @end 

El uso de esto es muy simple:

  • simplemente llame a [DBGStopwatch start:@"slow-operation"]; al principio
  • y luego [DBGStopwatch stop:@"slow-operation"]; después del final, para obtener el tiempo

De acuerdo, si tu objective es descubrir qué puedes arreglar para hacerlo más rápido, ese es un objective un poco diferente. Medir el tiempo que toman las funciones es una buena forma de averiguar si lo que hiciste marcó la diferencia, pero para saber qué hacer necesitas una técnica diferente. Esto es lo que recomiendo , y sé que puedes hacerlo en iPhones.

Yo uso esto:

 clock_t start, end; double elapsed; start = clock(); //Start code to time //End code to time end = clock(); elapsed = ((double) (end - start)) / CLOCKS_PER_SEC; NSLog(@"Time: %f",elapsed); 

Pero no estoy seguro acerca de CLOCKS_PER_SEC en el iPhone. Es posible que desee dejarlo apagado.

Yo uso este código:

 #import  float TIME_BLOCK(NSString *key, void (^block)(void)) { mach_timebase_info_data_t info; if (mach_timebase_info(&info) != KERN_SUCCESS) { return -1.0; } uint64_t start = mach_absolute_time(); block(); uint64_t end = mach_absolute_time(); uint64_t elapsed = end - start; uint64_t nanos = elapsed * info.numer / info.denom; float cost = (float)nanos / NSEC_PER_SEC; NSLog(@"key: %@ (%f ms)\n", key, cost * 1000); return cost; } 

Dado que desea optimizar el tiempo que pasa de una página a otra en un UIWebView, ¿no significa que realmente está buscando optimizar el Javascript utilizado para cargar estas páginas?

Con ese fin, miraría un perfilador de WebKit como el que aquí se habla:

http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/

Otro enfoque sería comenzar en un nivel alto, y pensar cómo puede diseñar las páginas web en cuestión para minimizar los tiempos de carga utilizando la carga de página de estilo AJAX en lugar de actualizar toda la vista web cada vez.

 struct TIME { static var ti = mach_timebase_info() static var k: Double = 1 static var mach_stamp: Double { if ti.denom == 0 { mach_timebase_info(&ti) k = Double(ti.numer) / Double(ti.denom) * 1e-6 } return Double(mach_absolute_time()) * k } static var stamp: Double { return NSDate.timeIntervalSinceReferenceDate() * 1000 } } do { let mach_start = TIME.mach_stamp usleep(200000) let mach_diff = TIME.mach_stamp - mach_start let start = TIME.stamp usleep(200000) let diff = TIME.stamp - start print(mach_diff, diff) } 

Aquí hay otra forma, en Swift, de hacer eso usando la palabra clave defer

 func methodName() { let methodStart = Date() defer { let executionTime = Date().timeIntervalSince(methodStart) print("Execution time: \(executionTime)") } // do your stuff here } 

De los documentos de Apple: se utiliza una statement de aplazamiento para ejecutar el código justo antes de transferir el control del progtwig fuera del scope en el que aparece la statement de aplazamiento.

Esto es similar a un bloque try / finally con la ventaja de tener el código relacionado agrupado.

Aquí hay una solución de Swift 3 para el código de bisección en cualquier lugar para encontrar un proceso de larga ejecución.

 var increment: Int = 0 var incrementTime = NSDate() struct Instrumentation { var title: String var point: Int var elapsedTime: Double init(_ title: String, _ point: Int, _ elapsedTime: Double) { self.title = title self.point = point self.elapsedTime = elapsedTime } } var elapsedTimes = [Instrumentation]() 

 func instrument(_ title: String) { increment += 1 let incrementedTime = -incrementTime.timeIntervalSinceNow let newPoint = Instrumentation(title, increment, incrementedTime) elapsedTimes.append(newPoint) incrementTime = NSDate() } 

Uso: –

 instrument("View Did Appear") print("ELAPSED TIMES \(elapsedTimes)") 

Muestra de salida: –

TIEMPOS TRANSCURRIDOS [MyApp.SomeViewController.Instrumentation (título: “Start View Did Load”, punto: 1, elapsedTime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (título: “Terminó de agregar SubViews”, punto: 2, elapsedTime: 0.010585010051727295), MyApp.SomeViewController.Instrumentation (título: “View Did Appear”, punto: 3, elapsedTime: 0.56564098596572876)]

muchas respuestas son raras y realmente no dan resultado en milisegundos (pero en segundos o cualquier otra cosa):

aquí lo que uso para obtener MS (MILLISECONDS):

Rápido:

 let startTime = NSDate().timeIntervalSince1970 * 1000 // your Swift code let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime print("time code execution \(endTimeMinStartTime) ms") 

C objective:

 double startTime = [[NSDate date] timeIntervalSince1970] * 1000.0; // your Objective-C code double endTimeMinusStartTime = [[NSDate date] timeIntervalSince1970] * 1000.0 - startTime; printf("time code execution %f ms\n", endTimeMinusStartTime ); 

Para Swift 4, agregue como delegado a su clase:

 public protocol TimingDelegate: class { var _TICK: Date?{ get set } } extension TimingDelegate { var TICK: Date { _TICK = Date() return(_TICK)! } func TOCK(message: String) { if (_TICK == nil){ print("Call 'TICK' first!") } if (message == ""){ print("\(Date().timeIntervalSince(_TICK!))") } else{ print("\(message): \(Date().timeIntervalSince(_TICK!))") } } } 

Agregar a nuestra clase:

 class MyViewcontroller: UIViewController, TimingDelegate 

Luego agrega a tu clase:

 var _TICK: Date? 

Cuando quieras cronometrar algo, comienza con:

 TICK 

Y termina con:

 TOCK("Timing the XXX routine") 

Yo uso esto en mi biblioteca utils ( Swift 4.2 ):

 public class PrintTimer { let start = Date() let name: String public init(file: String=#file, line: Int=#line, function: String=#function, name: String?=nil) { let file = file.split(separator: "/").last! self.name = name ?? "\(file):\(line) - \(function)" } public func done() { let end = Date() print("\(self.name) took \((end.timeIntervalSinceReferenceDate - self.start.timeIntervalSinceReferenceDate).roundToSigFigs(5)) s.") } } 

… luego llama a un método como:

 func myFunctionCall() { let timer = PrintTimer() // ... timer.done() } 

… que a su vez se ve así en la consola después de ejecutar:

 MyFile.swift:225 - myFunctionCall() took 1.8623 s. 

No es tan conciso como TICK / TOCK arriba, pero es lo suficientemente claro para ver lo que está haciendo e incluye automáticamente lo que se está cronometrando (por archivo, línea al comienzo del método y nombre de la función). Obviamente, si quisiera más detalles (por ejemplo, si no estoy cronometrando una llamada a un método como es el caso habitual, sino que estoy midiendo un bloque dentro de ese método) puedo agregar el parámetro “name =” Foo “” en PrintTimer init para nombrarlo algo además de los valores predeterminados.

Un ejemplo de sincronización de grano fino usando mach_absolute_time() en Swift 4:

 let start = mach_absolute_time() // do something let elapsedMTU = mach_absolute_time() - start var timebase = mach_timebase_info() if mach_timebase_info(&timebase) == 0 { let elapsed = Double(elapsedMTU) * Double(timebase.numer) / Double(timebase.denom) print("render took \(elapsed)") } else { print("timebase error") }