Bir yöntemin uygulanması için ne kadar zaman gerektiğini belirlemenin bir yolu var mı (milisaniye cinsinden)?
Bir yöntemin uygulanması için ne kadar zaman gerektiğini belirlemenin bir yolu var mı (milisaniye cinsinden)?
Yanıtlar:
NSDate *methodStart = [NSDate date];
/* ... Do whatever you need to do ... */
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"executionTime = %f", executionTime);
Swift:
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)")
Kullanımı kolaydır ve milisaniyeden daha düşük bir hassasiyete sahiptir.
NSLog(@"executionTime = %f", executionTime);
NSDate
ve mach_absolute_time()
30ms civarında. 27'e karşı 29, 36'ya karşı 39, 43'e karşı 45. NSDate
kullanımı benim için daha kolaydı ve sonuçlar rahatsız etmeyecek kadar benzerdi mach_absolute_time()
.
İşte kullandığım iki tek satır makro:
#define TICK NSDate *startTime = [NSDate date]
#define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
Şöyle kullanın:
TICK;
/* ... Do Some Work Here ... */
TOCK;
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
bu yanıtı da zamanlayıcının kullanıldığı işlevi döndürür. Birden fazla işlevi zamanlamak için TICK TOCK kullandığımda bunu yararlı buldum.
__PRETTY_FUNCTION__
ve __LINE__
daha detaylı bilgi isterseniz.
OS X'te ayrıntılı zamanlama için mach_absolute_time( )
beyan edilenleri kullanmalısınız <mach/mach_time.h>
:
#include <mach/mach_time.h>
#include <stdint.h>
// 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;
Tabii ki ince taneli ölçümlerle ilgili olağan uyarılar geçerlidir; Muhtemelen en iyi şekilde rutin testi birçok kez çağırmanız ve ortalama / minimum / başka bir işleme şekli almanız / almanız gerekir.
Ayrıca, Shark gibi bir araç kullanarak uygulamanızın profilini oluşturmanın daha yararlı olabileceğini lütfen unutmayın . Bu size tam zamanlama bilgisi vermez, ancak uygulamanın zamanının yüzde kaçını nerede harcandığını size söyler , bu genellikle daha yararlıdır (ancak her zaman değil).
İçin uygun bir sarıcı var mach_absolute_time()
- bu bir CACurrentMediaTime()
işlev.
Ofsetlerin
NSDate
veyaCFAbsoluteTimeGetCurrent()
ofsetlerin aksinemach_absolute_time()
veCACurrentMediaTime()
dahili ana bilgisayar saatine dayanır, kesin, monatomik bir ölçüdür ve zaman dilimleri, gün ışığından yararlanma veya artık saniye gibi harici zaman referansındaki değişikliklere tabi değildir.
objc
CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
hızlı
let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
NSDate
.
Swift'te kullanıyorum:
Makrolarımda. Ekledim
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)")
}
şimdi sadece herhangi bir yeri arayabilirsin
TICK()
// your code to be tracked
TOCK()
\(-startTime.timeIntervalSinceNow)
(olumsuz olduğuna dikkat etmeli )
Bunun eski olduğunu biliyorum ama kendimi tekrar geçip dolaşırken buldum, bu yüzden burada kendi seçeneğimi sunacağımı düşündüm.
En iyi bahis, bu konudaki blog yayınımı kontrol etmektir: Objective-C'de zamanlama: Kronometre
Temel olarak, çok basit bir şekilde izlemeyi bırakan ancak kapsüllenmiş bir sınıf yazdım, böylece sadece aşağıdakileri yapmanız gerekir:
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
Ve sonunda:
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
günlükte ...
Yine, biraz daha fazlası için yazıma göz atın veya buradan indirin: MMStopwatch.zip
Ron'un çözümüne dayalı makrolar kullanıyorum .
#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])
Kod satırları için:
TICK(TIME1);
/// do job here
TOCK(TIME1);
Konsolda şöyle bir şey göreceğiz: TIME1: 0.096618
Bu blog yazısından kod esinlenerek çok az bir sayfa sınıfı uygulama kullanın :
#import <mach/mach_time.h>
@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 %@ %g s",
name, [self secondsFromMachTime:(end - begin)]);
[self.watches removeObjectForKey:name];
}
@end
Kullanımı çok basit:
[DBGStopwatch start:@"slow-operation"];
başında ara[DBGStopwatch stop:@"slow-operation"];
bitirdikten sonra, zamanı almak içinSen alabilirsiniz gerçekten bu Kronometre sınıfını kullanarak ince zamanlama (saniye seconds.parts). İPhone'daki yüksek hassasiyetli zamanlayıcıyı kullanır. NSDate'i kullanmak size yalnızca ikinci (ler) doğruluğu verecektir. Bu sürüm özellikle otomatik çalıştırma ve objektif-c için tasarlanmıştır. Gerekirse bir c ++ sürümü de var. Burada c ++ sürümünü bulabilirsiniz .
StopWatch.h
#import <Foundation/Foundation.h>
@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 <mach/mach_time.h>
@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
Sınıf, otomatik olarak stopWatch
yayımlanan bir nesneyi döndüren statik bir yönteme sahiptir.
Aradığınızda start
, seconds
geçen süreyi almak için yöntemi kullanın. start
Yeniden başlatmak için tekrar arayın . Veya stop
durdurmak için. Çağrıyı seconds
yaptıktan sonra istediğiniz zaman (çağrı ) okuyabilirsiniz stop
.
Bir İşlevde Örnek (Yürütme zamanlaması çağrısı)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}
Bu kodu kullanıyorum:
#import <mach/mach_time.h>
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;
}
Bunu kullanıyorum:
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);
Ancak iPhone'da CLOCKS_PER_SEC olduğundan emin değilim. Bırakmak isteyebilirsiniz.
mach_absolute_time()
Swift 4'te kullanılan hassas zamanlama örneği :
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")
}
Tamam, hedefiniz daha hızlı hale getirmek için neleri düzeltebileceğinizi bulmaksa, bu biraz farklı bir hedeftir. Fonksiyonların harcadığı zamanı ölçmek, bir fark yaratıp yaratmadığınızı öğrenmek için iyi bir yoldur, ancak ne yapacağınızı bulmak için farklı bir tekniğe ihtiyacınız vardır. Tavsiye ettiğim şey bu ve iPhone'larda yapabileceğinizi biliyorum.
Edit: Reviewers Ben cevabı ayrıntılı önerdi, bu yüzden bunu söylemek için kısa bir yol düşünmeye çalışıyorum.
Genel programınız sizi rahatsız etmek için yeterli zaman alır. Diyelim ki N saniye.
Hızlandırabileceğinizi varsayıyorsunuz. Bunu yapabilmenin tek yolu, o anda yaptığı bir şeyi yapmamasını sağlamak, m saniye hesaplamaktır .
Başlangıçta bu şeyin ne olduğunu bilmiyorsunuz. Tüm programcıların yaptığı gibi tahmin edebilirsiniz, ancak kolayca başka bir şey olabilir. Her neyse, onu nasıl bulacağınız aşağıda açıklanmıştır:
O şey, ne olursa olsun , zamanın m / N'sini açıklar, bu da rastgele duraklarsanız, m / N olma olasılığını o şeyi yapma eyleminde yakalayacağınız anlamına gelir . Tabii ki başka bir şey yapıyor olabilir, ama duraklatın ve ne yaptığını görün.
Şimdi tekrar yap. Aynı şeyi tekrar yaptığını görürseniz, daha şüpheli olabilirsiniz.
10 kez veya 20 yapın. Şimdi birden fazla duraklamada belirli bir şey yaptığını görüyorsanız (nasıl tarif ederseniz yapın), kurtulabileceğiniz iki şey biliyorsunuz. Kabaca ne kadar zaman aldığını çok iyi biliyorsunuz, ama tam olarak neyi düzelteceğinizi biliyorsunuz .
Ayrıca tam olarak ne kadar zaman kazanacağınızı bilmek istiyorsanız , bu kolay. Önce ölçün, düzeltin ve sonra ölçün. Gerçekten hayal kırıklığına uğradıysanız, düzeltmeyi geri alın.
Bunun ölçümden ne kadar farklı olduğunu görüyor musunuz? Bu oluyor ölçme değil bulma . Çoğu profil oluşturma, bu kadar önemli bir zamanın ne kadar sürdüğünü tam olarak ölçmeye dayanır ve neyin düzeltilmesi gerektiğini belirleme sorununu elle dalgalandırır. Profil oluşturma her sorunu bulamaz, ancak bu yöntem her sorunu bulur ve size zarar veren bulamadığınız problemlerdir.
Swift'te defer anahtar sözcüğünü kullanarak bunu yapmanın başka bir yolu
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
Apple'ın dokümanlarından : Program denetimini, erteleme ifadesinin göründüğü kapsamın dışına aktarmadan hemen önce kodun yürütülmesi için bir erteleme ifadesi kullanılır.
Bu, ilgili kodun gruplandırılması avantajı ile bir dene / sonla bloğuna benzer.
Bunu utils kütüphanemde kullanıyorum ( 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.")
}
}
... sonra şöyle bir yöntem çağırın:
func myFunctionCall() {
let timer = PrintTimer()
// ...
timer.done()
}
... çalıştırdıktan sonra konsolda şöyle görünür:
MyFile.swift:225 - myFunctionCall() took 1.8623 s.
Yukarıdaki TICK / TOCK kadar özlü değildir, ancak ne yaptığını görmek için yeterince açıktır ve zamanlananı otomatik olarak içerir (dosyaya, yöntemin başlangıcındaki satır ve işlev adına göre). Açıkçası ben daha fazla ayrıntı istedim (ex, ben sadece olağan durumda olduğu gibi bir yöntem çağrısı zamanlama değil, bunun yerine bu yöntem içinde bir blok zamanlama) PrintTimer init "name =" Foo "" parametresini ekleyebilirsiniz varsayılanların yanında bir ad vermek için.
Bir UIWebView içinde bir sayfadan diğerine geçiş süresini optimize etmek istediğiniz için, bu sayfaları yüklemek için kullanılan Javascript'i gerçekten optimize etmek istediğiniz anlamına gelmiyor mu?
Bu amaçla, burada bahsettiğim gibi bir WebKit profiline bakardım:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Başka bir yaklaşım, yüksek düzeyde başlamak ve her seferinde tüm web görünümünü yenilemek yerine AJAX tarzı sayfa yüklemesini kullanarak yükleme sürelerini en aza indirmek için söz konusu web sayfalarını nasıl tasarlayabileceğinizi düşünmek olacaktır.
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)
}
İşte uzun süre çalışan bir süreç bulmak için her yerde kodu ikiye bölmek için bir Swift 3 çözümü.
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()
}
Kullanım: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
Örnek çıktı: -
ELAPSED TIMES [MyApp.SomeViewController.Instrumentation (başlık: "View View Load Load", nokta: 1, geçenSaat: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (başlık: "Alt Görüntüleme Ekleme Tamamlandı", nokta: 2, elaSedTime: 0.0105805175, 0,0107212517) MyApp.SomeViewController.Instrumentation (başlık: "Görünüm Göründü", nokta: 3, geçenSaat: 0.56564098596572876)]
birçok cevap gariptir ve gerçekten milisaniye olarak sonuç vermez (ancak saniyeler içinde veya başka bir şeyle):
MS (MILLISECONDS) almak için kullandığım burada:
Swift:
let startTime = NSDate().timeIntervalSince1970 * 1000
// your Swift code
let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime
print("time code execution \(endTimeMinStartTime) ms")
Objective-C:
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 );
Swift 4 için sınıfınıza Temsilci olarak ekleyin:
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!))")
}
}
}
Sınıfımıza ekleyin:
class MyViewcontroller: UIViewController, TimingDelegate
Ardından sınıfınıza ekleyin:
var _TICK: Date?
Bir şeyi zamanlamak istediğinizde şunlarla başlayın:
TICK
Ve şununla bit:
TOCK("Timing the XXX routine")