Skip to content

Commit

Permalink
RUM-5555 Collect FPS metric
Browse files Browse the repository at this point in the history
  • Loading branch information
maxep committed Aug 14, 2024
1 parent 121b2fd commit 47e5e34
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
9 changes: 9 additions & 0 deletions BenchmarkTests/Benchmarks/Sources/Benchmarks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,15 @@ public enum Benchmarks {
}
}

let fps = FPS()
_ = meter.createDoubleObservableGauge(name: "ios.benchmark.fps.min") { metric in
if let value = fps.minimumRate {
metric.observe(value: value, labels: labels)
}

fps.reset()
}

OpenTelemetry.registerMeterProvider(meterProvider: meterProvider)
}
}
54 changes: 54 additions & 0 deletions BenchmarkTests/Benchmarks/Sources/Metrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import Foundation
import QuartzCore

// The `TASK_VM_INFO_COUNT` and `TASK_VM_INFO_REV1_COUNT` macros are too
// complex for the Swift C importer, so we have to define them ourselves.
Expand Down Expand Up @@ -38,3 +39,56 @@ public enum Memory {
return Double(info.phys_footprint)
}
}

/// FPS aggregator to measure the minimal frame rate.
internal final class FPS {
private class CADisplayLinker {
weak var fps: FPS?

init() { }

@objc func tick(link: CADisplayLink) {
guard let fps else {
return
}

pthread_mutex_lock(&fps.mutex)
let rate = 1 / (link.targetTimestamp - link.timestamp)
fps.min = fps.min.map { Swift.min($0, rate) } ?? rate
pthread_mutex_unlock(&fps.mutex)
}
}

private var displayLink: CADisplayLink
private var mutex = pthread_mutex_t()
private var min: Double?

/// The minimum FPS value that was measured.
/// Call `reset` to reset the measure window.
var minimumRate: Double? {
pthread_mutex_lock(&mutex)
defer { pthread_mutex_unlock(&mutex) }
return min
}

/// Resets the minimum frame rate to `nil`.
func reset() {
pthread_mutex_lock(&mutex)
min = nil
pthread_mutex_unlock(&mutex)
}

required init() {
let linker = CADisplayLinker()
displayLink = CADisplayLink(target: linker, selector: #selector(CADisplayLinker.tick(link:)))

linker.fps = self
pthread_mutex_init(&mutex, nil)
displayLink.add(to: RunLoop.main, forMode: .common)
}

deinit {
displayLink.invalidate()
pthread_mutex_destroy(&mutex)
}
}

0 comments on commit 47e5e34

Please sign in to comment.