Apakah ada cara untuk menentukan berapa banyak waktu yang dibutuhkan suatu metode untuk dieksekusi (dalam milidetik)?
Apakah ada cara untuk menentukan berapa banyak waktu yang dibutuhkan suatu metode untuk dieksekusi (dalam milidetik)?
Jawaban:
NSDate *methodStart = [NSDate date];
/* ... Do whatever you need to do ... */
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"executionTime = %f", executionTime);
Cepat:
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)")
Mudah digunakan dan memiliki presisi sub-milidetik.
NSLog(@"executionTime = %f", executionTime);
NSDate
dan mach_absolute_time()
pada level sekitar 30 ms. 27 vs 29, 36 vs 39, 43 vs 45. NSDate
lebih mudah digunakan untuk saya dan hasilnya cukup mirip untuk tidak repot mach_absolute_time()
.
Berikut adalah dua makro satu baris yang saya gunakan:
#define TICK NSDate *startTime = [NSDate date]
#define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
Gunakan seperti ini:
TICK;
/* ... Do Some Work Here ... */
TOCK;
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
membuat jawaban ini juga mengembalikan fungsi timer digunakan. Saya menemukan ini berguna jika saya menggunakan TICK TOCK untuk mengatur waktu beberapa fungsi.
__PRETTY_FUNCTION__
dan __LINE__
jika Anda menginginkan informasi lebih rinci.
Untuk pengaturan waktu halus pada OS X, Anda harus menggunakan yang mach_absolute_time( )
dinyatakan dalam <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;
Tentu saja peringatan biasa tentang pengukuran berbutir halus berlaku; Anda mungkin sebaiknya menjalankan rutin yang sedang diuji berkali-kali, dan rata-rata / mengambil minimum / beberapa bentuk pemrosesan lainnya.
Selain itu, harap perhatikan bahwa Anda mungkin merasa lebih berguna untuk membuat profil aplikasi Anda berjalan menggunakan alat seperti Shark. Ini tidak akan memberi Anda informasi waktu yang tepat, tetapi akan memberi tahu Anda berapa persen waktu aplikasi dihabiskan di mana, yang seringkali lebih bermanfaat (tetapi tidak selalu).
Ada pembungkus yang nyaman untuk mach_absolute_time()
- itu CACurrentMediaTime()
fungsi.
Tidak seperti
NSDate
atauCFAbsoluteTimeGetCurrent()
offset,mach_absolute_time()
danCACurrentMediaTime()
didasarkan pada jam host internal, ukuran monatomik yang tepat, dan tidak mengalami perubahan dalam referensi waktu eksternal, seperti yang disebabkan oleh zona waktu, penghematan siang hari, atau detik kabisat.
ObjC
CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
Cepat
let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
NSDate
.
Di Swift, saya menggunakan:
Di Macros.swift saya, saya baru saja menambahkan
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)")
}
Anda sekarang dapat menelepon ke mana saja
TICK()
// your code to be tracked
TOCK()
\(-startTime.timeIntervalSinceNow)
(perhatikan yang negatif)
Saya tahu ini sudah lama tetapi bahkan saya mendapati diri saya melewatinya lagi, jadi saya pikir saya akan menyerahkan pilihan saya sendiri di sini.
Taruhan terbaik adalah untuk memeriksa posting blog saya tentang ini: Mengatur waktu hal-hal di Objective-C: A stopwatch
Pada dasarnya, saya menulis sebuah kelas yang tidak berhenti menonton dengan cara yang sangat dasar tetapi dienkapsulasi sehingga Anda hanya perlu melakukan hal berikut:
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
Dan Anda berakhir dengan:
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
dalam log ...
Sekali lagi, lihat tulisan saya untuk lebih banyak atau unduh di sini: MMStopwatch.zip
Saya menggunakan makro berdasarkan solusi Ron .
#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])
Untuk baris kode:
TICK(TIME1);
/// do job here
TOCK(TIME1);
kita akan melihat di konsol sesuatu seperti: TIME1: 0,096618
Saya menggunakan implementasi kelas yang sangat minimal, satu halaman yang terinspirasi oleh kode dari posting blog ini :
#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
Penggunaannya sangat sederhana:
[DBGStopwatch start:@"slow-operation"];
di awal[DBGStopwatch stop:@"slow-operation"];
setelah selesai, untuk mendapatkan waktuAnda bisa mendapatkan pengaturan waktu yang sangat baik (seconds.parts detik) menggunakan kelas StopWatch ini. Menggunakan pengatur waktu presisi tinggi di iPhone. Menggunakan NSDate hanya akan memberi Anda akurasi kedua. Versi ini dirancang khusus untuk autorelease dan objektif-c. Saya memiliki versi c ++ juga jika diperlukan. Anda dapat menemukan versi c ++ di sini .
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
Kelas memiliki stopWatch
metode statis yang mengembalikan objek autoreleased.
Setelah Anda menelepon start
, gunakan seconds
metode untuk mendapatkan waktu yang telah berlalu. Panggil start
lagi untuk memulai kembali. Atau stop
untuk menghentikannya. Anda masih dapat membaca waktu (panggilan seconds
) kapan saja setelah menelepon stop
.
Contoh Dalam Fungsi ( Pengaturan waktu eksekusi)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}
Saya menggunakan kode ini:
#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;
}
Saya menggunakan ini:
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);
Tapi saya tidak yakin tentang CLOCKS_PER_SEC di iPhone. Anda mungkin ingin meninggalkannya.
Contoh pengaturan waktu berbutir halus mach_absolute_time()
dalam 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")
}
Oke, jika tujuan Anda adalah mencari tahu apa yang dapat Anda perbaiki untuk membuatnya lebih cepat, itu adalah tujuan yang sedikit berbeda. Mengukur waktu yang dibutuhkan fungsi adalah cara yang baik untuk mengetahui apakah apa yang Anda lakukan membuat perbedaan, tetapi untuk mengetahui apa yang harus dilakukan, Anda memerlukan teknik yang berbeda. Ini yang saya rekomendasikan , dan saya tahu Anda bisa melakukannya di iPhone.
Sunting: Peninjau menyarankan agar saya menguraikan jawabannya, jadi saya mencoba memikirkan cara singkat untuk mengatakannya.
Program keseluruhan Anda membutuhkan cukup waktu jam untuk mengganggu Anda. Misalkan N detik.
Anda mengasumsikan Anda dapat mempercepatnya. Satu-satunya cara Anda dapat melakukannya adalah dengan membuatnya tidak melakukan sesuatu yang dilakukannya pada waktu itu, akuntansi untuk m detik.
Anda awalnya tidak tahu benda apa itu. Anda bisa menebak, seperti yang dilakukan oleh semua programmer, tetapi bisa dengan mudah menjadi sesuatu yang lain. Apa pun itu, inilah cara Anda dapat menemukannya:
Karena benda itu, apa pun itu, menyumbang fraksi m / N pada saat itu, itu berarti jika Anda menjeda secara acak kemungkinannya adalah m / N bahwa Anda akan menangkapnya saat melakukan hal itu. Tentu saja itu mungkin melakukan sesuatu yang lain, tetapi berhenti sebentar dan lihat apa yang dilakukannya.
Sekarang lakukan lagi. Jika Anda melihatnya melakukan hal yang sama lagi, Anda bisa lebih curiga.
Lakukan 10 kali, atau 20. Sekarang jika Anda melihatnya melakukan hal tertentu (tidak peduli bagaimana Anda menggambarkannya) pada beberapa jeda, yang dapat Anda singkirkan, Anda tahu dua hal. Anda tahu kira-kira berapa lama waktu yang dibutuhkan, tetapi Anda tahu persis apa yang harus diperbaiki.
Jika Anda juga ingin tahu persis berapa banyak waktu yang akan dihemat, itu mudah. Ukur sebelum, perbaiki, dan ukur sesudahnya. Jika Anda benar-benar kecewa, mundurlah perbaiki.
Apakah Anda melihat bagaimana ini berbeda dari mengukur? Itu menemukan, bukan mengukur . Kebanyakan profiling didasarkan pada pengukuran setepat mungkin berapa banyak waktu yang diambil, seolah-olah itu penting, dan menggerakkan tangan masalah mengidentifikasi apa yang perlu diperbaiki. Profil tidak menemukan setiap masalah, tetapi metode ini memang menemukan setiap masalah, dan masalah yang menurut Anda tidak menyakiti Anda.
Berikut cara lain, di Swift, untuk melakukannya menggunakan kata kunci penangguhan
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
Dari dokumen Apple : Pernyataan penundaan digunakan untuk mengeksekusi kode tepat sebelum mentransfer kontrol program di luar ruang lingkup di mana pernyataan penundaan muncul.
Ini mirip dengan blok coba / akhirnya dengan keuntungan memiliki kode terkait yang dikelompokkan.
Saya menggunakan ini di perpustakaan utils saya ( 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.")
}
}
... lalu panggil dengan metode seperti:
func myFunctionCall() {
let timer = PrintTimer()
// ...
timer.done()
}
... yang pada gilirannya terlihat seperti ini di konsol setelah dijalankan:
MyFile.swift:225 - myFunctionCall() took 1.8623 s.
Tidak sesingkat TICK / TOCK di atas, tetapi cukup jelas untuk melihat apa yang dilakukannya dan secara otomatis mencakup apa yang sedang dihitung waktunya (berdasarkan file, baris pada awal metode, dan nama fungsi). Jelas jika saya ingin lebih detail (mis., Jika saya tidak hanya menghitung waktu pemanggilan metode seperti kasus biasa tetapi saya menghitung waktu blok dalam metode itu) Saya dapat menambahkan parameter "name =" Foo "" pada init PrintTimer menamakannya sesuatu selain default.
Karena Anda ingin mengoptimalkan waktu bergerak dari satu halaman ke halaman lain di UIWebView, bukankah itu berarti Anda benar-benar ingin mengoptimalkan Javascript yang digunakan dalam memuat halaman-halaman ini?
Untuk itu, saya akan melihat profiler WebKit seperti yang dibicarakan di sini:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
Pendekatan lain adalah memulai pada level tinggi, dan pikirkan bagaimana Anda dapat mendesain halaman web yang dimaksud untuk meminimalkan waktu pemuatan menggunakan pemuatan halaman gaya AJAX alih-alih menyegarkan seluruh tampilan web setiap kali.
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)
}
Inilah solusi Swift 3 untuk membagi dua kode di mana saja untuk menemukan proses yang berjalan lama.
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()
}
Penggunaan: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
Output sampel: -
WAKTU YANG DIKILANGI [MyApp.SomeViewController.Instrumentation (judul: "Start View Did Load", titik: 1, berlaluTime: 0,040504038333892822), MyApp.SomeViewController.Instrumentation (judul: "Selesai Menambahkan SubViews", poin: 2, elapsedTime: 0,0105955050505050 MyApp.SomeViewController.Instrumentation (judul: "View Did Appear", poin: 3, elapsedTime: 0.56564098596572876)]
banyak jawaban yang aneh dan tidak benar-benar memberikan hasil dalam milidetik (tetapi dalam detik atau apa pun):
di sini apa yang saya gunakan untuk mendapatkan MS (MILLISECONDS):
Cepat:
let startTime = NSDate().timeIntervalSince1970 * 1000
// your Swift code
let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime
print("time code execution \(endTimeMinStartTime) ms")
Tujuan-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 );
Untuk Swift 4, tambahkan sebagai Delegasi ke kelas Anda:
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!))")
}
}
}
Tambahkan ke kelas kami:
class MyViewcontroller: UIViewController, TimingDelegate
Kemudian tambahkan ke kelas Anda:
var _TICK: Date?
Ketika Anda ingin mengatur waktu sesuatu, mulailah dengan:
TICK
Dan diakhiri dengan:
TOCK("Timing the XXX routine")