Czy przypadkiem pytasz, ponieważ chcesz dowiedzieć się, co możesz zoptymalizować, aby przyspieszyć?
Mike Dunlavey
1
Tak, używam UIWebView, który ładuje niektóre strony. Chcę zoptymalizować ładowanie stron poprzez sprawdzenie czasu potrzebnego do załadowania strony 1 do strony 10.
@BradLarson Chociaż wydaje się być duplikatem, drugie pytanie ma lepsze odpowiedzi, tzn. Tam, gdzie wybitne odpowiedzi nie sugerują użycia (niepoprawnego) NSDate, ale dobrze wyjaśnia, dlaczego NSDate jest niewłaściwym sposobem do tego celu.
Thomas Tempelmann,
Odpowiedzi:
437
NSDate*methodStart =[NSDate date];/* ... Do whatever you need to do ... */NSDate*methodFinish =[NSDate date];NSTimeInterval executionTime =[methodFinish timeIntervalSinceDate:methodStart];NSLog(@"executionTime = %f", executionTime);
Szybki:
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)")
Możesz zarejestrować tę wartość za pomocą% f - NSLog ("wykonanieTime =% f", wykonanieTime);
Tony
1
@ Tony zapomniałeś @,NSLog(@"executionTime = %f", executionTime);
John Riselvato
6
Właśnie porównałem NSDatei mach_absolute_time()na poziomie około 30 ms. 27 vs. 29, 36 vs. 39, 43 vs. 45. NSDatebyło dla mnie łatwiejsze w użyciu, a wyniki były na tyle podobne, że nie zawracałem sobie tym głowy mach_absolute_time().
Nevan King
5
Wszystko oparte na NSDate nie jest bezpieczne do pomiaru upływu czasu, ponieważ czas może skakać, nawet do tyłu. O wiele bezpieczniejszym sposobem jest użycie mach_absolute_time, jak pokazano w wielu innych odpowiedziach tutaj. Ten należy uznać za zły przykład. Zobacz także pokrewną odpowiedź, która wyjaśnia to wszystko bardziej szczegółowo: stackoverflow.com/a/30363702/43615
To, co czyni to tak dobrym, to fakt, że tik tak zapada w pamięć, że rejestrowanie prawie nie wymaga zastanowienia.
John Riselvato,
30
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])sprawia, że ta odpowiedź również zwraca, w której funkcji użyto timera. Uznałem to za użyteczne, jeśli użyłem TICK TOCK do pomiaru wielu funkcji.
golmschenk
3
Świetny pomysł @golmschenk! Możesz także zajrzeć __PRETTY_FUNCTION__i __LINE__uzyskać bardziej szczegółowe informacje.
Ron
50
W celu uzyskania precyzyjnego pomiaru czasu w systemie OS X należy użyć mach_absolute_time( )deklarowanego w <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;
Oczywiście obowiązują zwykłe zastrzeżenia dotyczące drobnoziarnistych pomiarów; prawdopodobnie najlepiej jest przywoływać testowaną procedurę wiele razy i uśredniać / przyjmować minimum / inną formę przetwarzania.
Ponadto pamiętaj, że bardziej przydatne może być profilowanie aplikacji przy użyciu narzędzia takiego jak Shark. Nie da ci to dokładnych informacji o czasie, ale powie ci, jaki procent czasu aplikacji spędza gdzie, co jest często bardziej przydatne (ale nie zawsze).
Próbujesz sprawić, żeby zadziałało w Swift ... jakieś sugestie?
zumzum
1
„Nie wystarczy ... przejść na Swift” - Ned Stark
stonedauwg
@zumzum Zobacz moją odpowiedź na przykład robienia tego w Swift.
jbg
23
Jest wygodne opakowanie mach_absolute_time()- to CACurrentMediaTime()funkcja.
W przeciwieństwie NSDatelub CFAbsoluteTimeGetCurrent()offsety,
mach_absolute_time()a CACurrentMediaTime()oparte są na wewnętrznym zegarze gospodarza, precyzyjny, monoatomowego środka, i nie podlega zmianom w czasie zewnętrznych punktów odniesienia, takich jak te spowodowane przez strefy czasowe, czas letni, lub sekundy przestępne.
ObjC
CFTimeInterval startTime =CACurrentMediaTime();// Do your stuff hereCFTimeInterval endTime =CACurrentMediaTime();NSLog(@"Total Runtime: %g s", endTime - startTime);
Szybki
let startTime =CACurrentMediaTime()// Do your stuff here
let endTime =CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
Możesz uzyskać naprawdę dobry czas (sekundy. Kilka sekund) za pomocą tej klasy StopWatch. Korzysta z precyzyjnego timera w iPhonie. Korzystanie z NSDate zapewni jedynie dokładność sekundową. Ta wersja jest zaprojektowana specjalnie dla autorelease i celu-c. W razie potrzeby mam również wersję c ++. Możesz znaleźć wersję c ++ tutaj .
Klasa ma statyczny stopWatch metodę , która zwraca automatycznie wydany obiekt.
Po wywołaniu startużyj secondsmetody, aby uzyskać upływ czasu. Zadzwoń startponownie, aby go ponownie uruchomić. Lub stopto zatrzymać. Nadal możesz odczytać czas (połączenie seconds) w dowolnym momencie po połączeniu stop.
Przykład w funkcji A (wywołanie czasowe wykonania)
CLOCKS_PER_SEC na iPhonie jest bardzo niedokładną wartością.
mxcl
1
Dobrze wiedzieć. Użyłbym odpowiedzi Matthew, gdybym musiał to zrobić teraz.
David Kanarek
2
Przykład precyzyjnego pomiaru czasu mach_absolute_time()w 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, jeśli Twoim celem jest ustalenie, co możesz naprawić, aby przyspieszyć, to trochę inny cel. Mierzenie czasu potrzebnego na działanie funkcji jest dobrym sposobem, aby dowiedzieć się, czy to, co zrobiłeś, miało znaczenie, ale aby dowiedzieć się, co zrobić , potrzebujesz innej techniki. Oto co polecam i wiem, że możesz to zrobić na iPhone'ach.
Edycja: recenzenci sugerowali, że opracowałem odpowiedź, więc staram się wymyślić krótki sposób, aby to powiedzieć.
Twój ogólny program zajmuje Ci wystarczająco dużo czasu. Załóżmy, że to N sekund.
Zakładasz, że możesz to przyspieszyć. Jedynym sposobem, aby to zrobić, jest sprawienie, aby w tym czasie nie robiła czegoś, co odpowiada m sekundom.
Początkowo nie wiesz, co to jest. Możesz zgadywać, jak wszyscy programiści, ale może to być coś innego. Cokolwiek to jest, oto jak to znaleźć:
Ponieważ ta rzecz, cokolwiek to jest, stanowi ułamek m / N czasu, oznacza to, że jeśli losowo ją zatrzymasz, prawdopodobieństwo wynosi m / N , że złapiesz ją podczas robienia tego. Oczywiście może robić coś innego, ale zatrzymaj to i zobacz, co robi.
Teraz zrób to jeszcze raz. Jeśli zobaczysz, że robi to samo, możesz być bardziej podejrzliwy.
Zrób to 10 razy lub 20. Teraz, gdy zobaczysz, że robi coś szczególnego (bez względu na to, jak to opisujesz) po wielu przerwach, których możesz się pozbyć, wiesz dwie rzeczy. Wiesz z grubsza, jaki ułamek czasu zajmuje, ale bardzo dokładnie wiesz , co naprawić.
Jeśli chcesz również bardzo dokładnie wiedzieć , ile czasu zaoszczędzisz, to proste. Zmierz to wcześniej, napraw i zmierz później. Jeśli jesteś naprawdę rozczarowany, wycofaj się.
Czy widzisz, czym różni się to od pomiaru? Znajduje , nie mierzy . Większość profilowania opiera się na jak najdokładniejszym pomiarze ilości czasu, co jest ważne, i macha ręką w celu ustalenia, co należy naprawić. Profilowanie nie powoduje znalezienia każdego problemu, ale ta metoda odnajduje każdy problem i bolą Cię problemy, których nie znajdziesz.
Oto inny sposób, w Swift, aby to zrobić za pomocą słowa kluczowego odroczenia
func methodName(){
let methodStart =Date()
defer {
let executionTime =Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")}// do your stuff here}
Z dokumentacji Apple'a : Instrukcja odroczenia służy do wykonania kodu tuż przed przeniesieniem kontroli programu poza zakres, w którym pojawia się instrukcja odroczenia.
Jest to podobne do bloku try / wreszcie z zaletą zgrupowania powiązanego kodu.
Używam tego w mojej bibliotece utils ( 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.")}}
... następnie wywołaj metodę taką jak:
func myFunctionCall(){
let timer =PrintTimer()// ...
timer.done()}
... który z kolei wygląda tak w konsoli po uruchomieniu:
MyFile.swift:225- myFunctionCall() took 1.8623 s.
Nie tak zwięzłe jak TICK / TOCK powyżej, ale jest wystarczająco jasne, aby zobaczyć, co robi i automatycznie uwzględnia to, co jest mierzone (według pliku, linii na początku metody i nazwy funkcji). Oczywiście, jeśli chciałbym uzyskać więcej szczegółów (np. Jeśli nie tylko odmierzam czas wywołania metody, jak to zwykle bywa, ale zamiast tego mierzę czas w bloku w tej metodzie), mogę dodać parametr „name =" Foo ”do parametru PrintTimer init nazwać to coś oprócz wartości domyślnych.
Skoro chcesz zoptymalizować czas przejścia z jednej strony na drugą w UIWebView, czy to nie znaczy, że naprawdę chcesz zoptymalizować JavaScript używany do ładowania tych stron?
W tym celu spojrzałbym na profilera WebKit, o którym tu mówiono:
Innym podejściem byłoby rozpoczęcie od wysokiego poziomu i zastanowienie się, jak zaprojektować dane strony internetowe, aby zminimalizować czas ładowania przy użyciu ładowania strony w stylu AJAX zamiast odświeżania całego widoku strony za każdym razem.
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)}
Oto rozwiązanie Swift 3 do dzielenia kodu w dowolnym miejscu, aby znaleźć długi proces.
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()}
Stosowanie: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
wiele odpowiedzi jest dziwnych i tak naprawdę nie daje wyniku w milisekundach (ale w sekundach lub cokolwiek innego):
tutaj, czego używam, aby uzyskać MS (MILLISECONDS):
Szybki:
let startTime =NSDate().timeIntervalSince1970 *1000// your Swift code
let endTimeMinusStartTime =NSDate().timeIntervalSince1970 *1000- startTime
print("time code execution \(endTimeMinStartTime) ms")
Odpowiedzi:
Szybki:
Swift3:
Łatwy w użyciu i ma precyzję poniżej milisekundy.
źródło
NSLog(@"executionTime = %f", executionTime);
NSDate
imach_absolute_time()
na poziomie około 30 ms. 27 vs. 29, 36 vs. 39, 43 vs. 45.NSDate
było dla mnie łatwiejsze w użyciu, a wyniki były na tyle podobne, że nie zawracałem sobie tym głowymach_absolute_time()
.Oto dwa makra jednowierszowe, których używam:
Użyj tego w ten sposób:
źródło
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
sprawia, że ta odpowiedź również zwraca, w której funkcji użyto timera. Uznałem to za użyteczne, jeśli użyłem TICK TOCK do pomiaru wielu funkcji.__PRETTY_FUNCTION__
i__LINE__
uzyskać bardziej szczegółowe informacje.W celu uzyskania precyzyjnego pomiaru czasu w systemie OS X należy użyć
mach_absolute_time( )
deklarowanego w<mach/mach_time.h>
:Oczywiście obowiązują zwykłe zastrzeżenia dotyczące drobnoziarnistych pomiarów; prawdopodobnie najlepiej jest przywoływać testowaną procedurę wiele razy i uśredniać / przyjmować minimum / inną formę przetwarzania.
Ponadto pamiętaj, że bardziej przydatne może być profilowanie aplikacji przy użyciu narzędzia takiego jak Shark. Nie da ci to dokładnych informacji o czasie, ale powie ci, jaki procent czasu aplikacji spędza gdzie, co jest często bardziej przydatne (ale nie zawsze).
źródło
Jest wygodne opakowanie
mach_absolute_time()
- toCACurrentMediaTime()
funkcja.ObjC
Szybki
źródło
NSDate
.W Swift używam:
W moim Macros.swift właśnie dodałem
możesz teraz dzwonić w dowolnym miejscu
źródło
\(-startTime.timeIntervalSinceNow)
(zauważ negatywne)Wiem, że to jest stara, ale nawet ja znów się po niej wędrowałem, więc pomyślałem, że przedstawię tutaj swoją własną opcję.
Najlepiej jest sprawdzić mój post na blogu na ten temat: Mierzenie czasu w Objective-C: Stoper
Zasadniczo napisałem klasę, która przestaje oglądać w bardzo prosty sposób, ale jest hermetyzowana, więc wystarczy wykonać następujące czynności:
I kończysz na:
w dzienniku ...
Ponownie sprawdź mój post, aby uzyskać więcej informacji lub pobierz go tutaj: MMStopwatch.zip
źródło
Używam makr opartych na rozwiązaniu Rona .
W przypadku wierszy kodu:
zobaczymy w konsoli coś takiego: TIME1: 0.096618
źródło
Używam bardzo minimalnej, jednostronicowej implementacji klasy strony zainspirowanej kodem z tego postu na blogu :
Korzystanie z niego jest bardzo proste:
[DBGStopwatch start:@"slow-operation"];
na początku[DBGStopwatch stop:@"slow-operation"];
po zakończeniu, aby uzyskać czasźródło
Możesz uzyskać naprawdę dobry czas (sekundy. Kilka sekund) za pomocą tej klasy StopWatch. Korzysta z precyzyjnego timera w iPhonie. Korzystanie z NSDate zapewni jedynie dokładność sekundową. Ta wersja jest zaprojektowana specjalnie dla autorelease i celu-c. W razie potrzeby mam również wersję c ++. Możesz znaleźć wersję c ++ tutaj .
StopWatch.h
StopWatch.m
Klasa ma statyczny
stopWatch
metodę , która zwraca automatycznie wydany obiekt.Po wywołaniu
start
użyjseconds
metody, aby uzyskać upływ czasu. Zadzwoństart
ponownie, aby go ponownie uruchomić. Lubstop
to zatrzymać. Nadal możesz odczytać czas (połączenieseconds
) w dowolnym momencie po połączeniustop
.Przykład w funkcji A (wywołanie czasowe wykonania)
źródło
Używam tego kodu:
źródło
Używam tego:
Ale nie jestem pewien CLOCKS_PER_SEC na iPhonie. Może chcesz to wyłączyć.
źródło
Przykład precyzyjnego pomiaru czasu
mach_absolute_time()
w Swift 4:źródło
OK, jeśli Twoim celem jest ustalenie, co możesz naprawić, aby przyspieszyć, to trochę inny cel. Mierzenie czasu potrzebnego na działanie funkcji jest dobrym sposobem, aby dowiedzieć się, czy to, co zrobiłeś, miało znaczenie, ale aby dowiedzieć się, co zrobić , potrzebujesz innej techniki. Oto co polecam i wiem, że możesz to zrobić na iPhone'ach.
Edycja: recenzenci sugerowali, że opracowałem odpowiedź, więc staram się wymyślić krótki sposób, aby to powiedzieć.
Twój ogólny program zajmuje Ci wystarczająco dużo czasu. Załóżmy, że to N sekund.
Zakładasz, że możesz to przyspieszyć. Jedynym sposobem, aby to zrobić, jest sprawienie, aby w tym czasie nie robiła czegoś, co odpowiada m sekundom.
Początkowo nie wiesz, co to jest. Możesz zgadywać, jak wszyscy programiści, ale może to być coś innego. Cokolwiek to jest, oto jak to znaleźć:
Ponieważ ta rzecz, cokolwiek to jest, stanowi ułamek m / N czasu, oznacza to, że jeśli losowo ją zatrzymasz, prawdopodobieństwo wynosi m / N , że złapiesz ją podczas robienia tego. Oczywiście może robić coś innego, ale zatrzymaj to i zobacz, co robi.
Teraz zrób to jeszcze raz. Jeśli zobaczysz, że robi to samo, możesz być bardziej podejrzliwy.
Zrób to 10 razy lub 20. Teraz, gdy zobaczysz, że robi coś szczególnego (bez względu na to, jak to opisujesz) po wielu przerwach, których możesz się pozbyć, wiesz dwie rzeczy. Wiesz z grubsza, jaki ułamek czasu zajmuje, ale bardzo dokładnie wiesz , co naprawić.
Jeśli chcesz również bardzo dokładnie wiedzieć , ile czasu zaoszczędzisz, to proste. Zmierz to wcześniej, napraw i zmierz później. Jeśli jesteś naprawdę rozczarowany, wycofaj się.
Czy widzisz, czym różni się to od pomiaru? Znajduje , nie mierzy . Większość profilowania opiera się na jak najdokładniejszym pomiarze ilości czasu, co jest ważne, i macha ręką w celu ustalenia, co należy naprawić. Profilowanie nie powoduje znalezienia każdego problemu, ale ta metoda odnajduje każdy problem i bolą Cię problemy, których nie znajdziesz.
źródło
Oto inny sposób, w Swift, aby to zrobić za pomocą słowa kluczowego odroczenia
Z dokumentacji Apple'a : Instrukcja odroczenia służy do wykonania kodu tuż przed przeniesieniem kontroli programu poza zakres, w którym pojawia się instrukcja odroczenia.
Jest to podobne do bloku try / wreszcie z zaletą zgrupowania powiązanego kodu.
źródło
Używam tego w mojej bibliotece utils ( Swift 4.2 ):
... następnie wywołaj metodę taką jak:
... który z kolei wygląda tak w konsoli po uruchomieniu:
Nie tak zwięzłe jak TICK / TOCK powyżej, ale jest wystarczająco jasne, aby zobaczyć, co robi i automatycznie uwzględnia to, co jest mierzone (według pliku, linii na początku metody i nazwy funkcji). Oczywiście, jeśli chciałbym uzyskać więcej szczegółów (np. Jeśli nie tylko odmierzam czas wywołania metody, jak to zwykle bywa, ale zamiast tego mierzę czas w bloku w tej metodzie), mogę dodać parametr „name =" Foo ”do parametru PrintTimer init nazwać to coś oprócz wartości domyślnych.
źródło
Skoro chcesz zoptymalizować czas przejścia z jednej strony na drugą w UIWebView, czy to nie znaczy, że naprawdę chcesz zoptymalizować JavaScript używany do ładowania tych stron?
W tym celu spojrzałbym na profilera WebKit, o którym tu mówiono:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Innym podejściem byłoby rozpoczęcie od wysokiego poziomu i zastanowienie się, jak zaprojektować dane strony internetowe, aby zminimalizować czas ładowania przy użyciu ładowania strony w stylu AJAX zamiast odświeżania całego widoku strony za każdym razem.
źródło
źródło
Oto rozwiązanie Swift 3 do dzielenia kodu w dowolnym miejscu, aby znaleźć długi proces.
Stosowanie: -
Próbka wyjściowa: -
źródło
wiele odpowiedzi jest dziwnych i tak naprawdę nie daje wyniku w milisekundach (ale w sekundach lub cokolwiek innego):
tutaj, czego używam, aby uzyskać MS (MILLISECONDS):
Szybki:
Cel C:
źródło
W przypadku Swift 4 dodaj jako delegata do swojej klasy:
Dodaj do naszej klasy:
Następnie dodaj do swojej klasy:
Jeśli chcesz coś zrobić, zacznij od:
I zakończ z:
źródło