Connect with us


Getting accurate profiling data from iOS applications

In this article, we’ll discuss several tools that can be used to instrument or sample your application and the pros and cons of each.

An important step in developing an iOS application is performance optimization. Making an app run smoothly on any device is crucial to ensure that it will offer a good user experience.

However, when faced with performance issues, it’s not always possible to understand why an application performs poorly by only looking at the code. Gathering profiling data at runtime is often necessary to determine where and how the code needs to be optimized.

This profiling data often comes in the form of so-called counters, which tell you how many times a region of code, such as a function, was executed. These counters can then be extrapolated into large-scale statistics or correlated with other data sources to provide insights into your application’s runtime performance.

There are multiple ways that such counters can be obtained, but the two most common approaches are:

Sampling does not require rebuilding your program. It is done by an external process that observes your program’s execution and, for instance, counts how many times each function has been executed.

Instrumenting requires rebuilding your program with special flags so the compiler can add “checkpoints” throughout in your program, which will individually keep track of how many times they’ve been hit.

Getting accurate profiling data from your application is crucial to optimize it correctly. Fortunately, both of these techniques will produce very accurate data, and choosing which one to use depends on what your constraints (or preferences) are.

In this article, we’ll discuss several tools that can be used to instrument or sample your application and the pros and cons of each.

Sampling with Xcode’s Instruments

The most well-known technique for obtaining performance data in the Apple ecosystem is through the Instruments app. This can be used to sample your application at runtime so you can get an accurate performance profile without having to rebuild the application.

As explained before, sampling is done by an external observer process, which will check what your application is doing periodically (as often as every few milliseconds). Based on the current program counter of your application (i.e. the current code being executed) and your app’s debugging symbols, the tool will know exactly which function is being executed for each sample taken.

This is convenient because it requires little effort on our side and does not require rebuilding the application. It’s also very accurate if the sampling rate is high, as you will basically know what your application is doing every millisecond. However, Instruments has a couple of drawbacks:

  • It’s a black box: We have little insight into how it gathers its data and how it estimates where our application is spending its time.
  • It doesn’t allow exporting the data to a format that can be read by third-party tools. It only allows saving the data to trace files that do not have a fixed structure (They contain private serialized classes that can change between Xcode versions).

If the tool outputs data in an undocumented or unstable format, it can often be a deal-breaker because it becomes very difficult to manipulate the data outside of Instruments (such as scripts or third-party tools). This means that Instruments is not the best solution for continuous integration or automation purposes, even though it is perfectly viable to manually optimize your application.