1

Assuming I have this kind of function and DispatchQueue logic. Assume that when synchLatest() gets called it fires "Code Block 1" twice.

How is supposed to be that, during a loop, the execution of "Code Block 1" which is only a retrieve of a string from the grpc response and a store in UserDefaults take me 1.7 seconds and the second it gets executed during the loop it takes 5 seconds?

let synchQueue = DispatchQueue(label: "com.dmapp.synchQueue", qos: .default, attributes: .concurrent)

let synchProcessQueue = DispatchQueue(label: "com.dmapp.processQueue", qos: .default, attributes: .concurrent)

func synchLatest() {
  while(someconditions) {
    synchQueue.async {
          ...
          let response = try grpcCall.receive()
          ...
          synchProcessQueue.async {
              ....
              measure("Code Block 1", {
                   if response.data.nickname != "" {
                        // Store in UserDefaults
                   }
              })
              ....
          }
    }
  }
}

@discardableResult
static func measure<A>(name: String = "", _ block: () -> A) -> A {
    let startTime = CACurrentMediaTime()
    let result = block()
    let timeElapsed = CACurrentMediaTime() - startTime
    print("Time: \(name) - \(timeElapsed)")
    return result
}

Am I measuring code execution time here in the wrong way?

denis_lor
  • 6,212
  • 4
  • 31
  • 55
  • 1
    It looks like you’re benchmarking just the updating of user defaults and I don’t know why that would be so slow. That having been said, you’re benchmarking tasks that appear to be running concurrently, so if there’s any synchronization going on, I’d expect the latter ones to be slower. – Rob Aug 19 '19 at 17:32
  • Thank you, that indeed made sense also to my analysis – denis_lor Aug 20 '19 at 07:46

1 Answers1

1

CACurrentMediaTime is a fine way of measuring time. It’s low overhead and doesn’t suffer the problems of Date or CFAbsoluteTimeGetCurrent, which “do not guarantee monotonically increasing results.”

A few general guidelines when benchmarking include:

  • let the app reach quiescence before starting the benchmarking;
  • do not run independent tests concurrently with respect to each other (because they may be contending for the same resources);
  • repeat it many times; and
  • change the order that the benchmarks are done in order to eliminate noise from the measurements.

If you’re looking for an alternative to manually using CACurrentMediaTime, another approach is to use signposts and points of interest, which not only will capture the amount of time it takes, but would you let you filter your instruments timeline to the relevant period of time (and you might be able to diagnose the source of the discrepancy).

Rob
  • 415,655
  • 72
  • 787
  • 1,044