Por acaso você está perguntando, porque deseja descobrir o que pode otimizar para torná-lo mais rápido?
Mike Dunlavey
1
Sim, estou usando um UIWebView que está carregando algumas páginas. Quero otimizar o pageloading verificando o tempo, o método precisa de carregamento da página 1 a página 10.
@BradLarson Embora pareça duplicada, a outra pergunta tem as melhores respostas, ou seja, as respostas mais importantes não estão sugerindo o uso (incorreto) do NSDate, mas sim explicando por que o NSDate é a maneira errada de fazer isso.
Thomas Tempelmann
Respostas:
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 e com precisão abaixo de milissegundos.
Você pode registrar esse valor com um% f - NSLog ("ExecutionTime =% f", ExecutionTime);
Tony
1
@ NSLog(@"executionTime = %f", executionTime);
Tony
6
Acabei de comparar NSDatee mach_absolute_time()em torno de 30ms. 27 x 29, 36 x 39, 43 x 45. NSDatefoi mais fácil de usar e os resultados foram semelhantes o suficiente para não incomodar mach_absolute_time().
Nevan king 31/07/2013
5
Qualquer coisa baseada no NSDate não é segura para medir o tempo passado, porque o tempo pode saltar, mesmo para trás. Uma maneira muito mais segura é usar mach_absolute_time, como mostrado em muitas das outras respostas aqui. Este deve ser votado por ser um mau exemplo. Ver também a resposta relacionada que explica tudo isso em mais detalhes: stackoverflow.com/a/30363702/43615
O que torna isso tão bom é que tick-tock é uma frase tão memorável que o registro quase não requer reflexão.
John Riselvato
30
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])faz com que esta resposta também retorne em qual função o temporizador foi usado. Achei isso útil se eu usasse o TICK TOCK para cronometrar várias funções.
golmschenk 13/03
3
Ótima idéia @golmschenk! Você também pode analisar __PRETTY_FUNCTION__e __LINE__se deseja informações mais detalhadas.
Ron
50
Para um tempo mais refinado no OS X, você deve usar mach_absolute_time( )declarado em <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;
É claro que as advertências usuais sobre medições refinadas se aplicam; provavelmente é melhor invocar a rotina em teste várias vezes e calcular a média / fazer um mínimo / outra forma de processamento.
Além disso, observe que você pode achar mais útil criar um perfil do aplicativo em execução usando uma ferramenta como o Shark. Isso não fornecerá informações exatas sobre o tempo, mas informará qual porcentagem do tempo do aplicativo está sendo gasta onde, o que geralmente é mais útil (mas nem sempre).
Tentando fazer isso funcionar em Swift ... alguma sugestão?
Zumzum
1
"Uma coisa não simplesmente ... convertido ao Swift" - Ned Stark
stonedauwg
@zumzum Veja minha resposta para um exemplo de como fazer isso no Swift.
Jbg 15/08
23
Existe um invólucro conveniente para mach_absolute_time()- é uma CACurrentMediaTime()função.
Diferentemente NSDateou CFAbsoluteTimeGetCurrent()compensados,
mach_absolute_time()e CACurrentMediaTime()são baseados no relógio interno do host, uma medida precisa e monatômica, e não estão sujeitos a alterações na referência de horário externo, como as causadas por fusos horários, horário de verão ou segundos bissextos.
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")
Você pode obter um timing muito bom (segundos.parts de segundos) usando esta classe StopWatch. Ele usa o timer de alta precisão no iPhone. O uso do NSDate fornece apenas uma precisão de segundo (s). Esta versão foi projetada especificamente para liberação automática e objetivo-c. Eu tenho uma versão c ++, bem se necessário. Você pode encontrar a versão c ++ aqui .
A classe possui um stopWatchmétodo estático que retorna um objeto liberado automaticamente.
Depois de ligar start, use o secondsmétodo para obter o tempo decorrido. Ligue startnovamente para reiniciá-lo. Ou stoppara pará-lo. Você ainda pode ler a hora (chamada seconds) a qualquer momento após a chamada stop.
Exemplo em uma função (chamada de tempo de execução)
Bom saber. Eu usaria a resposta de Matthew se tivesse que fazer isso agora.
David Kanarek 13/03/11
2
Um exemplo de tempo refinado usando mach_absolute_time()no 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, se seu objetivo é descobrir o que você pode corrigir para torná-lo mais rápido, esse é um objetivo um pouco diferente. Medir o tempo que as funções levam é uma boa maneira de descobrir se o que você fez fez a diferença, mas para descobrir o que fazer, você precisa de uma técnica diferente. É isso que eu recomendo e sei que você pode fazer isso em iPhones.
Edit: Os revisores sugeriram que eu elaborasse a resposta, então estou tentando pensar em uma maneira breve de dizê-la.
Seu programa geral leva tempo suficiente para incomodá-lo. Suponha que sejam N segundos.
Você está assumindo que pode acelerar. A única maneira de fazer isso é fazê-lo não fazer algo que está fazendo naquele tempo, contabilizando m segundos.
Você inicialmente não sabe o que é isso. Você pode adivinhar, como todos os programadores, mas poderia ser facilmente outra coisa. Seja o que for, veja como você pode encontrá-lo:
Como essa coisa, seja o que for, é responsável pela fração m / N do tempo, isso significa que, se você pausar aleatoriamente, a probabilidade é m / N de que você a capturará no ato de fazer a coisa. Claro que pode estar fazendo outra coisa, mas faça uma pausa e veja o que está fazendo.
Agora faça de novo. Se você vê fazendo a mesma coisa novamente, pode ficar mais desconfiado.
Faça 10 vezes ou 20. Agora, se você vê algo em particular (não importa como você o descreve) em várias pausas, das quais você pode se livrar, você sabe duas coisas. Você sabe muito bem qual é a fração do tempo que leva, mas sabe exatamente o que consertar.
Se você também quer saber exatamente quanto tempo será economizado, isso é fácil. Meça antes, corrija e depois. Se você está realmente desapontado, volte à solução.
Você vê como isso é diferente de medir? É encontrar, não medir . A maioria dos perfis baseia-se em medir o mais exatamente possível quanto tempo é necessário, como se isso fosse importante, e acenou com mão o problema de identificar o que precisa ser corrigido. A criação de perfil não encontra todos os problemas, mas esse método encontra todos os problemas, e são os problemas que você não acha que o machucam.
Aqui está outra maneira, no Swift, de fazer isso usando a palavra-chave adiar
func methodName(){
let methodStart =Date()
defer {
let executionTime =Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")}// do your stuff here}
Dos documentos da Apple : Uma declaração defer é usada para executar código imediatamente antes de transferir o controle do programa para fora do escopo em que a declaração defer aparece.
Isso é semelhante a um bloco try / finalmente com a vantagem de ter o código relacionado agrupado.
Eu uso isso na minha biblioteca de utilitários ( 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.")}}
... então chame um método como:
func myFunctionCall(){
let timer =PrintTimer()// ...
timer.done()}
... que por sua vez se parece com isso no console após a execução:
MyFile.swift:225- myFunctionCall() took 1.8623 s.
Não é tão conciso quanto o TICK / TOCK acima, mas é claro o suficiente para ver o que está fazendo e inclui automaticamente o que está sendo cronometrado (por arquivo, linha no início do método e nome da função). Obviamente, se eu quisesse mais detalhes (por exemplo, se eu não estiver apenas cronometrando uma chamada de método, como é o caso usual, mas estiver cronometrando um bloco nesse método), posso adicionar o parâmetro "name =" Foo "" no init PrintTimer para nomear algo além dos padrões.
Como você deseja otimizar o tempo passando de uma página para outra em um UIWebView, isso não significa que você realmente deseja otimizar o Javascript usado no carregamento dessas páginas?
Para esse fim, eu examinaria um criador de perfil do WebKit como o mencionado aqui:
Outra abordagem seria começar em um nível alto e pensar em como você pode projetar as páginas da Web em questão para minimizar o tempo de carregamento usando o carregamento de páginas no estilo AJAX, em vez de atualizar a visualização da Web toda a 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)}
Aqui está uma solução Swift 3 para dividir o código em qualquer lugar e encontrar um processo demorado.
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)")
Saída de amostra: -
TIMES ELAPSED [MyApp.SomeViewController.Instrumentation (título: "A exibição inicial foi carregada", ponto: 1, decorridoTime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (título: "Finalização da adição de sub-visualizações", ponto: 2, tempo decorrido: 0.010585010051727) MyApp.SomeViewController.Instrumentation (título: "A exibição apareceu", ponto: 3, tempo decorrido: 0.56564098596572876)]
muitas respostas são estranhas e não dão resultado em milissegundos (mas em segundos ou qualquer outra coisa):
aqui o que eu uso para obter MS (MILLISECONDS):
Rápido:
let startTime =NSDate().timeIntervalSince1970 *1000// your Swift code
let endTimeMinusStartTime =NSDate().timeIntervalSince1970 *1000- startTime
print("time code execution \(endTimeMinStartTime) ms")
Respostas:
Rápido:
Swift3:
Fácil de usar e com precisão abaixo de milissegundos.
fonte
NSLog(@"executionTime = %f", executionTime);
NSDate
emach_absolute_time()
em torno de 30ms. 27 x 29, 36 x 39, 43 x 45.NSDate
foi mais fácil de usar e os resultados foram semelhantes o suficiente para não incomodarmach_absolute_time()
.Aqui estão duas macros de uma linha que eu uso:
Use-o assim:
fonte
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
faz com que esta resposta também retorne em qual função o temporizador foi usado. Achei isso útil se eu usasse o TICK TOCK para cronometrar várias funções.__PRETTY_FUNCTION__
e__LINE__
se deseja informações mais detalhadas.Para um tempo mais refinado no OS X, você deve usar
mach_absolute_time( )
declarado em<mach/mach_time.h>
:É claro que as advertências usuais sobre medições refinadas se aplicam; provavelmente é melhor invocar a rotina em teste várias vezes e calcular a média / fazer um mínimo / outra forma de processamento.
Além disso, observe que você pode achar mais útil criar um perfil do aplicativo em execução usando uma ferramenta como o Shark. Isso não fornecerá informações exatas sobre o tempo, mas informará qual porcentagem do tempo do aplicativo está sendo gasta onde, o que geralmente é mais útil (mas nem sempre).
fonte
Existe um invólucro conveniente para
mach_absolute_time()
- é umaCACurrentMediaTime()
função.ObjC
Rápido
fonte
NSDate
.No Swift, estou usando:
No meu Macros.swift acabei de adicionar
agora você pode simplesmente ligar para qualquer lugar
fonte
\(-startTime.timeIntervalSinceNow)
(notar o negativo)Sei que é antiga, mas até me vi vagando novamente, então pensei em enviar minha própria opção aqui.
A melhor aposta é dar uma olhada no meu blog: Cronometrando as coisas no Objective-C: Um cronômetro
Basicamente, escrevi uma classe que para de assistir de uma maneira muito básica, mas é encapsulada para que você só precise fazer o seguinte:
E você acaba com:
no log ...
Mais uma vez, confira meu post um pouco mais ou faça o download aqui: MMStopwatch.zip
fonte
Eu uso macros baseadas na solução de Ron .
Para linhas de código:
veremos no console algo como: TIME1: 0.096618
fonte
Eu uso uma implementação de classe de página muito mínima, inspirada no código desta postagem do blog :
O uso dele é muito simples:
[DBGStopwatch start:@"slow-operation"];
no começo[DBGStopwatch stop:@"slow-operation"];
depois do final, para ganhar tempofonte
Você pode obter um timing muito bom (segundos.parts de segundos) usando esta classe StopWatch. Ele usa o timer de alta precisão no iPhone. O uso do NSDate fornece apenas uma precisão de segundo (s). Esta versão foi projetada especificamente para liberação automática e objetivo-c. Eu tenho uma versão c ++, bem se necessário. Você pode encontrar a versão c ++ aqui .
StopWatch.h
StopWatch.m
A classe possui um
stopWatch
método estático que retorna um objeto liberado automaticamente.Depois de ligar
start
, use oseconds
método para obter o tempo decorrido. Liguestart
novamente para reiniciá-lo. Oustop
para pará-lo. Você ainda pode ler a hora (chamadaseconds
) a qualquer momento após a chamadastop
.Exemplo em uma função (chamada de tempo de execução)
fonte
Eu uso este código:
fonte
Eu uso isso:
Mas não tenho certeza sobre CLOCKS_PER_SEC no iPhone. Você pode querer deixar de fora.
fonte
Um exemplo de tempo refinado usando
mach_absolute_time()
no Swift 4:fonte
OK, se seu objetivo é descobrir o que você pode corrigir para torná-lo mais rápido, esse é um objetivo um pouco diferente. Medir o tempo que as funções levam é uma boa maneira de descobrir se o que você fez fez a diferença, mas para descobrir o que fazer, você precisa de uma técnica diferente. É isso que eu recomendo e sei que você pode fazer isso em iPhones.
Edit: Os revisores sugeriram que eu elaborasse a resposta, então estou tentando pensar em uma maneira breve de dizê-la.
Seu programa geral leva tempo suficiente para incomodá-lo. Suponha que sejam N segundos.
Você está assumindo que pode acelerar. A única maneira de fazer isso é fazê-lo não fazer algo que está fazendo naquele tempo, contabilizando m segundos.
Você inicialmente não sabe o que é isso. Você pode adivinhar, como todos os programadores, mas poderia ser facilmente outra coisa. Seja o que for, veja como você pode encontrá-lo:
Como essa coisa, seja o que for, é responsável pela fração m / N do tempo, isso significa que, se você pausar aleatoriamente, a probabilidade é m / N de que você a capturará no ato de fazer a coisa. Claro que pode estar fazendo outra coisa, mas faça uma pausa e veja o que está fazendo.
Agora faça de novo. Se você vê fazendo a mesma coisa novamente, pode ficar mais desconfiado.
Faça 10 vezes ou 20. Agora, se você vê algo em particular (não importa como você o descreve) em várias pausas, das quais você pode se livrar, você sabe duas coisas. Você sabe muito bem qual é a fração do tempo que leva, mas sabe exatamente o que consertar.
Se você também quer saber exatamente quanto tempo será economizado, isso é fácil. Meça antes, corrija e depois. Se você está realmente desapontado, volte à solução.
Você vê como isso é diferente de medir? É encontrar, não medir . A maioria dos perfis baseia-se em medir o mais exatamente possível quanto tempo é necessário, como se isso fosse importante, e acenou com mão o problema de identificar o que precisa ser corrigido. A criação de perfil não encontra todos os problemas, mas esse método encontra todos os problemas, e são os problemas que você não acha que o machucam.
fonte
Aqui está outra maneira, no Swift, de fazer isso usando a palavra-chave adiar
Dos documentos da Apple : Uma declaração defer é usada para executar código imediatamente antes de transferir o controle do programa para fora do escopo em que a declaração defer aparece.
Isso é semelhante a um bloco try / finalmente com a vantagem de ter o código relacionado agrupado.
fonte
Eu uso isso na minha biblioteca de utilitários ( Swift 4.2 ):
... então chame um método como:
... que por sua vez se parece com isso no console após a execução:
Não é tão conciso quanto o TICK / TOCK acima, mas é claro o suficiente para ver o que está fazendo e inclui automaticamente o que está sendo cronometrado (por arquivo, linha no início do método e nome da função). Obviamente, se eu quisesse mais detalhes (por exemplo, se eu não estiver apenas cronometrando uma chamada de método, como é o caso usual, mas estiver cronometrando um bloco nesse método), posso adicionar o parâmetro "name =" Foo "" no init PrintTimer para nomear algo além dos padrões.
fonte
Como você deseja otimizar o tempo passando de uma página para outra em um UIWebView, isso não significa que você realmente deseja otimizar o Javascript usado no carregamento dessas páginas?
Para esse fim, eu examinaria um criador de perfil do WebKit como o mencionado aqui:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Outra abordagem seria começar em um nível alto e pensar em como você pode projetar as páginas da Web em questão para minimizar o tempo de carregamento usando o carregamento de páginas no estilo AJAX, em vez de atualizar a visualização da Web toda a cada vez.
fonte
fonte
Aqui está uma solução Swift 3 para dividir o código em qualquer lugar e encontrar um processo demorado.
Uso: -
Saída de amostra: -
fonte
muitas respostas são estranhas e não dão resultado em milissegundos (mas em segundos ou qualquer outra coisa):
aqui o que eu uso para obter MS (MILLISECONDS):
Rápido:
Objetivo-C:
fonte
Para o Swift 4, adicione como Delegado à sua turma:
Adicione à nossa turma:
Em seguida, adicione à sua turma:
Quando você quiser cronometrar alguma coisa, comece com:
E termine com:
fonte