메소드 실행 시간 (밀리 초)을 판별하는 방법이 있습니까?
메소드 실행 시간 (밀리 초)을 판별하는 방법이 있습니까?
답변:
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)")
스위프트 3 :
let methodStart = Date()
/* ... Do whatever you need to do ... */
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
사용하기 쉽고 1 밀리 초 미만의 정밀도를 갖습니다.
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;
물론 세밀한 측정에 대한 일반적인주의 사항이 적용됩니다. 테스트중인 루틴을 여러 번 호출하고 최소 / 일부 다른 형식의 처리를 평균화 / 취득하는 것이 가장 좋습니다.
또한 Shark와 같은 도구를 사용하여 실행중인 응용 프로그램 을 프로파일 링 하는 것이 더 유용 할 수 있습니다 . 정확한 타이밍 정보를 제공하지는 않지만 응용 프로그램 시간의 몇 퍼센트 를 어디에서 소비하고 있는지 알려주는 경우가 종종 있습니다 (항상 그런 것은 아님).
편리한 래퍼가 있습니다 mach_absolute_time()
– 그것은 CACurrentMediaTime()
기능입니다.
달리
NSDate
또는CFAbsoluteTimeGetCurrent()
오프셋mach_absolute_time()
과CACurrentMediaTime()
같은 시간대 서머 또는 윤초 의한 것과 외부 시간 기준의 변화에 내부 호스트 클럭, 정확한, 단원 자 계수 아닌 대상에 기초한다.
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
Ron의 솔루션을 기반으로 매크로를 사용합니다 .
#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를 사용하면 두 번째 정확도 만 얻을 수 있습니다. 이 버전은 자동 릴리스 및 objective-c를 위해 특별히 설계되었습니다. 필요한 경우 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
객체를 반환하는 정적 메서드가 있습니다.
를 호출 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);
그러나 iPhone의 CLOCKS_PER_SEC에 대해 잘 모르겠습니다. 당신은 그것을 떠나고 싶을 수도 있습니다.
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에서 defer 키워드를 사용하여 다른 방법을 사용하십시오.
func methodName() {
let methodStart = Date()
defer {
let executionTime = Date().timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")
}
// do your stuff here
}
Apple의 문서에서 : defer 문은 defer 문이 나타나는 범위 밖으로 프로그램 제어를 전송하기 직전에 코드를 실행하는 데 사용됩니다.
이것은 관련 코드를 그룹화한다는 이점이있는 try / finally 블록과 유사합니다.
나는 이것을 utils library ( 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만큼 간결하지는 않지만 수행중인 작업을 볼 수있을만큼 명확하며 시간이 초과 된 작업 (파일, 메서드 시작 줄 및 함수 이름)을 자동으로 포함합니다. 더 자세한 정보를 원한다면 (예를 들어, 일반적인 경우처럼 메소드 호출을 타이밍하는 것이 아니라 해당 메소드 내의 블록을 타이밍하는 경우) PrintTimer init에 "name ="Foo ""매개 변수를 추가 할 수 있습니다 기본값 이외의 이름을 지정하십시오.
UIWebView에서 한 페이지에서 다른 페이지로 이동하는 시간을 최적화하려고한다고해서 실제로 이러한 페이지를로드하는 데 사용되는 Javascript를 최적화하려고하는 것은 아닙니다.
이를 위해 여기에서 언급 한 WebKit 프로파일 러를 살펴 보겠습니다.
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)")
샘플 출력 :-
삭제 된 시간 [MyApp.SomeViewController.Instrumentation (제목 : "시작보기로드 실패", 포인트 : 1, 경과 시간 : 0.040504038333892822), MyApp.SomeViewController.Instrumentation (제목 : "Subviews 추가 완료", 포인트 : 2, 경과 시간 : 0.010585010051727295) MyApp.SomeViewController.Instrumentation (제목 : "보기가 나타남", 포인트 : 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")
목표 -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의 경우 수업에 대리인으로 추가하십시오.
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")