Open-source project
everettjf/appletrace avatar
everettjf/appletrace

AppleTrace turns Objective-C message sends into a Perfetto timeline

🍎Objective C Method Tracing Call Chart

832 stars125 forksHTMLMIT

At a glance

What is it?
AppleTrace is an embeddable iOS and macOS tracer that records manual sections or every objc_msgSend into sandbox trace fragments that a Python pipeline merges into a trace.json you open in the browser at ui.perfetto.dev.
Who is it for?
Engineers debugging Objective-C performance or message dispatch on iOS and macOS should embed AppleTrace directly in the app under investigation, because the manual APTBegin and APTEnd path needs no source rewrites and no toolchain beyond Xcode.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly HTML, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A tracer that writes Perfetto fragments from inside the app

AppleTrace is an iOS and macOS tracing toolkit that you embed in your own application. It records a timeline of events into sandbox trace fragments, and a small Python pipeline merges those fragments into a single trace.json that you open directly in Perfetto at ui.perfetto.dev to explore the call timeline, durations, threads and counters.

The audience is developers working on Apple platforms who need to see what their app actually did at runtime: performance analysis to find hotspots and long methods, debugging to follow method execution flow across threads, learning how frameworks dispatch, and security research into third-party app behaviour.

Two things shape the design. The first is that the output is Perfetto, not a proprietary format. There is nothing to install on the analysis side, it runs in the browser, and it scales to large traces. Begin and end pairs export as complete events by default, which the README notes roughly halves trace size.

The second is embeddability. The library is described as lightweight and embeddable, and the project ships as an Objective-C source package with a Swift package consumed by the Swift demo. Trace names are carried through, so Perfetto shows real thread names instead of bare ids.

The trace timeline that comes out is the method execution timeline and the call relationships between those methods.

Two ways to instrument: manual sections or a msgSend hook

AppleTrace gives you two modes, and the choice between them is really a choice about risk.

Mode A is manual instrumentation. You add begin and end markers around the region you care about, and the README calls this the recommended baseline and the lowest-risk option because it works on every OS version and changes nothing about how your code dispatches messages:

objc
#import <appletrace/appletrace.h>

- (void)yourMethod {
    APTBegin;            // section named "[ClassName yourMethod]"
    // ... your code ...
    APTEnd;
}

Mode B is automatic. Rather than annotate your code, AppleTrace rebinds objc_msgSend and objc_msgSendSuper2 directly on arm64, so every Objective-C message send is captured with no source changes at all. Installation is a single call after launch:

objc
// From your app, after launch:
APTInstallObjcMsgSendHook();

Automatic tracing is where the interesting engineering sits, because it has to stay cheap. The README describes (Class, SEL) name interning, a zero-allocation per-thread call stack, and per-thread batched writing, all aimed at keeping malloc, snprintf and dispatch off the per-message path.

Because automatic capture is inherently broad, the hook can be scoped. Environment variables APPLETRACE_TRACE_CLASS_ALLOW and APPLETRACE_TRACE_CLASS_DENY filter by class prefix, so you can trace a subsystem without paying for the whole application. The Swift sample adds a SwiftTrace auto-hook through the AppleTraceAuto product.

Instants, counters and async events beyond begin and end pairs

Begin and end markers are only part of the event vocabulary, and the richer types are what make a trace useful for live debugging rather than just for method timing.

APTInstant records a point in time. APTCounter records a counter series, and the README names memory, FPS and queue depth as the intended uses, so you can plot a metric against the timeline of what the app was doing. APTAsyncBegin and APTAsyncEnd describe work that crosses threads and dispatch queues, which is exactly the case that a naive method trace renders badly.

The helpers APTBegin, APTEnd and APTScopeSection sit alongside the explicit APTBeginSection and APTEndSection pair, so you can choose between a named scope that closes itself and an explicit pair that you control.

There is also a binary fragment format, enabled by setting the APPLETRACE_BINARY environment variable to 1. The README states that this keeps string formatting off the per-message path entirely, which is the option to reach for when the tracing overhead itself starts to distort the result you are trying to measure.

The Python tooling that comes with the project is a unified CLI at scripts/appletrace_cli.py, with a streaming merge for large captures, automated tests, and GitHub Actions CI.

Merging fragments into trace.json with merge.py or go.sh

Getting the toolkit onto your machine is a short sequence of shell steps, and the README documents the prerequisites as macOS with python, git and ldid, where ldid is only needed for re-signing loader builds:

bash
# 1. Prerequisites (macOS)
brew install python git ldid          # ldid is only needed for re-signing loader builds

# 2. Clone
git clone https://github.com/everettjf/AppleTrace.git
cd AppleTrace

# 3. Optional: Python tooling for merging/tests
python3 -m pip install -r requirements.txt

The fastest way to see a complete trace is the bundled Swift demo, which runs a curated multi-threaded workload with app-startup spans, parallel ImageDecoder, NetworkClient and DatabaseWriter threads, async download arcs, and a 60-frame render loop with live FPS and memory counters. The app prints the on-disk trace directory and the exact commands to merge and open it:

bash
python3 merge.py -d "<trace directory shown in the app>"     # → trace.json
# or in one step:
sh go.sh "<trace directory shown in the app>"

The merge step produces trace.json, which you open at ui.perfetto.dev. On the Simulator the trace directory is already on your Mac. On a device you have to pull the app container first, and the app shows the full command.

The Python requirements are minimal. The only pinned dependency is pytest>=9.0.3, and the comment in requirements.txt notes that this version picks up the fix for CVE-2025-71176 around insecure /tmp/pytest-of-* handling.

Where AppleTrace is the wrong tool

The constraints are specific, and they rule the tool out for a lot of work.

The automatic hook is arm64 only. It relies on direct objc_msgSend and objc_msgSendSuper2 rebinding on arm64, so it does nothing useful on a 32-bit target, and the manual path is the only option there. Since the library traces Objective-C message sends, a Swift codebase that will not adopt the AppleTraceAuto SwiftTrace hook gets very little from the automatic mode.

The tool is also Apple-platform only. The prerequisites are macOS, the demo needs Xcode and a Simulator or a device, and the loader builds need re-signing with ldid. There is nothing here for Android, Linux or Windows analysis.

The packaging picture is worth flagging. The repository lists a single release tag, v1.0 dated 2018-12-19, while the last push was on 2026-10-06. In other words, the code is moving but the released artefacts are old, so anyone integrating this is expected to build from source and vendor it themselves.

Finally, the scope is method tracing. The README describes the output as a timeline of events, durations, threads and counters, and it does not document memory sampling, energy metrics, or network capture, so it is not a replacement for a full system profiler.

Repository layout and the maintenance picture behind it

The repository is organised in a way that tells you what the project treats as product and what it treats as tooling. The core library lives in the appletrace directory, with Sources for the Swift side, plus an appletrace_binary.py module and a springboard directory for the loader. Sample data sits in sampledata, documentation in docs and Tutorial, and two runnable examples under sample: AppleTraceSwiftDemo in Swift and TraceAllMsgDemo in Objective-C.

Release artefacts live in a release directory, and there is a ROADMAP.md at the root. AGENT.md, AGENTS.md and CONTRIBUTING.md describe how work is coordinated on the project, and the CI configuration lives under .github.

The README describes the maintenance posture as maintained as needed, and the recent commit history is consistent with a project that is still touched: the last push was on 2026-10-06, well inside the last six months. What it is not is a project with a regular release train, given the single 2018 tag.

The licence is MIT, which is permissive enough that vendoring the library into a commercial app is straightforward. The MIT terms and their notice requirement are what govern, and the LICENSE file at the root is the authoritative copy.

One dependency note is worth repeating because it is easy to miss: the tooling pins pytest>=9.0.3 specifically to pick up the fix for CVE-2025-71176 concerning insecure /tmp/pytest-of-* handling, so do not relax that pin in requirements.txt.

Editorial conclusion

Engineers debugging Objective-C performance or message dispatch on iOS and macOS should embed AppleTrace directly in the app under investigation, because the manual APTBegin and APTEnd path needs no source rewrites and no toolchain beyond Xcode. It is the wrong choice for Swift-only work that will not adopt the SwiftTrace auto-hook, for Android or Linux targets, and for anyone who expects a released binary, since the repository lists a single v1.0 tag from 2018 while the last push was on 2026-10-06. Before adopting, verify that merge.py runs on your captured fragments, confirm the automatic objc_msgSend hook is arm64 only, and read the LICENSE file for the MIT terms that apply to your build.

Frequently asked questions

How do I get an AppleTrace trace into Perfetto?

AppleTrace records events into sandbox trace fragments, and the Python tooling merges them into a single trace.json that you open at ui.perfetto.dev. The README shows the merge as python3 merge.py -d with the trace directory, or sh go.sh with the same directory as a single step.

Does the automatic objc_msgSend hook work on every device?

No. The automatic mode works by direct objc_msgSend and objc_msgSendSuper2 rebinding on arm64, so it is arm64 only. The README describes manual APTBegin and APTEnd sections as the lowest-risk option that works on every OS version.

What events can AppleTrace record besides method sections?

APTInstant records point-in-time markers, APTCounter records counter series such as memory, FPS or queue depth, and APTAsyncBegin with APTAsyncEnd describe work that crosses threads and dispatch queues. The README also mentions a SwiftTrace auto-hook exposed through the AppleTraceAuto package product.

What licence is AppleTrace released under?

The project is released under the MIT licence, with the LICENSE file at the root of the repository as the authoritative text. The MIT notice requirement applies to any build you distribute.

Official sources

  1. everettjf/appletrace on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/everettjf-appletrace.svg)](https://hysenlabs.com/projects/everettjf-appletrace)

Was this useful?