Как записать время выполнения метода точно в миллисекундах? - PullRequest
211 голосов
/ 25 января 2010

Есть ли способ определить, сколько времени необходимо выполнить методу (в миллисекундах)?

Ответы [ 20 ]

2 голосов
/ 18 мая 2015

Я использую этот код:

#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 голосов
/ 15 августа 2018

Пример точной синхронизации с использованием 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")
}
2 голосов
/ 25 января 2010

ОК, если ваша цель - выяснить, что вы можете исправить, чтобы сделать это быстрее, это немного другая цель. Измерение времени, которое занимают функции, - это хороший способ выяснить, изменилось ли то, что вы сделали, но чтобы выяснить, что делать , вам нужна другая техника. Это то, что я рекомендую , и я знаю, что вы можете сделать это на iPhone.

Редактировать: Рецензенты предложили уточнить ответ, поэтому я пытаюсь придумать краткий способ сказать это.
Ваша общая программа занимает достаточно времени, чтобы беспокоить вас. Предположим, что это N секунд.
Вы предполагаете, что можете ускорить это. Единственный способ сделать это - заставить его не делать то, что он делает за это время, что составляет m секунд.
Вы изначально не знаете, что это за вещь. Вы можете догадаться, как и все программисты, но это может быть что-то другое. Что бы это ни было, вот как это можно найти:

Поскольку эта вещь, какой бы она ни была, составляет долю м / N времени, это означает, что если вы сделаете случайную паузу, вероятность м / N будет поймать это в процессе выполнения этой вещи. Конечно, он может делать что-то еще, но сделайте паузу и посмотрите, что он делает.
Теперь сделай это снова. Если вы видите, что он снова делает то же самое, вы можете быть более подозрительным.

Сделайте это 10 раз или 20. Теперь, если вы видите, что он делает какую-то конкретную вещь (независимо от того, как вы это описываете) в нескольких паузах, от которой вы можете избавиться, вы знаете две вещи. Вы очень точно знаете, сколько времени это занимает, но вы знаете, очень точно что исправить.
Если вы также хотите точно знать , сколько времени будет сэкономлено, это легко. Измерьте это прежде, исправьте это, и измерьте это после. Если вы действительно разочарованы, отмените исправление.

Вы видите, как это отличается от измерения? Это обнаружение, а не измерение . Большая часть профилирования основана на измерении как можно точнее того, сколько времени уходит, как будто это важно, и решает проблему определения того, что необходимо исправить. Профилирование не находит всех проблем, но этот метод находит все проблемы, и проблемы, которых вы не находите, причиняют вам боль.

0 голосов
/ 19 марта 2018

Для 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")
0 голосов
/ 10 июля 2018

Я использую это в моей библиотеке утилит ( 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 назвать это что-то кроме значений по умолчанию.

0 голосов
/ 07 марта 2018

многие ответы странные и на самом деле не дают результата в миллисекундах (но в секундах или чем-то еще):

вот что я использую для получения MS (МИЛЛИСЕКОНД):

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 );
0 голосов
/ 15 июня 2017

Вот решение 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 (title: "Начальный вид Did Load ", точка: 1, время: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (title: "Закончено добавление SubViews ", точка: 2, прошедшее время: 0,010585010051727295), MyApp.SomeViewController.Instrumentation (заголовок: «Вид появился», точка: 3, прошедшее время: 0,56564098596572876)]

0 голосов
/ 27 декабря 2016

Вот другой способ, в 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 с преимуществом группировки соответствующего кода.

0 голосов
/ 25 января 2010

Поскольку вы хотите оптимизировать время перехода с одной страницы на другую в UIWebView, не означает ли это, что вы действительно хотите оптимизировать Javascript, используемый при загрузке этих страниц?

Для этого я бы посмотрел на профилировщик WebKit, о котором говорилось здесь:

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

Другой подход заключается в том, чтобы начать с высокого уровня и подумать, как можно спроектировать соответствующие веб-страницы, чтобы минимизировать время загрузки, используя загрузку страницы в стиле AJAX вместо обновления всего веб-просмотра каждый раз.

0 голосов
/ 30 октября 2015
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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...