Hi,
My name is Hani Nemati, and I work at Microsoft, where we support several macOS applications such as Microsoft Edge and Teams. I’m also the primary contributor to Microsoft Performance Tools for Apple (https://github.com/microsoft/Microsoft-Performance-Tools-Apple), an open-source project aimed at improving trace analysis across platforms.
We are exploring ways to enhance our performance tracing capabilities on macOS and are particularly interested in the ability to attach PMU (Performance Monitoring Unit) counters to context switch events during trace collection. For reference, this capability is supported on Linux via LTTng using the add-context option (https://lttng.org/man/1/lttng-add-context/v2.13), and on Windows through Windows Performance Recorder (WPR), which allows PMU counters to be added at the start and end of context switches, enabling delta computation.
Would it be possible to introduce similar support in Instruments for macOS?
I’d appreciate any guidance or suggestions you might have on this request.
Thank you,
Hani Nemati
Email: hanemati@microsoft
Instruments
RSS for tagInstruments is a performance-analysis and testing tool for iOS, iPadOS, watchOS, tvOS, and macOS apps.
Posts under Instruments tag
57 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hiya folks! I'm David and I work on rust-analyzer, which is a language server for Rust similar to sourcekit-lsp. I'm using the new Instruments profiling tooling functionality in Xcode 16.3 and Xcode 26 (Processor Trace and CPU Counters) to profile our trait solver/type checker. While I've been able to use the new CPU Counters instrument successfully (the CPU Bottleneck feature is incredible! Props to the team!), I've been unable to make use of the Processor Trace instrument.
Instruments gives me the error message "Processor Trace cannot profile this process without proper permissions". The diagnostic suggests adding the com.apple.security-get-task-allow entitlement to the code I'm trying to profile, or ensure that the build setting CODE_SIGN_INJECT_BASE_ENTITLEMENTS = YES is enabled in Xcode.
Unfortunately, I don't know how I can add that entitlement to a self-signed binary produced by Cargo and I'm not using Xcode for somewhat obvious reasons.
Here's some information about my setup:
Instruments Version 26.0 (17A5241e)
I'm on an 14" MacBook Pro with M4 Pro. It's running macOS Version 26.0 Beta (25A5295e).
I've enabled the "Processor Trace" feature in "Developer Tools" and even added the Instruments application to "Developer Tools".
As a last-ditch effort before posting this, I disabled SIP on my Mac. Didn't help.
To reproduce my issue:
Get Rust via https://rustup.rs/.
Clone rust-analyzer: git clone https://github.com/rust-lang/rust-analyzer.git.
cd rust-analyzer
Run cargo test --package hir-ty --lib --profile=dev-rel -- tests::incremental::add_struct_invalidates_trait_solve --exact --show-output. By default, this command will output a bunch of build progress with the output containing something like Running unittests src/lib.rs (target/dev-rel/deps/hir_ty-f1dbf1b1d36575fe).
I take the absolute path of that hir_ty-$SOME-HASH string (in my case, it looks like /Users/dbarsky/Developer/rust-analyzer/target/dev-rel/deps/hir_ty-f1dbf1b1d36575fe) and add it to the "Launch" profile. To the arguments section, I add --exact tests::incremental::add_struct_invalidates_trait_solve.
I then try to record/profile via Instruments, but then I get the error message I shared above.
Below is output of codesign -dvvv:
❯ codesign -dvvv target/dev-rel/deps/hir_ty-f1dbf1b1d36575fe
Executable=/Users/dbarsky/Developer/rust-analyzer/target/dev-rel/deps/hir_ty-f1dbf1b1d36575fe
Identifier=hir_ty-f1dbf1b1d36575fe
Format=Mach-O thin (arm64)
CodeDirectory v=20400 size=140368 flags=0x20002(adhoc,linker-signed) hashes=4383+0 location=embedded
Hash type=sha256 size=32
CandidateCDHash sha256=99e96c8622c7e20518617c66a7d4144dc0daef28
CandidateCDHashFull sha256=99e96c8622c7e20518617c66a7d4144dc0daef28f22fac013c28a784571ce1df
Hash choices=sha256
CMSDigest=99e96c8622c7e20518617c66a7d4144dc0daef28f22fac013c28a784571ce1df
CMSDigestType=2
CDHash=99e96c8622c7e20518617c66a7d4144dc0daef28
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements=none
Any tips would be welcome! Additionally—and perhaps somewhat naively—I think I'd expect the Processor Trace instrument to just work with an adhoc-signed binary, as lldb and friends largely do—I'm not sure that such a high barrier for CPU perf counters is warranted, especially on an adhoc-signed binary.
I made a small project that freezes after the following steps:
Run the app
Turn on VoiceOver
Tap on "Header" once so it is read out loud
Turn off VoiceOver
Scroll up and down really quickly
Using the Time Profiler, the items in the Main Thread followed by significant drops are:
19.11 s 85.1% 0 s closure #2 in closure #1 in ViewRendererHost.render(interval:updateDisplayList:targetTimestamp:)
13.05 s 58.1% 4.00 ms ViewGraph.updateOutputs(async:)
7.97 s 35.5% 83.00 ms AG::Graph::UpdateStack::update()
5.76 s 25.6% 19.00 ms LayoutScrollableTransform.updateValue()
1.73 s 7.7% 2.00 ms specialized NativeDictionary.setValue(:forKey:isUnique:)
579.00 ms 2.6% 58.00 ms 0x100a8c908
311.00 ms 1.4% 165.00 ms __thread_stack_pcs
I see the memory usage increase by about 0.6 MB per second while frozen.
And there are a few things that prevent the freeze:
Changing LazyVStack for VStack
Removing the VStack from the Section
Removing the header: parameter from the Section
Reducing the range of the ForEach
Move the Text(verbatim: "Text at same level as ForEach containing Section") outside of the LazyVStack
However, these are all things I need to keep for my actual app. So what is causing this hang? Am I using SwiftUI in any way it's not intended to be used?
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
VStack(alignment: .leading) {
Image(systemName: "pencil.circle.fill")
Text("Title")
Text("Label")
}
ScrollView {
LazyVStack {
Section {
VStack {
ForEach(0..<70) { _ in
Text(verbatim: "A")
}
}
} header: {
Text(verbatim: "Header")
}
Text(verbatim: "Text at same level as ForEach containing Section")
}
}
}
}
}
AppDelegate:
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UINavigationController(rootViewController: MainViewController())
window.makeKeyAndVisible()
self.window = window
return true
}
}
MainViewController:
import UIKit
import SwiftUI
final class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let swiftUIView = ContentView()
let hostingController = UIHostingController(rootView: swiftUIView)
addChild(hostingController)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
hostingController.didMove(toParent: self)
view.backgroundColor = .white
}
}
I’m seeing inconsistent call stacks and usage percentages in the Time Profiler between two Instruments builds:
• Xcode 16.0’s Instruments Version 16.0 (16A242d)
• Xcode 16.3’s Instruments Version 16.0 (16E140)
When I open an old .trace file recorded with the 16A242d profiler in the newer 16E140 Instruments, the call trees and percentage breakdowns no longer match. It looks like the latest Instruments now exposes or collapses different frames (e.g. system libraries, inline code) by default.
I rely on these call stacks as a baseline to track performance regressions and verify optimizations over time. Unfortunately, every Xcode/Instruments update changes what I see, making it impossible to compare profiles across versions.
My questions:
Is there a way in Instruments 16.0 (16E140) to restore the exact call-tree view and percentage calculations that 16A242d produced?
Failing that, is there a recommended workflow or tool for capturing CPU profiles in a way that remains stable and comparable, regardless of Xcode or Instruments version?
Any guidance on achieving consistent, version-independent performance measurements would be greatly appreciated!
I kept CoreLocation’s startUpdatingLocation running for a full day and used Performance trace - PowerProfiler to track the power usage during that time. The trace file was successfully generated on the iOS device, and I later transferred it to my MacBook.
However, when I tried to open the .atrc file, I received the following warning:
The document cannot be imported because of an error: File ‘/Users/jun/Downloads/PowerProfiler_25-06-16_181049_to_25-06-17_091037_001.atrc’ doesn’t contain any events.
Why is this happening? Is there a known issue with PowerProfiler in iOS 26, or am I missing something in the tracing setup?
Note: The .aar file and the extracted .atrc file are not attached here, as forum uploads do not support these formats.
Hi Nathaniel,
I spoke with you yesterday in the WWDC lab. Thanks for chatting with me! Is it possible to get a link to a doc that has some key metrics I'd find in a RealityKit trace so I know if that metric is exceeding limits and probably causing a problem? Right now, I just see numbers and have no idea if a metric is high or low :). This is specifically for a VisionOS app.
Thanks,
Bob
Hi, I need help to get Instruments running to profile my application. I tried to profile my main app (Qt-5.15-Framework, c++, Intel-arch only) from Xcode. My app starts and Instruments runs time profiler or Leaks for about 15 seconds and the quits. No crash, no message nothing.
This has been happening for a while on my Mac Studio M1 Max running macOS 14.7.6 and Xcode 15.4 IDE with a toolchain from Xcode 14.3 for the qmake (qt) project. However, this also happens if i set up a new vanilla Swift UI project from scratch wihtout any Qt stuff.
In addition to the Mac Studio I also have Mac Book Pro M4 running macOS 15.5 and Xcode 16.4. On that machine I get the same results, no matter if I try Instruments on my qt project or a vanilla SwiftUI project.
Also it does not make a difference if I change the toolchain with:
sudo xcode-select -s /Applications/Xcode_143.app
or
sudo xcode-select -s /Applications/Xcode_164.app.
Same results in either case.
I also tried switching to Debug build in the editing the scheme for profiling, but got no better results.
I also tried to lauch Instruments from Xcode using the Open Developer Tool menu entry, but got no better results.
When I start Instruments first, run my program in Xcode and attach to it, I get the same results.
Do you have any advice what to check for or to setup, maybe in signing or such? I am probably missing something basic.
Thanks in advance
As stated in the title.
I am running the following code.
Each time I perform an API call, I create a new instance of URLSession and use a background-configured session to allow background API calls.
`
Code being executed:
import Foundation
// Model definitions
struct RandomUserResponse: Codable {
let results: [RandomUser]
}
struct RandomUser: Codable {
let name: Name
let email: String
}
struct Name: Codable {
let first: String
let last: String
}
// Fetcher class
class RandomUserFetcher: NSObject, URLSessionDataDelegate {
private var receivedData = Data()
private var completion: ((RandomUser?) -> Void)?
private var session: URLSession!
func fetchRandomUserInBackground(completion: @escaping (RandomUser?) -> Void) {
self.completion = completion
let configuration = URLSessionConfiguration.background(withIdentifier: "com.example.randomuser.bg")
session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
let url = URL(string: "https://randomuser.me/api/" )!
let task = session.dataTask(with: url)
task.resume()
}
// Data received
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
receivedData.append(data)
}
// Completion
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
defer { self.session.finishTasksAndInvalidate() }
guard error == nil else {
print("Error: \(error!)")
completion?(nil)
return
}
do {
let response = try JSONDecoder().decode(RandomUserResponse.self, from: receivedData)
completion?(response.results.first)
} catch {
print("Decoding error: \(error)")
completion?(nil)
}
}
}`
Called in viewDidLoad, etc.:
let fetcher = RandomUserFetcher()
fetcher.fetchRandomUserInBackground { user in
if let user = user {
print("Name: \(user.name.first) \(user.name.last), Email: \(user.email)")
} else {
print("Failed to fetch random user.")
}
}
In Instruments' Network instrument, I focus on my app's process, use 'Command + 3', and switch to 'List: URLSessionTasks'.
Even though didCompleteWithError is called and the API call fully completes, the Duration keeps increasing, and the Success column remains '-' (neither 'Yes' nor 'No').
For non-background URLSessions, the session shows up as 'unnamed session', but for background URLSessions, it appears as 'unnamed background session 1 (XXXXXX-XXXXXX-XXXXX)'.
Does this mean the session is not actually being completed?
I've checked Debug Memory Graph and confirmed there is no NSURLSession memory leak, but is it possible that the app is somehow still retaining session information internally?
I also suspect that Instruments may not be able to fully track background URLSession tasks.
Context
I created a short script to CPU profile a program from the command line. I am able to record via the Instruments app, but when I try from the command line I get the following error shown below. This example is just profiling the grep command.
Error:
% cpu_profile /usr/bin/grep \
--recursive "Brendan Gregg" \
"$(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
Profiling /usr/bin/grep into /tmp/cpu_profile_grep.trace
Starting recording with the CPU Profiler template. Launching process: grep.
Ctrl-C to stop the recording
Run issues were detected (trace is still ready to be viewed):
* [Error] Failed to start the recording: Failed to force all hardware CPU counters: 13.
Recording failed with errors. Saving output file...
Script:
#!/bin/sh
set -o errexit
set -o nounset
if [ "$#" -lt 1 ]
then
echo "Usage $0 <program> [arguments...]" 1>&2
exit 1
fi
PROGRAM="$(realpath "$1")"
shift
OUTPUT="/tmp/cpu_profile_$(basename "$PROGRAM").trace"
echo "Profiling $PROGRAM into $OUTPUT" 1>&2
# Delete potential previous traces
rm -rf "$OUTPUT"
xcrun xctrace record \
--template 'CPU Profiler' \
--no-prompt \
--output "$OUTPUT" \
--target-stdout - \
--launch -- "$PROGRAM" "$@"
open "$OUTPUT"
I think the error has to do with xctrace based on this post, but according to this post it should have been resolved in MacOS version 15.4.
System
Chip: Apple M3 Pro
macOS: Sequoia 15.4.1
xctrace version: 16.0 (16E140)
xcrun version: 70.
Xcode version: 16.3 (16E140)
Working Screenshots from Instruments App:
Topic:
Developer Tools & Services
SubTopic:
Instruments
Tags:
Developer Tools
Instruments
Xcode
Debugging
When running instruments or when debug memory in Xcode, I am getting same error as
An unknown error occurred launching the helper task
Xcode: Xcode16.3
OS: 15.5 Beta (24F5068b)
Mac mini: Apple M2 Pro
Hi,
Xcode Instruments shows multiple Points of Interest with the information that the framework is not listed in my Privacy Manifest.
However, I have already included them in the Privacy Manifest under the privacy tracking domains.
I have this problem with every tracking domain i listed in the Privacy Manifest's Privacy Tracking Domains.
Did I make a mistake in my Privacy Manifest declaration?
I am currently reviewing the tutorial documentation for the instruments. (Instruments Tutorials: https://developer.apple.com/tutorials/instruments/identifying-a-hang)
It seems very useful, so I want to follow the tutorials step by step.
However, I am having trouble downloading the sample project files; it appears that the 7z file is broken.
(https://developer.apple.com/instruments/tutorials/downloads/InitialVersion.7z)
Can anyone help me with how to download the project files properly?
I am using XCode16 and macOS 14.7.2. Previously, using the instruments on an iPhone with iOS 14.3 was normal, but when I upgraded to iOS 18, the instruments often couldn't find the library.
I have to restart the instruments to restore normal operation, but the problem will occur again after using it for a period of time
I have an XPC server running on macOS and want to perform comprehensive performance and load testing to evaluate its efficiency, responsiveness, and scalability. Specifically, I need to measure factors such as request latency, throughput, and how well it handles concurrent connections under different load conditions.
What are the best tools, frameworks, or methodologies for testing an XPC service? Additionally, are there any best practices for simulating real-world usage scenarios and identifying potential bottlenecks?
Topic:
App & System Services
SubTopic:
Processes & Concurrency
Tags:
XPC
Endpoint Security
Instruments
Performance
Hi,
I’m encountering an issue while using xctrace & instruments to profile an application on macOS. Specifically, when trying to record a trace using the CPU Profiler template, I get the following errors:
Failed to start the recording: configureHardwareCounters: Failed set kpc configuration: Operation not permitted.
Unexpected failure: Couriers have returned unexpectedly.
macOS Version: 15.3.1
Chip: Apple M4 Pro
Xcode Version: Xcode 16.2
I've discovered what appears to be a system-level memory leak when pressing any key in Swift UI projects. This issue occurs even in a completely empty SwiftUI project with no custom code or event handlers.
When monitoring with Instruments' Leaks tool, I observe multiple memory leaks each time any key is pressed. These leaks consist primarily of:
NSExtraData objects (240 bytes each)
NSMenuItem objects (112 bytes each)
Other AppKit and Foundation objects
Has anyone else encountered this issue? How can I fix this behavior? While the leaks are small (about 5-6KB per keypress), they could potentially accumulate in applications where keyboard input is frequent.
I have a complex CoreImage pipeline which I'm keen to optimise. I'm aware that calling back to the CPU can have a significant impact on the performance - what is the best way to find out where this is happening?
Hello,
We are experiencing slow launch time indicators in our performance monitoring tools(Crashlytics/DataDog/Xcode), and trying to understand what is the best approach to reduce it.
Currently, cold launch takes ~900ms on iPhone 16 Pro , but
~2s on iPhone 11. Profiling app launch detected that most of the time
is spend on loading the libraries. Our app is massive, we use a
total of ~40 3rd parties libraries + 10 internal libraries. We enabled
the "mergeable libraries" XCode new feature however the app
launch is as written above.
We also postponed some of the work in didFinishLaunch, which help a bit...
But maybe we are trying to achieve the impossible?
Could it be that large apps just can't reach the golden 500ms goal?
Currently we are trying to create an "umbrella" library for
all the third parties in order to force them to become part of the
mergeable libraries. We would like to know if, are we on the right
track?
I am a developer creating an app for iOS 16 and my app mysteriously started showing a blank screen during previews and the simulator. I profiled the app launch with Instruments, and the results said that dlopen was running on the main thread for the whole minutes of profiling:
Context
I'm trying to profile a binary (a simple C++ program compiled into dummy.o) and collect CPU Counters data. I have a configuration that works fine from the Instruments Counters GUI (see Screenshots below).
I've exported this configuration to a template file named prof1.tracetemplate.
Problem
When I try to run a recording with that same template from the command line with xctrace (I also tried with sudo):
$ xctrace record --template prof1.tracetemplate --launch dummy.o
I get the following errors:
Starting recording with the prof1 template. Launching process: dummy.o.
Ctrl-C to stop the recording
Run issues were detected (trace is still ready to be viewed):
[Error] Unexpected failure: Couriers have returned unexpectedly.
[Error] Failed to start the recording: Failed to force all hardware CPU counters: 13.
[Error] Failed to pause recording session: Cannot pause session session unless it's running. Current state: kSessionError
[Error] Unexpected failure: Data source agent failed to arm.
Recording failed with errors. Saving output file...
Output file saved as: Launch_dummy.o_2024-01-31_14.22.32_0B6E1A78.trace
System
Chip: Apple M1
macOS: 14.1.1 (23B81)
xctrace version: 15.2 (15C500b)
xcode version: 15.2 (15C500b)
Screenshots