¿Está por casualidad preguntando porque quiere saber qué puede optimizar para hacerlo más rápido?
Mike Dunlavey
1
Sí, estoy usando un UIWebView que está cargando algunas páginas. Quiero optimizar la carga de la página comprobando el tiempo que necesita el método para cargar la página 1 a la página 10.
@BradLarson Si bien parece ser un duplicado, la otra pregunta tiene las mejores respuestas, es decir, allí las respuestas prominentes no sugieren usar (incorrecto) NSDate, sino que explica bien por qué NSDate es la forma incorrecta de hacerlo para este propósito.
Thomas Tempelmann
Respuestas:
437
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 inferior a milisegundos.
Puede registrar este valor con un% f - NSLog ("executeTime =% f", executeTime);
Tony
1
@ Tony olvidaste el @,NSLog(@"executionTime = %f", executionTime);
John Riselvato
66
Acabo de comparar NSDatey mach_absolute_time()en alrededor de 30 ms de nivel. 27 vs. 29, 36 vs. 39, 43 vs. 45. NSDatefue más fácil de usar para mí y los resultados fueron lo suficientemente similares como para no molestarme mach_absolute_time().
nevan king
55
Cualquier cosa basada en NSDate no es segura para medir el tiempo pasado porque el tiempo puede saltar, incluso hacia atrás. Una forma mucho más segura es usar mach_absolute_time, como se muestra en muchas de las otras respuestas aquí. Este debería ser rechazado por ser un mal ejemplo. Vea también la respuesta relacionada que explica todo esto con más detalle: stackoverflow.com/a/30363702/43615
Lo que lo hace tan bueno es que el tic-tac es una frase tan memorable que el registro casi no requiere pensar.
John Riselvato
30
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])hace que esta respuesta también devuelva en qué función se usó el temporizador. Encontré esto útil si utilicé TICK TOCK para cronometrar múltiples funciones.
golmschenk
3
¡Gran idea @golmschenk! También puede buscar __PRETTY_FUNCTION__y __LINE__si desea información más detallada.
Ron
50
Para una sincronización precisa en OS X, debe usar mach_absolute_time( )declarado en <mach/mach_time.h>:
#include<mach/mach_time.h>#include<stdint.h>// Do some stuff to setup for timingconstuint64_t startTime = mach_absolute_time();// Do some stuff that you want to timeconstuint64_t endTime = mach_absolute_time();// Time elapsed in Mach time units.constuint64_t elapsedMTU = endTime - startTime;// Get information for converting from MTU to nanosecondsmach_timebase_info_data_t info;if(mach_timebase_info(&info))
handleErrorConditionIfYoureBeingCareful();// Get elapsed time in nanoseconds:constdouble elapsedNS =(double)elapsedMTU *(double)info.numer /(double)info.denom;
Por supuesto, se aplican las advertencias habituales sobre las mediciones de grano fino; Probablemente sea mejor invocar la rutina bajo prueba muchas veces y promediar / tomar un mínimo / alguna otra forma de procesamiento.
Además, tenga en cuenta que puede resultarle más útil perfilar su aplicación que se ejecuta con una herramienta como Shark. Esto no le dará información de tiempo exacta, pero le dirá qué porcentaje del tiempo de la aplicación se está gastando dónde, que a menudo es más útil (pero no siempre).
Intentando que esto funcione en Swift ... ¿alguna sugerencia?
zumzum
1
"Uno no simplemente ... se convierte a Swift" - Ned Stark
stonedauwg
@zumzum Vea mi respuesta para ver un ejemplo de cómo hacer esto en Swift.
jbg
23
Hay un contenedor conveniente para mach_absolute_time()- es una CACurrentMediaTime()función.
A diferencia NSDateo CFAbsoluteTimeGetCurrent()compensaciones,
mach_absolute_time()y CACurrentMediaTime()están basados en el reloj interno de acogida, a, medida monoatómico preciso, y no está sujeto a cambios en la referencia de tiempo externa, tales como las causadas por las zonas de tiempo, los cambios de horario, o segundos bisiestos.
ObjC
CFTimeInterval startTime =CACurrentMediaTime();// Do your stuff hereCFTimeInterval endTime =CACurrentMediaTime();NSLog(@"Total Runtime: %g s", endTime - startTime);
Rápido
let startTime =CACurrentMediaTime()// Do your stuff here
let endTime =CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
Puede obtener una sincronización realmente buena (segundos, partes de segundos) utilizando esta clase StopWatch. Utiliza el temporizador de alta precisión en el iPhone. El uso de NSDate solo le brindará una segunda (s) precisión (s). Esta versión está diseñada específicamente para la liberación automática y el objetivo-c. Tengo una versión de C ++ también si es necesario. Puede encontrar la versión de c ++ aquí .
La clase tiene una estática. stopWatch método que devuelve un objeto lanzado automáticamente.
Una vez que llame start, use el secondsmétodo para obtener el tiempo transcurrido. Llame startnuevamente para reiniciarlo. O stoppara detenerlo. Aún puede leer la hora (llamada seconds) en cualquier momento después de llamar stop.
Ejemplo en una función (llamada de tiempo de ejecución)
CLOCKS_PER_SEC en iPhone es un valor muy inexacto.
mxcl
1
Bueno saber. Usaría la respuesta de Matthew si tuviera que hacer esto ahora.
David Kanarek
2
Un ejemplo de sincronización precisa utilizando mach_absolute_time()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")}
OK, si su objetivo es averiguar qué puede arreglar para hacerlo más rápido, ese es un objetivo un poco diferente. Medir el tiempo que tardan las funciones es una buena manera 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.
Editar: los revisores me sugirieron que elaborara la respuesta, así que estoy tratando de pensar en una breve forma de decirla.
Su programa general toma suficiente tiempo de reloj para molestarlo. Supongamos que son N segundos.
Estás asumiendo que puedes acelerarlo. La única forma de hacerlo es haciendo que no haga algo que está haciendo en ese tiempo, representando m segundos.
Inicialmente no sabes qué es esa cosa. Puedes adivinar, como lo hacen todos los programadores, pero fácilmente podría ser otra cosa. Sea lo que sea, así es como puedes encontrarlo:
Dado que esa cosa, sea lo que sea, representa la fracción m / N del tiempo, eso significa que si la pausas al azar, la probabilidad es m / N de que la atraparás en el acto de hacer esa cosa. Por supuesto, podría estar haciendo otra cosa, pero pause y vea qué está haciendo.
Ahora hazlo de nuevo. Si lo ves haciendo lo mismo otra vez, puedes sospechar más.
Hazlo 10 veces, o 20. Ahora, si ves que hace algo en particular (no importa cómo lo describas) en múltiples pausas, de las que puedes deshacerte, sabes dos cosas. Sabes más o menos qué fracción de tiempo lleva, pero sabes exactamente qué arreglar.
Si también desea saber exactamente cuánto tiempo se ahorrará, eso es fácil. Mídelo antes, arréglalo y mídelo después. Si realmente estás decepcionado, retira la solución.
¿Ves cómo esto es diferente de medir? Es encontrar, no medir . La mayoría de los perfiles se basan en medir de la manera más exacta posible cuánto tiempo se toma, como si eso fuera importante, y agita con la mano el problema de identificar lo que necesita ser arreglado. La creación de perfiles no encuentra todos los problemas, pero este método sí encuentra todos los problemas, y son los problemas que no encuentra los que lo lastiman.
Aquí hay otra forma, en Swift, de hacerlo usando la palabra clave de aplazamiento
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 usa una declaración de aplazamiento para ejecutar código justo antes de transferir el control del programa fuera del alcance en el que aparece la declaración de aplazamiento.
Esto es similar a un bloque try / finally con la ventaja de tener el código relacionado agrupado.
Lo uso en mi biblioteca de utilidades ( Swift 4.2 ):
publicclassPrintTimer{
let start =Date()
let name:Stringpublic 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 llame 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 anterior, pero es lo suficientemente claro como para ver lo que está haciendo e incluye automáticamente lo que se está cronometrando (por archivo, línea al inicio del método y nombre de la función). Obviamente, si quisiera más detalles (por ejemplo, si no solo estoy cronometrando una llamada al método como es el caso habitual, sino que estoy cronometrando un bloque dentro de ese método), puedo agregar el parámetro "name =" Foo "" en el init PrintTimer por nombrarlo además de los valores predeterminados.
Dado que desea optimizar el tiempo de pasar 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 se menciona aquí:
Otro enfoque sería comenzar a un alto nivel 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áginas 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=1static var mach_stamp:Double{if ti.denom ==0{
mach_timebase_info(&ti)
k =Double(ti.numer)/Double(ti.denom)*1e-6}returnDouble(mach_absolute_time())* k
}static var stamp:Double{returnNSDate.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 una solución Swift 3 para dividir el código en cualquier lugar para encontrar un proceso de larga ejecución.
var increment:Int=0
var incrementTime =NSDate()structInstrumentation{
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)")
Salida de muestra: -
TIEMPOS TRANSCURRIDOS [MyApp.SomeViewController.Instrumentation (título: "Start View Did Load", punto: 1, elapsedTime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (título: "Finished Adding SubViews", punto: 2, elapsedTime: 0.0105850100517, MyApp.SomeViewController.Instrumentation (título: "La vista apareció", punto: 3, tiempo transcurrido: 0.56564098596572876)]
muchas respuestas son extrañas 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")
Respuestas:
Rápido:
Swift3:
Fácil de usar y tiene una precisión inferior a milisegundos.
fuente
NSLog(@"executionTime = %f", executionTime);
NSDate
ymach_absolute_time()
en alrededor de 30 ms de nivel. 27 vs. 29, 36 vs. 39, 43 vs. 45.NSDate
fue más fácil de usar para mí y los resultados fueron lo suficientemente similares como para no molestarmemach_absolute_time()
.Aquí hay dos macros de una línea que uso:
Úselo así:
fuente
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
hace que esta respuesta también devuelva en qué función se usó el temporizador. Encontré esto útil si utilicé TICK TOCK para cronometrar múltiples funciones.__PRETTY_FUNCTION__
y__LINE__
si desea información más detallada.Para una sincronización precisa en OS X, debe usar
mach_absolute_time( )
declarado en<mach/mach_time.h>
:Por supuesto, se aplican las advertencias habituales sobre las mediciones de grano fino; Probablemente sea mejor invocar la rutina bajo prueba muchas veces y promediar / tomar un mínimo / alguna otra forma de procesamiento.
Además, tenga en cuenta que puede resultarle más útil perfilar su aplicación que se ejecuta con una herramienta como Shark. Esto no le dará información de tiempo exacta, pero le dirá qué porcentaje del tiempo de la aplicación se está gastando dónde, que a menudo es más útil (pero no siempre).
fuente
Hay un contenedor conveniente para
mach_absolute_time()
- es unaCACurrentMediaTime()
función.ObjC
Rápido
fuente
NSDate
.En Swift, estoy usando:
En mi Macros.swift acabo de agregar
ahora puedes llamar a cualquier parte
fuente
\(-startTime.timeIntervalSinceNow)
(nótese la negativa)Sé que este es viejo, pero incluso me encontré deambulando de nuevo, así que pensé en presentar mi propia opción aquí.
La mejor apuesta es revisar mi publicación de blog sobre esto: Cronometraje de cosas en Objective-C: Un cronómetro
Básicamente, escribí una clase que deja de mirar de una manera muy básica pero está encapsulada de modo que solo necesita hacer lo siguiente:
Y terminas con:
en el registro ...
Nuevamente, mira mi publicación para un poco más o descárgala aquí: MMStopwatch.zip
fuente
Yo uso macros basadas en la solución de Ron .
Para líneas de código:
veremos en la consola algo como: TIME1: 0.096618
fuente
Utilizo una implementación mínima de clase de una página inspirada en el código de esta publicación de blog :
Su uso es muy simple:
[DBGStopwatch start:@"slow-operation"];
al principio[DBGStopwatch stop:@"slow-operation"];
después del final, para tener el tiempofuente
Puede obtener una sincronización realmente buena (segundos, partes de segundos) utilizando esta clase StopWatch. Utiliza el temporizador de alta precisión en el iPhone. El uso de NSDate solo le brindará una segunda (s) precisión (s). Esta versión está diseñada específicamente para la liberación automática y el objetivo-c. Tengo una versión de C ++ también si es necesario. Puede encontrar la versión de c ++ aquí .
StopWatch.h
StopWatch.m
La clase tiene una estática.
stopWatch
método que devuelve un objeto lanzado automáticamente.Una vez que llame
start
, use elseconds
método para obtener el tiempo transcurrido. Llamestart
nuevamente para reiniciarlo. Ostop
para detenerlo. Aún puede leer la hora (llamadaseconds
) en cualquier momento después de llamarstop
.Ejemplo en una función (llamada de tiempo de ejecución)
fuente
Yo uso este código:
fuente
Yo uso esto:
Pero no estoy seguro acerca de CLOCKS_PER_SEC en el iPhone. Es posible que desee dejarlo.
fuente
Un ejemplo de sincronización precisa utilizando
mach_absolute_time()
Swift 4:fuente
OK, si su objetivo es averiguar qué puede arreglar para hacerlo más rápido, ese es un objetivo un poco diferente. Medir el tiempo que tardan las funciones es una buena manera 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.
Editar: los revisores me sugirieron que elaborara la respuesta, así que estoy tratando de pensar en una breve forma de decirla.
Su programa general toma suficiente tiempo de reloj para molestarlo. Supongamos que son N segundos.
Estás asumiendo que puedes acelerarlo. La única forma de hacerlo es haciendo que no haga algo que está haciendo en ese tiempo, representando m segundos.
Inicialmente no sabes qué es esa cosa. Puedes adivinar, como lo hacen todos los programadores, pero fácilmente podría ser otra cosa. Sea lo que sea, así es como puedes encontrarlo:
Dado que esa cosa, sea lo que sea, representa la fracción m / N del tiempo, eso significa que si la pausas al azar, la probabilidad es m / N de que la atraparás en el acto de hacer esa cosa. Por supuesto, podría estar haciendo otra cosa, pero pause y vea qué está haciendo.
Ahora hazlo de nuevo. Si lo ves haciendo lo mismo otra vez, puedes sospechar más.
Hazlo 10 veces, o 20. Ahora, si ves que hace algo en particular (no importa cómo lo describas) en múltiples pausas, de las que puedes deshacerte, sabes dos cosas. Sabes más o menos qué fracción de tiempo lleva, pero sabes exactamente qué arreglar.
Si también desea saber exactamente cuánto tiempo se ahorrará, eso es fácil. Mídelo antes, arréglalo y mídelo después. Si realmente estás decepcionado, retira la solución.
¿Ves cómo esto es diferente de medir? Es encontrar, no medir . La mayoría de los perfiles se basan en medir de la manera más exacta posible cuánto tiempo se toma, como si eso fuera importante, y agita con la mano el problema de identificar lo que necesita ser arreglado. La creación de perfiles no encuentra todos los problemas, pero este método sí encuentra todos los problemas, y son los problemas que no encuentra los que lo lastiman.
fuente
Aquí hay otra forma, en Swift, de hacerlo usando la palabra clave de aplazamiento
De los documentos de Apple : se usa una declaración de aplazamiento para ejecutar código justo antes de transferir el control del programa fuera del alcance en el que aparece la declaración de aplazamiento.
Esto es similar a un bloque try / finally con la ventaja de tener el código relacionado agrupado.
fuente
Lo uso en mi biblioteca de utilidades ( Swift 4.2 ):
... luego llame a un método como:
... que a su vez se ve así en la consola después de ejecutar:
No es tan conciso como TICK / TOCK anterior, pero es lo suficientemente claro como para ver lo que está haciendo e incluye automáticamente lo que se está cronometrando (por archivo, línea al inicio del método y nombre de la función). Obviamente, si quisiera más detalles (por ejemplo, si no solo estoy cronometrando una llamada al método como es el caso habitual, sino que estoy cronometrando un bloque dentro de ese método), puedo agregar el parámetro "name =" Foo "" en el init PrintTimer por nombrarlo además de los valores predeterminados.
fuente
Dado que desea optimizar el tiempo de pasar 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 se menciona aquí:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Otro enfoque sería comenzar a un alto nivel 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áginas de estilo AJAX en lugar de actualizar toda la vista web cada vez.
fuente
fuente
Aquí hay una solución Swift 3 para dividir el código en cualquier lugar para encontrar un proceso de larga ejecución.
Uso: -
Salida de muestra: -
fuente
muchas respuestas son extrañas y realmente no dan resultado en milisegundos (pero en segundos o cualquier otra cosa):
Aquí lo que uso para obtener MS (MILLISECONDS):
Rápido:
C objetivo:
fuente
Para Swift 4, agregue como delegado a su clase:
Añadir a nuestra clase:
Luego agregue a su clase:
Cuando quieras cronometrar algo, comienza con:
Y termina con:
fuente