garysimpson.dev
Mobile development with swift and flutter

Swift TimeProfiler

April 02, 2025 at 8:28AM

Once the main item was create I needed to refine it a little so It both returns the elapsed time and also works with async functions. The result is pretty sweet.



import Foundation

/// A  utility struct for measuring the execution time of synchronous and asynchronous code blocks.
struct TimeProfiler {
    
    /// Measure the execution time of a synchronous block.
    ///
    /// - Example:
    ///```swift
    /// let (result, time) = TimeProfiler.measure("ButtonTapped.Accept") {
    ///   dispatch(DialogView.DismissDialog(dialog: activationDialog))
    /// }
    ///```
    static func measureAsyncWithTime<T>(_ label: String? = nil, block: () -> T) -> (result: T, milliseconds: Double) {
        let startTime = CFAbsoluteTimeGetCurrent()
        let result = block()
        let endTime = CFAbsoluteTimeGetCurrent()
        
        let elapsed = (endTime - startTime) * 1000
        printTime(label, elapsed)
        return (result, elapsed)
    }
    
    /// Measure the execution time of an asynchronous block.
    ///
    /// - Example:
    ///```swift
    /// let (result, time) = try await  TimeProfiler.measure("ButtonTapped.Accept") {
    ///   return try await env.service.acceptRequestAsync(activationId: activation.id, activationRequestId: requestId)
    /// }
    ///```
    static func measureAsyncWithTime<T>(_ label: String? = nil, block: () async throws -> T) async rethrows -> (result: T, milliseconds: Double) {
        let startTime = CFAbsoluteTimeGetCurrent()
        let result = try await block()
        let endTime = CFAbsoluteTimeGetCurrent()
        
        let elapsed = (endTime - startTime) * 1000
        printTime(label, elapsed)
        return (result, elapsed)
    }
    
    /// Measure the execution time of a synchronous block.
    ///
    /// - Example:
    ///```swift
    /// TimeProfiler.measure("ButtonTapped.Accept") {
    ///   dispatch(DialogView.DismissDialog(dialog: activationDialog))
    /// }
    ///```
    static func measure<T>(_ label: String? = nil, block: () -> T) -> (T) {
        let startTime = CFAbsoluteTimeGetCurrent()
        let result = block()
        let endTime = CFAbsoluteTimeGetCurrent()
        
        let elapsed = (endTime - startTime) * 1000
        printTime(label, elapsed)
        return (result)
    }
    
    /// Measure the execution time of an asynchronous block.
    ///
    /// - Example:
    ///```swift
    /// let result = try await  TimeProfiler.measure("ButtonTapped.Accept") {
    ///   return try await env.service.acceptRequestAsync(activationId: activation.id, activationRequestId: requestId)
    /// }
    ///```
    static func measureAsync<T>(_ label: String? = nil, block: () async throws -> T) async rethrows -> (T) {
        let startTime = CFAbsoluteTimeGetCurrent()
        let result = try await block()
        let endTime = CFAbsoluteTimeGetCurrent()
        
        let elapsed = (endTime - startTime) * 1000
        printTime(label, elapsed)
        return (result)
    }
    
    /// Internal TimeProfiler func to print time and label info to console.
    static private func printTime(_ label: String? = nil, _ elapsed: Double) {
        if let label = label {
            debugPrint("⏱️ [\(label)] Execution time: \(elapsed) ms")
        } else {
            debugPrint("⏱️ Execution time = \(elapsed) ms")
        }
    }
}


Happy Coding ;-)