Signposts for performance: 2 Instruments

Apple detailed and demonstrated its free tool for harvesting and analysing Signposts, as a means of assessing performance, at WWDC 2018. This article describes my own attempts to replicate those demonstrations, to understand their benefits and limitations.

For Apple, all macOS and iOS development is centred on Xcode, and Signposts are no exception. Provided that you developed your app/tool/whatever in Xcode and it can write Signposts using the standard macOS/iOS interface, then you can use these tools. If you’re working in a scripting language with a restricted interface to macOS, then you will have problems.

In Swift, this is now simple stuff, and stepped through in the help pages for Instruments. In essence, you build your app for a Profile product, which automatically launches the linked Instruments app. Select a blank template in Instruments, then add the os_signpost instrument from its library to the pane at the top left of Instruments’ window, and you’re ready to run your app.

Although at this stage the build process has completed, your app won’t be launched until you start recording it in Instruments. Once that’s done, quit the app or stop recording. You can then browse the Signpost data which it has harvested.

The os_signpost instrument works with real-time streamed log entries, i.e. Signposts. You’ll also see many Signposts from other related processes, such as Metal, together with those which you have written.

The Signposts instrument makes the assumption that what you want to study are the time intervals between matching begin and end Signposts. For example, if you want to know the time taken to transit a loop which is repeated many times, you should write Signposts in this way:
for item in theDirEnumerator {
let mySpid = OSSignpostID(log: self.myLog!)
os_signpost(.begin, log: self.myLog!, name: "scanFolderSP", signpostID: mySpid)
// do whatever the loop does
os_signpost(.end, log: self.myLog!, name: "scanFolderSP", signpostID: mySpid)

Each paired begin and end will be given a unique signpostID, which the Signpost instrument then uses to measure the time between those two points. signpostIDs are a problem for command tools such as Blowhole: although they contain a UInt64, the only current means of generating a valid signpostID is to ask the system for one. Because of this, separate calls to Blowhole cannot write Signposts with the same signpostID. This makes it impossible, for example, for AppleScript to write begin-end Signpost pairs using Blowhole.

If you do that, the instrument will indeed provide you with statistical information about the time elapsed between each of the begin-end pairs. Although the instrument lists event Signposts too, it seems unable to make any further use of them, and they cannot provide times in its analysis.

In my case, in my test app Whither, this was a sticking point, as I had placed just a single begin at the start of the iteration loops, and a matching end at their finish. The Signposts instrument therefore recorded this as one long period, and was unable to resolve times or rates based on the event Signposts written at the end of each pass through the loop.


There is another instrument provided to look at ‘Points of Interest’, but that too ignores event Signposts.

It is of course possible to write your own instrument to perform quite different analyses. Before committing to doing so, I recommend that you study the material from session 410 of WWDC 2018, which deals with the creation of custom instruments. They’re not as simple as you might think, and writing your own looks like a serious commitment.

Signposts are only available in macOS 10.14 Mojave. Xcode 10 currently runs on High Sierra and Mojave alone; support for High Sierra may be dropped soon after the release of Mojave in the autumn/fall. So using Signposts to assess performance in Instruments can only be performed live on a Mac running Mojave. Apple doesn’t provide any equivalent which can be used with High Sierra or earlier.

In summary, Apple’s solution using Signposts works well in the following circumstances:

  • You will only run performance tests under Mojave, on Macs with Xcode and Instruments installed.
  • Instruments will harvest Signposts from the live log stream. It is unable to harvest from logs collected previously.
  • You will build your app on the Mac being used for testing.
  • You are using a supported language such as Swift or Objective-C, with full access to macOS.
  • You want to measure times elapsed between begin-end paired Signposts, with matching signpostIDs.

If you need anything different, then you can’t use Signposts with Xcode, Instruments, and the standard os_signpost instrument.