Last active
March 17, 2021 12:32
-
-
Save MaximKotliar/d38fd4e79dc58c425d7e47fea460b089 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public final class Stopwatch { | |
var start: DispatchTime = .now() | |
let maxTime: TimeInterval | |
let measurementTitle: String | |
private var isReportedAtLeastOnce = false | |
@discardableResult | |
static func create(title: String = #function, maxTime: TimeInterval = 0) -> Stopwatch { | |
Self.init(title: title, maxTime: maxTime) | |
} | |
private init(title: String = #function, annotation: String? = nil, maxTime: TimeInterval = 0) { | |
self.measurementTitle = title | |
self.maxTime = maxTime | |
} | |
var time: TimeInterval { | |
let end = DispatchTime.now() | |
let nanoTime = end.uptimeNanoseconds - start.uptimeNanoseconds | |
return Double(nanoTime) / Double(NSEC_PER_SEC) | |
} | |
private func reportTime(time: TimeInterval, message: String? = nil) { | |
debugPrint("⏱ [\([measurementTitle, message].compactMap { $0 }.joined(separator: ", "))]: \(NSNumber(value: time).decimalValue)s") | |
} | |
func report(message: String? = nil) { | |
isReportedAtLeastOnce = true | |
reportTime(time: self.time, message: message) | |
} | |
func reportAndReset(message: String? = nil) { | |
report(message: message) | |
start = .now() | |
} | |
func reportIfNeeded(message: String? = nil) { | |
let time = self.time | |
guard time > maxTime else { return } | |
reportTime(time: time, message: message) | |
} | |
func callAsFunction() { | |
report() | |
} | |
deinit { | |
guard !isReportedAtLeastOnce else { return } | |
reportIfNeeded() | |
} | |
} | |
import UIKit | |
final class FrameDropMonitor { | |
private static var current: FrameDropMonitor? | |
private var displayLink: CADisplayLink? | |
private var lastRenderTime: DispatchTime = .now() | |
init() { | |
let maxTime = TimeInterval(1) / TimeInterval(UIScreen.main.maximumFramesPerSecond) | |
displayLink = CADisplayLink { [unowned self] in | |
let now = DispatchTime.now() | |
let timeSinceLastRender = TimeInterval(now.uptimeNanoseconds - self.lastRenderTime.uptimeNanoseconds) / TimeInterval(NSEC_PER_SEC) | |
if timeSinceLastRender.milliseconds > maxTime.milliseconds + 1 { | |
debugPrint("Frame drop, render time is: \(timeSinceLastRender.milliseconds)ms") | |
} | |
self.lastRenderTime = now | |
} | |
displayLink?.add(to: .current, forMode: .common) | |
} | |
deinit { | |
displayLink?.invalidate() | |
} | |
static func start() { | |
current = FrameDropMonitor() | |
} | |
static func stop() { | |
current = nil | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: