Performance

Performance Profiler Guide

Turn a profiler's raw output into a ranked list of what's actually worth optimizing -- self time vs. cumulative time, and whether the hot path is even on the critical path a user feels.

When to use this

  • A profiler (CPU, wall-clock, flame graph) has run and the raw output needs interpreting.
  • "It's slow" needs turning into a specific, measured bottleneck before anyone writes an optimization.
  • Not a replacement for actually running a profiler -- this skill interprets its output; guessing at hot paths without measuring is how time gets wasted on the wrong fix.

The skill file

Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.

SKILL.md
---
name: performance-profiler-guide
description: Interpret profiler output (CPU/wall-clock profile, flame graph) to identify the specific functions worth optimizing, distinguishing self time from cumulative time and checking whether the hot path is actually on the user-facing critical path. Use after a profile has been captured.
---

# Performance Profiler Guide

Never optimize from a guess. If no profile exists yet, the first
recommendation is "profile it," not a speculative fix.

## Reading the profile correctly

- **Self time vs. cumulative time**: a function with high cumulative time
  but low self time is slow because of what it calls, not itself --
  optimize its callees. A function with high self time is where the actual
  work is happening.
- **Call count**: a cheap function called a huge number of times can
  outweigh an expensive function called once. Multiply per-call cost by
  call count before ranking.
- **Wall-clock vs. CPU time**: if wall-clock time is much higher than CPU
  time, the bottleneck is likely I/O/waiting (network, disk, lock
  contention), not computation -- a CPU profiler alone will mislead you
  here.

## Is it even worth fixing?

Before recommending an optimization, check: is this hot path on the
critical path a user actually experiences (e.g. request latency), or is
it a background job where a few extra seconds don't matter? Optimizing
the wrong thing is worse than not optimizing.

## Output

Ranked list of the top few actual bottlenecks (not a full profile dump),
each with self/cumulative time, call count, whether it's user-facing, and
a concrete optimization direction (not yet the implementation -- confirm
priority first).

Installing it elsewhere

The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:

Claude Code
.claude/skills/performance-profiler-guide/SKILL.md

Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /performance-profiler-guide.

Cursor
.cursor/rules/performance-profiler-guide.mdc

Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.

Codex CLI / Copilot
AGENTS.md

Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.

Windsurf
.windsurfrules

Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.

Where this goes wrong
  • Optimizing the function with the biggest bar in the flame graph without checking self time vs. cumulative time -- you might be optimizing a leaf that isn't actually slow.
  • Chasing CPU optimizations on a workload that's actually I/O-bound.
  • Optimizing a hot path that isn't on any user-facing critical path.