Instruments 27 introduces Run Comparisons โ a new mode that directly diffs two profiling traces side-by-side in a single document to calculate exact performance deltas โ alongside the new Top Functions analysis mode that merges scattered call-tree nodes by self-weight to instantly surface the costliest functions regardless of call hierarchy.
โข Run Comparisons eliminates manual window juggling: load a baseline trace and an optimized trace together, and Instruments cross-references every sample to show you the exact delta per function โ making it fast to verify that a fix actually helped.
โข Top Functions mode solves a long-standing flame graph blind spot: runtime helpers and utilities called from many sites are shown as one merged block sorted by self-weight, so you immediately see the true most-expensive function rather than fragmented slices.
โข OSSignpost / Points-of-Interest integration lets you annotate specific user-facing workflows (like lasso selection) and filter the entire trace to that window, dramatically narrowing the search space before you even open the call tree.
Demonstrates how to annotate a performance-sensitive code path with OSSignpost so Instruments 27 can surface it in the Points of Interest track, enabling filtered Run Comparisons and Top Functions analysis on just that workflow.
import SwiftUI
import OSLog
// MARK: - Signposter setup
// Using the Points of Interest category causes Instruments to automatically
// display this data in the Points of Interest track in Instruments 27.
private let signposter = OSSignposter(
subsystem: "com.example.NoteApp",
category: .pointsOfInterest
)
// MARK: - Canvas model using concrete types instead of existentials
// Before: var strokes: [any DrawingElement] โ causes swift_project_boxed_opaque_existential overhead
// After: concrete generic approach avoids existential boxing entirely
struct Stroke: Identifiable {
let id = UUID()
var points: [CGPoint]
var color: Color
}
final class CanvasModel: ObservableObject {
@Published var strokes: [Stroke] = []
@Published var lassoSelection: [Stroke] = []
/// Performs lasso hit-testing, wrapped in an OSSignpost interval so
/// Instruments 27 can isolate and compare this work across runs.
func performLassoSelection(in region: CGRect) {
let state = signposter.beginInterval(
"Lasso Selection",
id: signposter.makeSignpostID()
)
defer { signposter.endInterval("Lasso Selection", state) }
// Concrete type iteration โ no existential unwrap overhead
lassoSelection = strokes.filter { stroke in
stroke.points.contains { region.contains($0) }
}
}
}
// MARK: - SwiftUI View
struct CanvasView: View {
@StateObject private var model = CanvasModel()
@State private var showingSelection = false
var body: some View {
ZStack {
Canvas { context, size in
for stroke in model.strokes {
var path = Path()
guard let first = stroke.points.first else { continue }
path.move(to: first)
stroke.points.dropFirst().forEach { path.addLine(to: $0) }
context.stroke(path, with: .color(stroke.color), lineWidth: 3)
}
}
.onTapGesture { location in
let sampleStroke = Stroke(
points: [location, CGPoint(x: location.x + 40, y: location.y + 40)],
color: .blue
)
model.strokes.append(sampleStroke)
}
VStack {
Spacer()
Button("Simulate Lasso (profile me)") {
// This call is wrapped in an OSSignpost interval;
// visible as "Lasso Selection" in the Points of Interest
// track in Instruments 27, enabling Run Comparisons.
model.performLassoSelection(in: CGRect(x: 0, y: 0, width: 300, height: 300))
showingSelection = true
}
.padding()
.background(.ultraThinMaterial, in: Capsule())
.padding(.bottom, 40)
}
}
.alert("Selected \(model.lassoSelection.count) strokes", isPresented: $showingSelection) {
Button("OK", role: .cancel) {}
}
}
}
#Preview {
CanvasView()
}MetricKit has been rebuilt from the ground up in iOS 27 with a contextually rich, Swift-first API that delivers metrics and diagnostics as async streams, plus new capabilities like Metal frame rate metrics, memory exception diagnostics, and per-state metric breakdowns via the StateReporting framework.
iOS 26+ introduces a Deferred Start API for AVCaptureSession that postpones initialization of non-preview outputs (like photo and movie outputs) until after the first preview frame renders, dramatically cutting camera app launch times.
iOS 27 rebuilds MetricKit from the ground up with a modern, Swift-first API that delivers metric and diagnostic reports via async streams, adds Metal frame rate metrics, memory exception diagnostics, and crash termination categories, plus a new StateReporting framework to contextualize metrics by app state.
Run Comparisons requires both traces to be captured from the same binary (or a closely related build) for function matching to succeed. Top Functions uses self-weight, so high-weight runtime functions like swift_project_boxed_opaque_existential indicate code patterns (existentials) to fix, not Instruments bugs. Always profile a release build โ debug builds disable optimizations and inflate sampled costs.
Profile on a physical device with a release build for accurate data; simulator and debug builds produce misleading profiling results.
iOS/macOS 27 introduces the StateReporting API and look-back trace collection tools, letting developers annotate game state (levels, graphics settings, network) directly into Metal performance traces and retroactively collect hours of performance data without pre-instrumentation.