首页 > 解决方案 > Xcode time profiler accuracy

问题描述

I would like to know the exact time it takes to go from one screen to another. For example how long it takes to login and access the next screen. I tried using the Xcode time profiler but it doesn't log everything. I even enabled the "High frequency" option but still I think that something is missing. What I've come to understand is that you have to use signposts in order to achieve accuracy. Which works but you have to set your iOS version to 12 and also change the code to add os_signpost. Is there another way to achieve this without changing the iOS version? or the code?

Do you have any suggestions of another Xcode profiler tool or another tool in general that can give me this output?

I thought that the time profiler would give me the begin and end time of each method something similar to the Android Studio profiler. Am I missing something?

标签: swiftxcodeinstruments

解决方案


A couple of observations:

  1. Yes, if you want to calculate the time elapsed between two points of code, signposts are a great way of doing that. And if you want to know what’s going on between those two signposts, a “points of interest” range, which you can zoom into by control-clicking. This lets you focus on the area in question:

    enter image description here

  2. I'd suggest selecting “Record Waiting Threads”. Sometimes your thread is blocked by something, and if you don’t choose this option, it won't capture samples when your thread is blocked, often making it harder to find the culprit.

    enter image description here

    (I also tend to record in deferred mode, too, to minimize the observer effect.)

  3. You said

    you have to set your iOS version to 12 ...

    Well, not quite. Sure, if you want to use os_signpost you have to do your profiling on an iOS 12 device/simulator, but you don’t have have to change the target of your app. You'd only have to wrap your logging statements in #available blocks, e.g.:

    import UIKit
    import os.log
    
    @available(iOS 12.0, *)
    let pointsOfInterest = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: .pointsOfInterest)
    
    class ViewController: UIViewController {
        @IBAction func didTapNextButton(_ sender: Any) {
            if #available(iOS 12.0, *) {
                os_signpost(.begin, log: pointsOfInterest, name: "Transition")
            }
    
            performSegue(withIdentifier: "Next", sender: self)
        }
    }
    

    and

    import UIKit
    import os.log
    
    class SecondViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            somethingSlow()
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            if #available(iOS 12.0, *) {
                os_signpost(.end, log: pointsOfInterest, name: "Transition")
            }
        }
    
        func somethingSlow() { ... }
    
    }
    
  4. If you don't like having that if #available check and you have to support older OS versions, just use kdebug:

    kdebug_signpost_start(0, 0, 0, 0, 0)
    

    and

    kdebug_signpost_end(0, 0, 0, 0, 0)
    

    You don't have nice names on your points of interest ranges, but it works in older iOS versions.

For more information, see WWDC 2018 video Measuring Performance Using Logging.


推荐阅读