Skip to content

Commit

Permalink
Merge pull request #1995 from DataDog/maxep/RUM-5555/fps-metrics
Browse files Browse the repository at this point in the history
RUM-5555 Benchmarks: Collect FPS Metric
  • Loading branch information
maxep authored Aug 20, 2024
2 parents 6d875cc + 47e5e34 commit d0a2fec
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 d0a2fec

Please sign in to comment.