Comment enregistrer le temps d'exécution d'une méthode exactement en millisecondes?

Est-il un moyen de déterminer combien de temps une méthode doit exécuter (en millisecondes)?

197
demandé sur Kara 2010-01-25 04:57:46
la source

19 ответов

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)")

facile à utiliser et avec une précision inférieure à la milliseconde.

404
répondu Matthew McGoogan 2017-01-17 17:05:22
la source

voici deux macros d'une ligne que j'utilise:

#define TICK   NSDate *startTime = [NSDate date]
#define TOCK   NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])

utilisez - le comme ceci:

TICK;

/* ... Do Some Work Here ... */

TOCK;
238
répondu Ron 2013-04-01 13:01:07
la source

pour le chronométrage à grains fins sur OS X, vous devez utiliser mach_absolute_time( ) déclaré dans <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;

bien sûr, les mises en garde habituelles au sujet des mesures à grain fin s'appliquent; il est probablement préférable d'invoquer la routine en cours de test à plusieurs reprises, et de faire la moyenne/de prendre un minimum/une autre forme de traitement.

en outre, s'il vous plaît noter que vous pouvez le trouver plus utile à profil votre application en cours d'exécution en utilisant un outil comme le Requin. Cela ne vous donnera pas des informations précises sur le moment, mais il vous indiquera pourcentage du temps de l'application est passé où, ce qui est souvent plus utile (mais pas toujours).

47
répondu Stephen Canon 2010-01-25 05:11:48
la source

dans Swift, j'utilise:

dans Mes Macros.swift I vient d'ajouter

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)")
}

vous pouvez maintenant appeler n'importe où

TICK()

// your code to be tracked

TOCK()
  • ce code est basé sur le code de Ron traduire à Swift, il a les crédits
  • j'utilise la date de début au niveau mondial, toute suggestion pour améliorer sont les bienvenus
11
répondu Adriano Spadoni 2015-01-22 18:33:18
la source

je sais que c'est un vieux, mais même moi je me suis retrouvé à le dépasser, alors j'ai pensé Soumettre ma propre option ici.

meilleur pari est de vérifier mon billet de blog sur ce: Timing des choses en Objective-C: Un chronomètre

en gros, j'ai écrit une classe qui cesse de regarder d'une manière très basique mais qui est encapsulée de sorte qu'il suffit de faire ce qui suit:

[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];

et tu finis avec:

MyApp[4090:15203]  -> Stopwatch: [My Timer] runtime: [0.029]

dans le journal...

encore une fois, vérifier mon post pour un peu plus ou le télécharger ici: MMStopwatch.zip

10
répondu bladnman 2012-01-24 23:37:58
la source

j'utilise des macros basées sur la solution Ron's .

#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])

pour les lignes de code:

TICK(TIME1);
/// do job here
TOCK(TIME1);

nous verrons dans la console quelque chose comme: TIME1: 0.096618

8
répondu Sergey Teryokhin 2017-05-23 13:31:12
la source

Vous pouvez obtenir vraiment temporelle (secondes.parties de secondes) en utilisant cette classe de Chronomètre. Il utilise le minuteur de haute précision dans l'iPhone. En utilisant NSDate vous obtiendrez seulement la seconde (s) Précision. Cette version est conçue spécifiquement pour autorelease et objective-C. J'ai aussi une version c++ si nécessaire. vous pouvez trouver la version c++ ici .

Chronomètre.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

Chronomètre.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

la classe a une méthode statique stopWatch qui renvoie un objet auto-libéré.

une fois que vous appelez start , utilisez la méthode seconds pour obtenir le temps écoulé. Appeler start à nouveau pour le redémarrer. Ou stop pour l'arrêter. Vous pouvez toujours lire l'heure (appeler seconds ) n'importe quand après avoir appelé stop .

par Exemple Dans Une Fonction (Temporisation d'appel de l'exécution)

-(void)SomeFunc
{
   StopWatch* stopWatch = [StopWatch stopWatch];
   [stopWatch Start];

   ... do stuff

   [stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}
3
répondu FuzzyBunnySlippers 2014-01-02 17:46:56
la source

j'utilise très minime, une page d'application de classe inspiré par code de ce blog post :

#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

l'usage en est très simple:

  • il suffit d'appeler [DBGStopwatch start:@"slow-operation"]; au début
  • puis [DBGStopwatch stop:@"slow-operation"]; après l'arrivée, pour obtenir le temps
3
répondu zubko 2014-09-30 13:20:55
la source

OK, si votre objectif est de trouver ce que vous pouvez corriger pour le rendre plus rapide, c'est un peu différent de l'objectif. Mesurer le temps que prennent les fonctions est un bon moyen de savoir si ce que vous avez fait a fait une différence, mais pour trouver ce qu'il faut faire vous avez besoin d'une technique différente. C'est ce que je recommande , et je sais que vous pouvez le faire sur iPhone.

2
répondu Mike Dunlavey 2017-05-23 15:10:27
la source

j'utilise ceci:

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);

mais je ne suis pas sûr de CLOCKS_PER_SEC sur l'iPhone. Vous voudrez peut-être laisser.

2
répondu David Kanarek 2010-01-25 05:10:07
la source

j'utilise ce code:

#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;
}
2
répondu cleexiang 2017-08-16 13:28:05
la source

puisque vous voulez optimiser le temps de déplacement d'une page à l'autre dans un UIWebView, cela ne signifie-t-il pas que vous cherchez vraiment à optimiser le Javascript utilisé pour charger ces pages?

à cette fin, je regarderais un profileur WebKit comme celui dont il est question ici:

http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit /

une Autre approche serait de commencer à un niveau élevé, et penser comment vous pouvez concevoir les pages Web en question pour minimiser les temps de charge en utilisant le chargement de page de style AJAX au lieu de rafraîchir l'ensemble de la vue web à chaque fois.

0
répondu Kendall Helmstetter Gelner 2010-01-25 05:52:06
la source
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)
}
0
répondu user3441734 2015-10-30 01:15:38
la source

Voici une autre façon, dans Swift, de faire cela en utilisant le mot-clé defer

func methodName() {
  let methodStart = Date()
  defer {
    let executionTime = Date().timeIntervalSince(methodStart)
    print("Execution time: \(executionTime)")
  }
  // do your stuff here
}

de Apple docs : une instruction defer est utilisée pour exécuter le code juste avant de transférer le contrôle du programme en dehors de la portée dans laquelle l'instruction defer apparaît.

c'est similaire à un bloc try/finally avec l'avantage d'avoir le code associé groupé.

0
répondu CMont 2016-12-27 07:52:18
la source

Voici une solution Swift 3 pour séparer le code n'importe où pour trouver un processus de longue durée.

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()
}

Usage: -

instrument("View Did Appear")

print("ELAPSED TIMES \(elapsedTimes)")

sortie D'échantillon: -

temps écoulé [MyApp.SomeViewController.Instrumentation(titre: "Start View Did Load", point: 1, passedtime: 0.040504038333892822), MyApp.SomeViewController.Instrumentation(titre: "Finished Adding Les sous-vues", point d': 2, délai: 0.010585010051727295), MyApp.SomeViewController.Instrumentation(titre: "View Did appeared", point: 3, délai: 0.56564098596572876)]

0
répondu markhorrocks 2017-06-15 03:14:36
la source

beaucoup de réponses sont bizarres et ne donnent pas vraiment de résultat en millisecondes (mais en secondes ou autre chose):

voici ce que j'utilise pour obtenir MS (millisecondes):

Swift:

let startTime = NSDate().timeIntervalSince1970 * 1000

// your Swift code

let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime
print("time code execution \(endTimeMinStartTime) ms")

Objectif-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 );
0
répondu user924 2018-03-07 00:35:03
la source

pour Swift 4, ajouter en tant que délégué à votre classe:

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!))")
        }
    }
}

ajouter à notre classe:

class MyViewcontroller: UIViewController, TimingDelegate

puis Ajouter à votre classe:

var _TICK: Date?

quand vous voulez chronométrer quelque chose, commencez par:

TICK

et se termine par:

TOCK("Timing the XXX routine")
0
répondu Snickitybit 2018-03-19 05:16:31
la source

j'utilise ceci dans ma bibliothèque utils ( 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.")
    }
}

... puis appelez une méthode comme:

func myFunctionCall() {
    let timer = PrintTimer()
    // ...
    timer.done()
}

... qui ressemble à ceci dans la console après l'exécution:

MyFile.swift:225 - myFunctionCall() took 1.8623 s.

pas aussi concis que TICK/TOCK ci-dessus, mais il est assez clair pour voir ce qu'il fait et inclut automatiquement ce qui est chronométré (par fichier, Ligne Au début de la méthode, et le nom de la fonction). Évidemment si je voulais plus de détails (ex, si Je ne chronomètre pas simplement un appel de méthode comme c'est le cas d'habitude mais que je chronomètre plutôt un bloc dans cette méthode) je peux ajouter le paramètre "name="Foo" sur L'init PrintTimer pour lui donner un nom en plus des valeurs par défaut.

0
répondu Tom Dibble 2018-07-10 02:23:39
la source

exemple de minuterie à grain fin utilisant mach_absolute_time() dans 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")
}
0
répondu jbg 2018-08-15 07:42:52
la source

Autres questions sur ios objective-c optimization time