Skip to content

Commit

Permalink
update performance testing
Browse files Browse the repository at this point in the history
  • Loading branch information
maerki committed Feb 25, 2025
1 parent b57587b commit acaa3ea
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 17 deletions.
15 changes: 10 additions & 5 deletions ios/maps/MCMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ open class MCMapView: MTKView, @unchecked Sendable {
mapInterface.prepare()
}

open func drawFrame(in view: MTKView, completion: @escaping (Bool) -> Void) {
open func drawFrame(in view: MTKView, completion: @escaping (CFTimeInterval?) -> Void) {
guard
let commandBuffer = MetalContext.current.commandQueue
.makeCommandBuffer(),
Expand All @@ -208,7 +208,7 @@ open class MCMapView: MTKView, @unchecked Sendable {
let renderEncoder = commandBuffer.makeRenderCommandEncoder(
descriptor: renderPassDescriptor)
else {
completion(false)
completion(nil)
return
}

Expand All @@ -227,12 +227,17 @@ open class MCMapView: MTKView, @unchecked Sendable {
renderEncoder.endEncoding()

guard let drawable = view.currentDrawable else {
completion(false)
completion(nil)
return
}

commandBuffer.addCompletedHandler { _ in
completion(true)
commandBuffer.addCompletedHandler { commandBuffer in
let start = commandBuffer.gpuStartTime
let end = commandBuffer.gpuEndTime


let gpuRuntimeDuration = end - start
completion(gpuRuntimeDuration)
}

// if we want to save the drawable (offscreen rendering), we commit and wait synchronously
Expand Down
1 change: 1 addition & 0 deletions tests/TestPlan.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
},
"testTargets" : [
{
"parallelizable" : false,
"target" : {
"containerPath" : "container:",
"identifier" : "iOSTests",
Expand Down
10 changes: 4 additions & 6 deletions tests/ios/BasemapLayerPerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ struct BasemapLayerPerformanceTests {

try await view.prepare(.zurich)

for _ in 0..<10 {
print("measuring fps")
let fps = view.measureFPS(duration: 30)
print("fps: \(fps)")
}

let fps = (0 ..< 100).map { _ in view.measureFPS(duration: 5) }
let maxFps = fps.max()!
print(maxFps)
#expect(maxFps > 80.0)
}

@Test func testStyleParsing() async throws {
Expand Down
7 changes: 2 additions & 5 deletions tests/ios/BasemapPerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,8 @@ final class BasemapPerformanceTests: XCTestCase {

try await view.prepare(.aletsch)

let prepareMetric = XCTOSSignpostMetric(subsystem: TestingMapView.signposterSubsystem, category: TestingMapView.signposterCategory, name: "\(TestingMapView.signposterIntervalPrepare)")
let drawMetric = XCTOSSignpostMetric(subsystem: TestingMapView.signposterSubsystem, category: TestingMapView.signposterCategory, name: "\(TestingMapView.signposterIntervalDraw)")
let awaitMetric = XCTOSSignpostMetric(subsystem: TestingMapView.signposterSubsystem, category: TestingMapView.signposterCategory, name: "\(TestingMapView.signposterIntervalAwait)")
self.measure(metrics: [prepareMetric, drawMetric, awaitMetric]) {
view.drawMeasured(frames: 70)
self.measure(metrics: [FPSMetric(mapView: view)]) {
view.drawMeasured()
}
}

Expand Down
31 changes: 31 additions & 0 deletions tests/ios/helpers/FPSMetric.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// FPSMetric.swift
// MapCore
//
// Created by Nicolas Märki on 25.02.2025.
//

import XCTest

class FPSMetric: NSObject, XCTMetric {

var mapView: TestingMapView

init(mapView: TestingMapView) {
self.mapView = mapView
}

func reportMeasurements(from startTime: XCTPerformanceMeasurementTimestamp, to endTime: XCTPerformanceMeasurementTimestamp) throws -> [XCTPerformanceMeasurement] {
let frames = self.mapView.frames.count { $0.start.absoluteTimeNanoSeconds > startTime.absoluteTimeNanoSeconds && $0.end.absoluteTimeNanoSeconds < endTime.absoluteTimeNanoSeconds }
let duration = Double(endTime.absoluteTimeNanoSeconds - startTime.absoluteTimeNanoSeconds) / Double(1_000_000_000)
let fps = Double(frames) / duration
return [.init(identifier: "FPS", displayName: "Frames per Second", value: .init(value: fps, unit: .init(symbol: "fps")), polarity: .prefersLarger)]
}

func copy(with zone: NSZone? = nil) -> Any {
let copy = FPSMetric(mapView: mapView)
return copy
}


}
8 changes: 7 additions & 1 deletion tests/ios/helpers/TestingMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import MapCore
import MetalKit
import UIKit
import os
import XCTest

@available(iOS 15.0, *)
class TestingMapView: MCMapView, @unchecked Sendable, MCMapReadyCallbackInterface {
Expand Down Expand Up @@ -134,14 +135,19 @@ class TestingMapView: MCMapView, @unchecked Sendable, MCMapReadyCallbackInterfac
signposter.endInterval(Self.signposterIntervalPrepare, state)
}

override func drawFrame(in view: MTKView, completion: @escaping (Bool) -> Void) {
private(set) var frames: [(start: XCTPerformanceMeasurementTimestamp, end: XCTPerformanceMeasurementTimestamp)] = []

override func drawFrame(in view: MTKView, completion: @escaping (CFTimeInterval?) -> Void) {
let signpostID = signposter.makeSignpostID()

let state = signposter.beginInterval(Self.signposterIntervalDraw, id: signpostID)
let start = XCTPerformanceMeasurementTimestamp()

super.drawFrame(in: view) { [signposter] in
signposter.endInterval(Self.signposterIntervalDraw, state)
completion($0)
let end = XCTPerformanceMeasurementTimestamp()
self.frames.append((start, end))
}

}
Expand Down

0 comments on commit acaa3ea

Please sign in to comment.