มีวิธีในการพิจารณาว่าต้องใช้เวลาเท่าใดในการประมวลผล (เป็นมิลลิวินาที)?
มีวิธีในการพิจารณาว่าต้องใช้เวลาเท่าใดในการประมวลผล (เป็นมิลลิวินาที)?
คำตอบ:
NSDate *methodStart = [NSDate date];
/* ... Do whatever you need to do ... */
NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"executionTime = %f", executionTime);
สวิฟท์:
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)")
ใช้งานง่ายและมีความแม่นยำย่อยมิลลิวินาที
NSLog(@"executionTime = %f", executionTime);
NSDate
และmach_absolute_time()
ที่ระดับประมาณ 30ms 27 กับ 29, 36 กับ 39, 43 กับ 45 ก็ง่ายที่จะใช้สำหรับฉันและผลที่ได้ก็เพียงพอที่คล้ายกันที่จะไม่รำคาญกับNSDate
mach_absolute_time()
ต่อไปนี้เป็นมาโครสองบรรทัดที่ฉันใช้:
#define TICK NSDate *startTime = [NSDate date]
#define TOCK NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])
ใช้มันแบบนี้:
TICK;
/* ... Do Some Work Here ... */
TOCK;
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])
ทำให้คำตอบนี้กลับมาพร้อมกับฟังก์ชั่นจับเวลาที่ใช้ฉันพบว่ามีประโยชน์ถ้าฉันใช้ TICK TOCK เพื่อฟังก์ชั่นหลาย ๆ ครั้ง
__PRETTY_FUNCTION__
และ__LINE__
ถ้าคุณต้องการข้อมูลรายละเอียดเพิ่มเติม
สำหรับช่วงเวลาที่ละเอียดใน OS X คุณควรใช้mach_absolute_time( )
ประกาศใน<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;
แน่นอน caveats ปกติเกี่ยวกับการวัดที่ละเอียดใช้; คุณน่าจะดีที่สุดที่จะเรียกใช้งานรูทีนภายใต้การทดสอบหลายครั้งและเฉลี่ย / ทำการประมวลผลขั้นต่ำ / รูปแบบอื่น ๆ
นอกจากนี้โปรดทราบว่าคุณอาจพบว่ามีประโยชน์มากขึ้นสำหรับโปรไฟล์แอปพลิเคชันของคุณที่ทำงานโดยใช้เครื่องมือเช่น Shark สิ่งนี้จะไม่ให้ข้อมูลเวลาที่แน่นอนแก่คุณ แต่มันจะบอกคุณว่าเปอร์เซ็นต์ของเวลาของแอปพลิเคชั่นนั้นถูกใช้ไปที่ไหนซึ่งมักจะมีประโยชน์มากกว่า (แต่ไม่เสมอไป)
มีตัวห่อหุ้มที่สะดวกสำหรับmach_absolute_time()
- เป็นCACurrentMediaTime()
ฟังก์ชั่น
ต่างจาก
NSDate
หรือCFAbsoluteTimeGetCurrent()
ออฟเซ็ตmach_absolute_time()
และCACurrentMediaTime()
ขึ้นอยู่กับนาฬิกาของโฮสต์ภายในตัวชี้วัดที่แม่นยำ monatomic และไม่ขึ้นอยู่กับการเปลี่ยนแปลงในการอ้างอิงเวลาภายนอกเช่นที่เกิดจากเขตเวลาการประหยัดเวลากลางวันหรือการกระโดดวินาที
ObjC
CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);
รวดเร็ว
let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")
NSDate
มันเป็นวิธีที่ดีกว่าการใช้
ใน Swift ฉันใช้:
ใน Macros.swift ของฉันฉันเพิ่งเพิ่ม
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)")
}
ตอนนี้คุณสามารถโทรได้ทุกที่
TICK()
// your code to be tracked
TOCK()
\(-startTime.timeIntervalSinceNow)
(สังเกตว่ามีค่าติดลบ)
ฉันรู้ว่านี่เป็นรุ่นเก่า แต่ฉันก็พบว่าตัวเองหลงทางอีกครั้งดังนั้นฉันคิดว่าฉันจะส่งตัวเลือกของฉันเองที่นี่
ทางออกที่ดีที่สุดคือการตรวจสอบโพสต์บล็อกของฉันเกี่ยวกับเรื่องนี้: กำหนดเวลาใน Objective-C: นาฬิกาจับเวลา
โดยทั่วไปฉันเขียนชั้นเรียนที่ไม่หยุดดูในวิธีขั้นพื้นฐานมาก แต่ถูกห่อหุ้มเพื่อที่คุณจะต้องทำสิ่งต่อไปนี้:
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
และคุณท้ายด้วย:
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
ในบันทึก ...
ตรวจสอบโพสต์ของฉันอีกสักครู่หรือดาวน์โหลดได้ที่นี่: MMStopwatch.zip
ฉันใช้มาโครตามวิธีแก้ปัญหาของรอน
#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])
สำหรับบรรทัดของรหัส:
TICK(TIME1);
/// do job here
TOCK(TIME1);
เราจะเห็นในคอนโซลบางอย่างเช่น: TIME1: 0.096618
ฉันใช้การปรับใช้คลาสหน้าน้อยที่สุดซึ่งได้รับแรงบันดาลใจจากรหัสจากโพสต์บล็อกนี้ :
#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
การใช้งานง่ายมาก:
[DBGStopwatch start:@"slow-operation"];
ที่จุดเริ่มต้น[DBGStopwatch stop:@"slow-operation"];
หลังจากเสร็จสิ้นเพื่อให้ได้เวลาคุณสามารถได้เวลาที่ดีจริง ๆ (วินาทีส่วนของวินาที) โดยใช้ระดับ StopWatch นี้ ใช้ตัวจับเวลาที่มีความแม่นยำสูงใน iPhone การใช้ NSDate จะช่วยให้คุณมีความแม่นยำที่สองเท่านั้น รุ่นนี้ได้รับการออกแบบมาโดยเฉพาะสำหรับการยกเลิกอัตโนมัติและวัตถุประสงค์ -c ฉันมีรุ่น c ++ เช่นกันหากจำเป็น คุณสามารถค้นหาค ++ รุ่นที่นี่
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
คลาสมีสแตติก stopWatch
วิธีการที่ส่งกลับวัตถุที่ autoreleased
เมื่อคุณโทรstart
ใช้seconds
วิธีการเพื่อให้ได้เวลาที่ผ่านไป โทรstart
อีกครั้งเพื่อเริ่มต้นใหม่ หรือstop
เพื่อหยุดมัน คุณยังสามารถอ่านเวลา (โทรseconds
) stop
ได้ตลอดเวลาหลังจากเรียก
ตัวอย่างในฟังก์ชั่น (การเรียกเวลาของการดำเนินการ)
-(void)SomeFunc
{
StopWatch* stopWatch = [StopWatch stopWatch];
[stopWatch Start];
... do stuff
[stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}
ฉันใช้รหัสนี้:
#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;
}
ฉันใช้สิ่งนี้:
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);
แต่ฉันไม่แน่ใจเกี่ยวกับ CLOCKS_PER_SEC บน iPhone คุณอาจต้องการที่จะทิ้งมันไว้
ตัวอย่างของการจับเวลาแบบละเอียดที่ใช้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")
}
ตกลงถ้าเป้าหมายของคุณคือค้นหาสิ่งที่คุณสามารถแก้ไขได้เพื่อให้เร็วขึ้นนั่นคือเป้าหมายที่แตกต่างกันเล็กน้อย การวัดเวลาที่ฟังก์ชั่นใช้เป็นวิธีที่ดีในการตรวจสอบว่าสิ่งที่คุณทำมีความแตกต่างหรือไม่ แต่เพื่อค้นหาว่าคุณต้องใช้เทคนิคอื่น นี่คือสิ่งที่ฉันแนะนำและฉันรู้ว่าคุณสามารถทำได้บน iPhone
แก้ไข: ผู้ตรวจทานแนะนำให้ฉันอธิบายคำตอบอย่างละเอียดดังนั้นฉันจึงพยายามคิดหาวิธีพูดสั้น ๆ
โปรแกรมโดยรวมของคุณใช้เวลานาฬิกามากพอที่จะรบกวนคุณ สมมติว่านั่นคือNวินาที
คุณสมมติว่าคุณสามารถเร่งความเร็วได้ วิธีเดียวที่คุณสามารถทำได้คือการทำให้มันไม่ทำสิ่งที่มันทำในเวลานั้นคิดเป็นmวินาที
ตอนแรกคุณไม่รู้ว่ามันคืออะไร คุณสามารถเดาได้เหมือนโปรแกรมเมอร์ทุกคนทำ แต่อาจเป็นอย่างอื่นได้ง่าย นี่คือวิธีที่คุณจะพบ:
เนื่องจากสิ่งนั้นไม่ว่าจะเป็นเศษส่วนm / Nของเวลาหมายความว่าถ้าคุณหยุดชั่วคราวโดยการสุ่มความน่าจะเป็นคือm / Nที่คุณจะจับมันในการกระทำสิ่งนั้น แน่นอนว่ามันอาจจะทำอย่างอื่น แต่หยุดมันชั่วคราวและดูว่ามันกำลังทำอะไรอยู่
ตอนนี้ทำมันอีกครั้ง หากคุณเห็นว่ามันทำสิ่งเดียวกันอีกครั้งคุณก็อาจจะสงสัยมากขึ้น
ทำ 10 ครั้งหรือ 20 ทีนี้ถ้าคุณเห็นมันทำอะไรบางอย่าง (ไม่ว่าคุณจะอธิบาย) ในหลาย ๆ ช่วงหยุดชั่วคราวคุณสามารถกำจัดคุณรู้สองสิ่ง คุณรู้ว่าใช้เวลาแค่ไหน แต่คุณรู้ว่าต้องแก้ไขอย่างไร
หากคุณต้องการทราบว่าจะประหยัดเวลามากเพียงใดนั่นเป็นเรื่องง่าย วัดก่อนแก้ไขและวัดหลังจาก หากคุณผิดหวังจริงๆให้ถอยออกไปแก้ไข
คุณเห็นว่ามันแตกต่างจากการวัดหรือไม่? มันหาไม่ได้วัด การทำโปรไฟล์ส่วนใหญ่ขึ้นอยู่กับการวัดให้มากที่สุดเท่าที่จะเป็นไปได้ใช้เวลาเท่าใดราวกับว่าเป็นเรื่องสำคัญและส่งคลื่นปัญหาของการระบุสิ่งที่ต้องแก้ไข การสร้างโปรไฟล์ไม่พบปัญหาทุกปัญหา แต่วิธีนี้จะพบปัญหาทุกปัญหาและเป็นปัญหาที่คุณไม่พบว่าทำให้คุณเจ็บปวด
นี่เป็นอีกวิธีหนึ่งใน Swift การทำเช่นนั้นโดยใช้คำหลักที่เลื่อนออกไป
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
จากdocsของ Apple : คำสั่ง defer ใช้สำหรับการเรียกใช้งานโค้ดก่อนโอนการควบคุมโปรแกรมนอกขอบเขตที่คำสั่ง defer ปรากฏขึ้น
สิ่งนี้คล้ายกับการลอง / ปิดกั้นในที่สุดโดยมีข้อได้เปรียบในการจัดกลุ่มรหัสที่เกี่ยวข้อง
ฉันใช้สิ่งนี้ในห้องสมุดของฉัน ( 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.")
}
}
... จากนั้นเรียกใช้วิธีการเช่น:
func myFunctionCall() {
let timer = PrintTimer()
// ...
timer.done()
}
... ซึ่งในลักษณะนี้ในคอนโซลหลังจากทำงาน:
MyFile.swift:225 - myFunctionCall() took 1.8623 s.
ไม่รัดกุมเหมือน TICK / TOCK ด้านบน แต่ชัดเจนพอที่จะดูว่ามันกำลังทำอะไรและรวมถึงสิ่งที่ถูกกำหนดเวลาโดยอัตโนมัติ (ตามไฟล์บรรทัดที่จุดเริ่มต้นของเมธอดและชื่อฟังก์ชัน) เห็นได้ชัดว่าถ้าฉันต้องการรายละเอียดเพิ่มเติม (เช่นถ้าฉันไม่เพียงแค่กำหนดเวลาการเรียกเมธอดตามปกติ แต่แทนที่จะกำหนดเวลาบล็อกภายในเมธอดนั้น) ฉันสามารถเพิ่มพารามิเตอร์ "name =" Foo "" ใน PrintTimer init เพื่อตั้งชื่อบางสิ่งนอกเหนือจากค่าเริ่มต้น
เนื่องจากคุณต้องการปรับการย้ายเวลาจากหน้าหนึ่งไปอีกหน้าหนึ่งใน UIWebView ไม่ได้หมายความว่าคุณต้องการเพิ่มประสิทธิภาพของ Javascript ที่ใช้ในการโหลดหน้าเหล่านี้หรือไม่
ด้วยเหตุนี้ฉันจะดู WebKit Profiler อย่างที่พูดถึงที่นี่:
http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/
อีกวิธีคือการเริ่มต้นในระดับสูงและคิดว่าคุณสามารถออกแบบหน้าเว็บที่เป็นปัญหาเพื่อลดเวลาในการโหลดโดยใช้การโหลดหน้าสไตล์ AJAX แทนที่จะรีเฟรชหน้าเว็บทั้งหมดในแต่ละครั้ง
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)
}
นี่คือโซลูชัน Swift 3 สำหรับการตัดรหัสที่ใดก็ได้เพื่อค้นหากระบวนการทำงานที่ยาวนาน
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()
}
การใช้งาน: -
instrument("View Did Appear")
print("ELAPSED TIMES \(elapsedTimes)")
ตัวอย่างผลลัพธ์: -
ELAPSED TIMES [MyApp.SomeViewController.Instrumentation (ชื่อเรื่อง: "มุมมองเริ่มโหลดไม่ได้", จุด: 1, elapsedTime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (ชื่อเรื่อง: "เสร็จสิ้นการเพิ่มตัวอย่างย่อย", จุด: 2, elapsedTime: 0.0105850) MyApp.SomeViewController.Instrumentation (ชื่อเรื่อง: "View Did ปรากฏ", จุด: 3, เวลาที่ผ่านไป: 0.56564098596572876)]
คำตอบมากมายนั้นแปลกและไม่ได้ให้ผลลัพธ์เป็นมิลลิวินาที (แต่ในเสี้ยววินาทีหรืออย่างอื่น):
นี่คือสิ่งที่ฉันใช้เพื่อรับ MS (MILLISECONDS):
สวิฟท์:
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 เพิ่มเป็น Delegate ให้กับคลาสของคุณ:
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!))")
}
}
}
เพิ่มในชั้นเรียนของเรา:
class MyViewcontroller: UIViewController, TimingDelegate
จากนั้นเพิ่มชั้นเรียนของคุณ:
var _TICK: Date?
เมื่อคุณต้องการเวลาบางสิ่งเริ่มต้นด้วย:
TICK
และจบลงด้วย:
TOCK("Timing the XXX routine")