Finding the Slow Spots in Your Code with the Time Profiler Instrument
I continue my coverage of Instruments with the Time Profiler instrument. If your app is running slowly, use the Time Profiler instrument to find the slow spots in your code so you know where to optimize.
If you are new to Instruments, I recommend reading the Measuring Your App’s Memory Usage with Instruments article. That article provides an introduction to Instruments and covers some aspects of using Instruments this article glosses over.
How the Time Profiler Instrument Works
The Time Profiler instrument records the call stack every millisecond. The function at the top of the call stack is the function your app is currently executing. If a function appears at the top of the call stack in a lot of samples, that’s a sign your app is spending a lot of time in that function.
Launch and Record
Choose Product > Profile in Xcode to launch Instruments. Select the Time Profiler template and click the Choose button.
Click the Record button to launch your app and start profiling.
Controlling the Graph
When you pause recording you’ll notice the Time Profiler instrument shows a lot of graphs. There’s a graph for each thread, and iOS and Mac apps have a surprisingly high number of threads.
Above the graph is a series of buttons to control what graphs appear in the trace document window.
You can show instruments, threads, or CPU cores. You can also use the search field to filter what graphs appear. At the start you should focus on instruments, specifically CPU usage, because it helps find the slow spots in your code.
CPU Usage Graph
Starting with Xcode 10 the Time Profiler instrument has two graphs: CPU usage and life cycle. If you move the mouse cursor over the CPU usage graph, tooltips appear with the percentage of CPU usage at that moment in the recording.
Life Cycle Graph
The life cycle graph reports the current state of your app: initializing, launching, foreground, or background. If you move the mouse over the life cycle graph, tooltips tell you the state of the app and the amount of time the app was in that state.
Older versions of Xcode do not have a life cycle graph.
Profile Data
The Time Profiler instrument shows the call tree view initially. Click the Call Tree button at the bottom of the window and select the Invert Call Tree and Hide System Libraries checkboxes to make your code easier to find in the call tree view.
For each function the call tree tells you its weight and it self weight. The weight is expressed as a time and a percentage. The weight measures the amount of time the function was on the call stack. The self weight measures the amount of time the function was at the top of the call stack.
The Self Weight column is more important. Suppose you have a function A that calls functions B and C. The Weight column for A tells you the amount of time your app was in functions A, B, and C. The Self Weight column for A tells you the amount of time your app was in A. When you’re looking for the slow spots in your code, look at functions with a high self weight.
Double-clicking a function opens the source view, where you can see the lines of code that take the most time in the function.
Narrative
The narrative section has a listing for each event in the Life Cycle graph. Each listing has the start time relative to the start of the recording and a description of what the app is doing.
Older versions of Xcode do not have a narrative section.
Samples
If you choose Samples from the jump bar, you can look at every sample the Time Profiler instrument took during the recording. Instruments shows the following data for each sample:
- Sample time, relative to the start of recording
- Core, the CPU core
- Process, which is the name of your app
- Thread
- State, which is usually Running
- Backtrace, which lists the function at the top of the call stack
The extended detail view shows a compressed backtrace. If you want to see every function in the call stack, click the button at the top right of the backtrace.
Remember that the Time Profiler instrument takes a sample every millisecond so there are a lot of samples to go through.
CPU Cores
If you move the mouse cursor over a CPU core in the graph, a tooltip appears showing you the percentage of CPU usage for that core at that moment in the recording.
Selecting a CPU core from the instrument list fills the detail view with call tree statistics for that core. Choosing Samples from the jump bar shows all the samples Instruments recorded for that CPU core.
Threads
If you move the mouse cursor over a thread in the graph, a tooltip appears showing the percentage of CPU usage for that thread at that moment in the recording. The graph can tell you if the main thread is doing too much work.
Selecting a thread from the instrument list fills the detail view with call tree statistics for that thread. Choosing Samples from the jump bar shows all the samples Instruments recorded for that thread.
Summary
The main point of using the Time Profiler instrument is to find the slow spots in your code. Look for functions in the call tree with a high self weight. If you need to make your app run faster, start by optimizing those functions with a high self weight.