Agent skill

Analyze Perfetto Trace

by ZacSweers in ZacSweers/metro

Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time.

Apache-2.0Auto-check passedMobile

Install Analyze Perfetto Trace

skills CLI
$ npx skills add ZacSweers/metro --skill analyze-perfetto-trace -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install ZacSweers/metro analyze-perfetto-trace --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/ZacSweers/metro.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/analyze-perfetto-trace .claude/skills/analyze-perfetto-trace && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
analyze-perfetto-trace
GitHub stars
1.4k
Token cost
~2.7k tokens
SKILL.md length
1,128 words
Files
1
Skills in repo
4
Repo updated
First seen
Licence
Apache-2.0

At a glance

Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time.

  • Works in 6 steps: Get the parent's dur — SELECT dur FROM… → Sum direct children — the "Children of a… → gap = parent - sum(children). → …
  • The user asks about metro compile-time perf
  • SKILL.md covers When to use, Where metro writes traces, Producing a fresh trace from a… and Producing a fresh trace from…, plus 8 more sections
  • Calls python3, pip and brew

What it does

Analyze Perfetto Trace is an agent skill from ZacSweers/metro. Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time. Use whenever the user asks about metro compile-time perf, where time is going in a trace, or shares a perfetto screenshot.

Its SKILL.md is about 2.7k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile. The repository describes itself as: A multiplatform, compile-time dependency injection framework for Kotlin. The licence is Apache-2.0.

When your agent uses it

  • The user asks about metro compile-time perf
  • Where time is going in a trace
  • Shares a perfetto screenshot

Example prompts

  • “/analyze-perfetto-trace”

Requirements

  • Python 3

Workflow steps

6 steps, taken from the first numbered list in SKILL.md.

  1. Get the parent's dur — SELECT dur FROM slice WHERE name = '' LIMIT 1.
  2. Sum direct children — the "Children of a named parent" query above, sum the durs.
  3. gap = parent - sum(children).
  4. If gap is significant (>10% or >1ms), that time is spent in untraced code inside the phase.
  5. Open the source, find calls that happen between/before/after the existing trace("...") blocks in that phase, and add trace("...") around…
  6. Re-profile to confirm — the gap should now be filled by the new spans.

What it can do on your machine

Read from SKILL.md and the folder at commit ba2f45f. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • python3
    • pip
    • brew

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use pip, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Analyze Perfetto Trace loads about 2.7k tokens when it runs. Until then it costs about 60 tokens; SKILL.md has 1,128 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~60
When it runs · the whole SKILL.md, loaded when a task matches
~2.7k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from ZacSweers/metro at commit ba2f45f, republished under its Apache-2.0 licence (© ZacSweers). 1,128 words, ~2,674 tokens.

Download SKILL.mdSave it as .claude/skills/analyze-perfetto-trace/SKILL.md (or your agent's skills folder).
name
analyze-perfetto-trace
description
Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time. Use whenever the user asks about metro compile-time perf, where time is going in a trace, or shares a perfetto screenshot.

When to use

  • User shares a metro perfetto trace file (.perfetto-trace) or a perfetto UI screenshot.
  • User asks "where is time going in the metro compiler" / "why is phase X slow".
  • You need to verify a suspected hot spot instead of guessing from the code. The profile is almost always more informative than code reading.
  • Before recommending optimizations so you're fixing the thing that actually matters.

Where metro writes traces

Metro writes perfetto traces into the configured traceDestination directory. As of the FIR + IR tracing rework, one compilation produces multiple files — one per FIR session and one per IR module fragment — all sharing a common id prefix:

<traceDestination>/<id>-<phase>-<moduleName>.perfetto-trace
  • <id> is a yyMMdd-HHmmss timestamp generated once per compilation. Every file from the same compilation invocation shares it, so you can group them by prefix.
  • <phase> is fir or ir.
  • <moduleName> is the FIR session name (commonMain, jvmMain, etc.) or the IR IrModuleFragment.name (often main). Filesystem-unsafe characters in module names are replaced with _.

Examples: 260505-133503-fir-commonMain.perfetto-trace, 260505-133503-ir-main.perfetto-trace.

When asked "look at the trace", first decide which phase the user is asking about. FIR-side time (checkers, generators, supertype computation) lives in the fir-* files; IR-side time (graph processing, transformers) lives in the ir-* files. They are separate timelines — not a unified trace — so you cannot directly compare durations across files. If multiple older invocations exist in the directory, pick the freshest <id> group unless the user points at a specific file.

Producing a fresh trace from a local Metro change

Use ./metrow trace (or the underlying scripts/trace-project.sh directly). It publishes Metro to mavenLocal, bumps the target project's metro version in gradle/libs.versions.toml, runs the given compile task with -Pmetro.traceDestination=metro/trace --rerun, locates the freshest .perfetto-trace (variant subdir varies by task), and copies it into tmp/traces/<timestamp>-<version>_<task>.perfetto-trace. The path is also written to tmp/traces/LATEST so you can chain with TRACE=$(cat tmp/traces/LATEST) in analysis.

./metrow trace <project-dir> <gradle-task> [version]
./metrow trace ~/dev/android/personal/CatchUp :app-scaffold:compileDebugKotlin

Pass --open-in-browser (or --open) to additionally launch the trace in ui.perfetto.dev — the script fetches Google's open_trace_in_ui helper once (cached at tmp/open_trace_in_ui) and fires it in the background so the UI can keep streaming the file:

./metrow trace --open-in-browser ~/dev/android/personal/CatchUp :app-scaffold:compileDebugKotlin

Equivalent direct call:

scripts/trace-project.sh [--open-in-browser] <project-dir> <gradle-task> [version]

Use this when the user asks for a "fresh trace" / "re-profile" / has just made a Metro change they want profiled against a real-world project.

Producing a fresh trace from the in-repo benchmark project

For raw-perf iteration on a large generated project (no external repo needed), use benchmark/trace_compile.sh. It runs gradle-profiler against a fresh :app:component:compileKotlin --rerun of the benchmark project, with Metro's perfetto tracing enabled, and picks the iteration whose duration is closest to the measured-mean — so a single representative trace lands in tmp/traces/ (and tmp/traces/LATEST is updated).

benchmark/trace_compile.sh                  # run + pick + copy
benchmark/trace_compile.sh --open-in-browser  # also open in ui.perfetto.dev
TRACE=$(cat tmp/traces/LATEST)              # chain into analysis

Prereqs: the benchmark project must be generated for metro mode (cd benchmark && kotlin generate-projects.main.kts --mode metro). gradle-profiler is auto-installed on first run. Use this for "raw compile perf on a 500-module project" iteration loops where you don't need a real-world app like CatchUp.

Tooling

Use the perfetto python library. It's available via pip but installed against a specific python — on this machine it's Python 3.13, not the default 3.14:

bash
/opt/homebrew/opt/python@3.13/bin/python3.13 -c "from perfetto.trace_processor import TraceProcessor; print('ok')"

If python3 -c "import perfetto.trace_processor" fails with ModuleNotFoundError, switch to the 3.13 binary above. pip install perfetto installs against whatever python3 on PATH points to, which may not be the one actually invoked.

Do not try brew install perfetto — there is no homebrew cask/formula for it.

Running a query — the runner pattern

Always wrap the Python in a single -c invocation so it stays self-contained. The boilerplate:

bash
/opt/homebrew/opt/python@3.13/bin/python3.13 -c "
from perfetto.trace_processor import TraceProcessor
tp = TraceProcessor(trace='<ABSOLUTE_PATH>')
r = list(tp.query('''
  <SQL>
'''))
for row in r:
    print(f'{row.dur/1e6:6.2f}ms  {row.name}')
tp.close()
"

Notes:

  • trace= must be an absolute path.
  • dur is in nanoseconds — divide by 1e6 for ms.
  • tp.query() returns a rows iterator; wrap in list() if you'll iterate more than once.
  • Always tp.close() at the end.

The slice table

That's the one you'll use 95% of the time. Relevant columns:

columnmeaning
idslice id (primary key)
nametrace span name (e.g. "Build GraphNode")
durduration in nanoseconds
parent_idparent slice id (or NULL at top level)
tsstart timestamp (nanoseconds since trace start)

Canonical queries

Top-level slice durations
sql
SELECT name, dur FROM slice ORDER BY dur DESC LIMIT 30

Gives an ordered view of the biggest spans. Start here.

Sum by name (when the same span fires many times)
sql
SELECT name, SUM(dur) AS total_dur, COUNT(*) AS cnt
FROM slice GROUP BY name ORDER BY total_dur DESC LIMIT 30

Useful for per-class spans like "Visit X" that fire hundreds of times.

Show full SKILL.md (443 more words)Show less
Children of a named parent
sql
WITH parent AS (SELECT id FROM slice WHERE name = 'Build binding graph' LIMIT 1)
SELECT name, dur FROM slice
WHERE parent_id = (SELECT id FROM parent)
ORDER BY dur DESC

This is the most important query for finding gaps. Compare the summed children to the parent duration:

python
total_child = sum(row.dur for row in r)
print(f'children sum: {total_child/1e6:.2f}ms  parent: <parent dur>ms  gap: <diff>ms')

A large gap means there's untraced work inside the parent. That's where to add instrumentation or investigate.

Only children above a threshold
sql
SELECT name, dur FROM slice
WHERE parent_id = (SELECT id FROM slice WHERE name = 'Core transformers' LIMIT 1)
  AND dur > 1e6  -- >1ms
ORDER BY dur DESC
Find the biggest single slice across the whole trace
sql
SELECT name, dur FROM slice ORDER BY dur DESC LIMIT 1
Time spent inside a category (recursive descendants)

If you want "all time spent under parent X including grandchildren":

sql
WITH RECURSIVE descendants(id) AS (
  SELECT id FROM slice WHERE name = 'Core transformers'
  UNION
  SELECT s.id FROM slice s JOIN descendants d ON s.parent_id = d.id
)
SELECT SUM(dur) FROM slice WHERE id IN (SELECT id FROM descendants)

Note: summing descendants double-counts time (parent dur already includes children). Use this for "total CPU in this subtree" questions, not for gap math.

The "find the gap" recipe

This is the workflow you'll use most often when someone says "X looks slow but it's a black box":

  1. Get the parent's dur — SELECT dur FROM slice WHERE name = '<phase>' LIMIT 1.
  2. Sum direct children — the "Children of a named parent" query above, sum the durs.
  3. gap = parent - sum(children).
  4. If gap is significant (>10% or >1ms), that time is spent in untraced code inside the phase.
  5. Open the source, find calls that happen between/before/after the existing trace("...") blocks in that phase, and add trace("...") around them.
  6. Re-profile to confirm — the gap should now be filled by the new spans.

Worked example: on a 161ms catchup build, "Build binding graph" was 11.3ms but direct children summed to 4.2ms. The 7ms gap was construction of BindingLookup/IrBindingGraph/IrBindingStack at the top of generate(), which had no trace. Wrapping that in trace("Construct lookup & graph") surfaced it.

Interpreting the numbers

  • Total compile time = the top-level span (usually "Metro compiler").
  • If one phase is >30% of total, that's your first target.
  • "Gap percentage" inside a phase (untraced / total) tells you whether to instrument (big gap) or dig into a specific child (small gap).
  • cnt in the sum-by-name query tells you whether to optimize per-call work (high cnt, small per-call) or one-shot cost (cnt=1, big dur).

Don't

  • Don't recommend optimizations without looking at the trace first when a trace is available. The profile almost always surprises you. E.g. you might guess "Process declarations" is slow; the trace might say it's 1.2ms while "Collect supertypes" is 7.5ms.
  • Don't confuse sum(descendants) with parent dur — parent already includes all descendants. Use direct children for gap math.
  • Don't assume the whole timeline is work — long top-level spans often contain significant I/O or lazy-init time. Instrument to confirm.

Helpful follow-up queries after finding a hot spot

What's the biggest single call of name = X?
sql
SELECT dur FROM slice WHERE name = '<name>' ORDER BY dur DESC LIMIT 5
What's nested inside a specific long instance of a span?

Get the id first (SELECT id FROM slice WHERE name = '<name>' ORDER BY dur DESC LIMIT 1), then:

sql
SELECT name, dur FROM slice WHERE parent_id = <id> ORDER BY dur DESC
Group by thread / process (rare, usually metro is single-threaded)
sql
SELECT thread.name, SUM(slice.dur) AS total
FROM slice JOIN thread_track ON slice.track_id = thread_track.id
          JOIN thread ON thread_track.utid = thread.utid
GROUP BY thread.name ORDER BY total DESC

© ZacSweers, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/analyze-perfetto-trace of ZacSweers/metro.

Open the folder on GitHubat commit ba2f45f

Compare with similar skills

Analyze Perfetto Trace next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Analyze Perfetto Trace compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Analyze Perfetto Trace this skillZacSweers/metro1.4k—~2.7kAutomated safety check: PassApache-2.0
React Native Best Practicesvercel-labs/openreview1.7k17 repos~1.1kAutomated safety check: PassMIT
Swiftui Protwostraws/SwiftUI-Agent-Skill5.6k2 repos~1.5kAutomated safety check: PassMIT
Kortix Brandkortix-ai/suna20k—~4kAutomated safety check: PassCustom licence
Ip As LogoKartikLabhshetwar/better-shot2.4k1 repos~4.3kAutomated safety check: PassMIT
Compose Multiplatform Patternsmonta-app/ocpp-emulator1805 repos~2kAutomated safety check: PassApache-2.0

Similar skills

  • React Native Best Practices

    vercel-labs/openreview

    Official

    A prioritized rule set for React Native and Expo apps covering list performance, animation, navigation, UI patterns, state, rendering, monorepos and configuration.

    1.7k GitHub starsUsed in 17 repos~1.1k tokens
    MobileAuto-check passed
  • Swiftui Pro

    twostraws/SwiftUI-Agent-Skill

    Comprehensively reviews SwiftUI code for best practices on modern APIs, maintainability, and performance.

    5.6k GitHub starsUsed in 2 repos~1.5k tokens
    MobileAuto-check passed
  • Kortix Brand

    kortix-ai/suna

    Load FIRST for anything that carries the Kortix look or voice: product or mobile UI, copy of any kind, decks, social, images, email, CLI output, anything with the logo, and reviews of these.

    20k GitHub stars~4k tokensUpdated today
    MobileAuto-check passed
  • Ip As Logo

    KartikLabhshetwar/better-shot

    Generate extremely simple, cute, personified square character images with rounded heavy forms, two purposeful character colors, one solid background color, and a dominant lower-corner composition.

    2.4k GitHub starsUsed in 1 repo~4.3k tokens
    MobileAuto-check passed
  • Compose Multiplatform Patterns

    monta-app/ocpp-emulator

    Compose Multiplatform and Jetpack Compose patterns for KMP projects — state management, navigation, theming, performance, and platform-specific UI.

    180 GitHub starsUsed in 5 repos~2k tokens
    MobileAuto-check passed
  • Aso Appstore Screenshots

    adamlyttleapps/claude-skill-aso-appstore-screenshots

    Generate high-converting App Store screenshots by analyzing your app's codebase, discovering core benefits, and creating ASO-optimized screenshot images using Nano Banana Pro.

    1.8k GitHub starsUsed in 1 repo~9.6k tokens
    MobileAuto-check passed

More from ZacSweers/metro

  • Test Metro Ide Locally

    ZacSweers/metro

    Run Metro's IDE plugin from source in a sandboxed local IDE against a consumer project.

    1.4k GitHub stars~3k tokensUpdated today
    Auto-check passed
  • Test Metro Locally

    ZacSweers/metro

    Publish the current Metro checkout to Maven Local and verify it in an external consumer or reproducer.

    1.4k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Add Compiler Option

    ZacSweers/metro

    Adds a new compiler option to Metro.

    1.4k GitHub stars~1.1k tokensUpdated today
    Auto-check passed

Categories

Questions about Analyze Perfetto Trace

What does Analyze Perfetto Trace do?

Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time. Analyze Perfetto Trace is an agent skill from ZacSweers/metro. Query and analyze Metro's perfetto compiler traces to find real hot spots and untraced time.

When should I use Analyze Perfetto Trace?

Analyze Perfetto Trace fits situations like: the user asks about metro compile-time perf; where time is going in a trace; shares a perfetto screenshot.

How do I install Analyze Perfetto Trace in Claude Code?

Run `npx skills add ZacSweers/metro --skill analyze-perfetto-trace -a claude-code`. Or copy the skill folder (.agents/skills/analyze-perfetto-trace in ZacSweers/metro) into .claude/skills/analyze-perfetto-trace in your project. Claude Code loads it when a task matches its description.

How do I install Analyze Perfetto Trace in Codex?

Run `npx skills add ZacSweers/metro --skill analyze-perfetto-trace -a codex`. Or copy the skill folder (.agents/skills/analyze-perfetto-trace in ZacSweers/metro) into .agents/skills/analyze-perfetto-trace in your project. Codex loads it when a task matches its description.

Can I use Analyze Perfetto Trace in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ZacSweers/metro --skill analyze-perfetto-trace -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/analyze-perfetto-trace, .gemini/skills/analyze-perfetto-trace, .github/skills/analyze-perfetto-trace and .opencode/skills/analyze-perfetto-trace in your project.

What does Analyze Perfetto Trace need to run?

Going by SKILL.md and its folder, Analyze Perfetto Trace needs the command-line tools its instructions call (python3, pip and brew). Our summary lists: Python 3.

Does Analyze Perfetto Trace access the network?

SKILL.md contains no URLs. Its commands use pip, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Analyze Perfetto Trace safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Analyze Perfetto Trace use?

Analyze Perfetto Trace is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Analyze Perfetto Trace use?

About 2.7k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Analyze Perfetto Trace?

Skills that share tags, products or a category with Analyze Perfetto Trace: React Native Best Practices (vercel-labs/openreview, 1.7k stars), Swiftui Pro (twostraws/SwiftUI-Agent-Skill, 5.6k stars), Kortix Brand (kortix-ai/suna, 20k stars) and Ip As Logo (KartikLabhshetwar/better-shot, 2.4k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Analyze Perfetto Trace?

ZacSweers (a GitHub user) maintains it in ZacSweers/metro, which has 1,408 GitHub stars. The repository holds 4 skills in this directory. The repository was last updated on October 11, 2026.

Source: ZacSweers/metro on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.