perf-profile
Skill0 starsChanged 33 days agoMITView on GitHub
Profile, diagnose, and fix performance bottlenecks using the right tools for the stack. Use when the user says something is slow, asks why an endpoint is taking too long, wants to reduce memory usage, needs to find what is hogging CPU, says a query is slow, asks to profile the app, or wants to improve response time. Never guesses — always measures before changing code.
- Installs packages
19 other projects use a version of this.
Adopted by
Most recently taken up by
- striderZA/OpenCodeGameStudiostheir own version, first seen Nov 4, 2026
- Donchitos/Claude-Code-Game-Studiostheir own version, first seen Oct 19, 2026
- venus2099/codex-game-studiostheir own version, first seen Oct 17, 2026
- Swih/godot-foundrytheir own version, first seen Oct 11, 2026
- scotidev/GameDevStudiotheir own version, first seen Oct 9, 2026
- facontidavide/PlotJugglertheir own version, first seen Oct 8, 2026
Used with
Projects with it also use soak-test, team-live-ops and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
lilangMaxSkillsoak-test
Generate a soak test protocol for extended play sessions. Defines what to observe, measure, and log during long play sessions to surface slow leaks, fatigue effects, and edge cases that only appear after sustained play. Primarily used in Polish and Release phases.
Also in 9 projects that use this
lilangMaxSkillteam-live-ops
Orchestrate the live-ops team for post-launch content planning: coordinates live-ops-designer, economy-designer, analytics-engineer, community-manager, writer, and narrative-director to design and plan a season, event, or live content update.
Also in 9 projects that use this
- +10 more from lilangMax
Other versions19 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 19
- Donchitos/Claude-Code-Game-Studios★ 27ksame name
- facontidavide/PlotJuggler★ 6.3ksame name
- pixel-cellar/Claude-Code-Game-Studios★ 324same name
- striderZA/OpenCodeGameStudios★ 118same name
- tranhieutt/software_development_department★ 71same name
- cenconq25/claude-code-app-studio★ 40same name
- CoralGame/Claude-Code-Game-Studios★ 19same name
- dawn840705/codex-code-studios★ 17same name
- ariadoss/superskills★ 12same name
- CodePhobiia/claude-roblox-game-studio★ 9same name
9 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository68 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- accessibilitySkill
- api-designSkill
- api-versioningSkill
- authSkill
- background-jobsSkill
- cachingSkill
- capacity-planningSkill
- changelogSkill
- chaos-engineeringSkill
- ci-cdSkill
- circuit-breakerSkill
- claude-best-practicesSkill
- code-commentsSkill
- code-hygieneSkill
- code-reviewSkill
- code-structureSkill
- commit-styleSkill
- concurrency-and-lockingSkill
- database-transactionsSkill
- data-consistencySkill
- debug-infra-startupSkill
- debug-sessionSkill
- demo-video-creatorSkill
- demo-video-script-creatorSkill
- dependency-injectionSkill
- dependency-updateSkill
- disk-cleanupSkill
- distributed-tracingSkill
- dockerSkill
- env-configSkill
- env-setupSkill
- error-handlingSkill
- event-driven-architectureSkill
- feature-flagsSkill
- file-storageSkill
- graceful-shutdownSkill
- idempotencySkill
- input-validationSkill
- jars-engineering-blogsmithSkill
- jars-workshop-builderSkill
- licensingSkill
- loggingSkill
- memory-and-allocationsSkill
- migrate-dbSkill
- monitoringSkill
- multi-tenancySkill
- notificationsSkill
- openapiSkill
- paginationSkill
- pr-descriptionSkill
- query-optimizationSkill
- rate-limitingSkill
- refactorSkill
- releaseSkill
- runbook-writerSkill
- searchSkill
- secrets-auditSkill
- simplifySkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
7 rules. 0 are common, 7 are distinctive, and 0 are very specific to this project.
0
Common
Most of the 18 edited versions we read keep these.
7
Distinctive
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 23
Stop when the bottleneck is gone: Don't keep micro-optimizing once the problem is fixed.
- Distinctive: line 29
Before touching a profiler:
- Distinctive: line 34
When did it regress?: Check recent commits if it used to be fast:
- Distinctive: line 245
Read the code around the slow function.
- Distinctive: line 281
Only add a cache after confirming the operation is actually slow and called repeatedly.
- Distinctive: line 330
After applying a change, re-run the same measurement you started with.
- Distinctive: line 364
Do not keep going once the target is met.
“Common” is measured: kept by at least 6 in 10 of the 18 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Performance profiling
Find what is actually slow, fix only that thing, and verify the fix made a real difference. Guessing about performance is how you spend a week optimizing the wrong function. Measure first.
Ground rules
- Measure before changing anything. Form a hypothesis, collect data, then fix. Never optimise code based on intuition alone.
- Read the code in the hot path before profiling. You need enough context to interpret what the profiler is telling you.
- One change at a time. Apply one fix, re-profile, compare. Multiple simultaneous changes make it impossible to know which one helped (or hurt).
- Establish a baseline. Record the before metric (latency, throughput, memory, query time) so you can prove the fix worked.
- Never regress correctness for speed. A wrong answer returned in 1 ms is worse than a correct one returned in 100 ms.
- Stop when the bottleneck is gone. Don't keep micro-optimizing once the problem is fixed.
Step 0: Define the problem
Before touching a profiler:
- What is slow? Endpoint? Build step? batch job? CLI command?
- What is the observed metric? p50/p95/p99 latency? Requests per second? Peak memory? CPU %?
- What is acceptable? Know the target before you start. "Fast enough" is a number.
- When did it regress? Check recent commits if it used to be fast:
git log --oneline -20 git bisect start # if the culprit isn't obvious
Profiling by stack
Node.js / TypeScript
CPU profiling — find where time goes
# Built-in V8 profiler (no deps)
node --prof server.js
# run your workload (curl the slow endpoint a few times)
node --prof-process isolate-*.log > profile.txt
# open profile.txt — look for the top entries in [Summary] and [Bottom up]
# Or use clinic.js for a visual flame graph
npx clinic flame -- node server.js
# (serve workload while it runs, then open the generated HTML)
# For a quick scripted function
node --inspect-brk script.js
# Open chrome://inspect → "Open dedicated DevTools for Node" → Profiler tabMemory profiling — find leaks and over-allocation
# Heap snapshot via DevTools
node --inspect server.js
# In Chrome DevTools → Memory → Take snapshot → run workload → take another → compare
# Or automate with heapdump
node -e "
const heapdump = require('heapdump');
// run workload
heapdump.writeSnapshot('./heap-before.heapsnapshot');
"In-process timing (no profiler needed for a specific function)
const start = performance.now();
await doTheThing();
console.log(`doTheThing: ${(performance.now() - start).toFixed(2)}ms`);Python
CPU profiling
# cProfile — built-in, good first pass
python -m cProfile -o profile.out -s cumulative your_script.py
python -c "import pstats; pstats.Stats('profile.out').strip_dirs().sort_stats('cumulative').print_stats(20)"
# py-spy — low-overhead profiler, attaches to a running process, no code changes
pip install py-spy
py-spy record -o profile.svg --pid <pid> # flame graph as SVG
py-spy top --pid <pid> # live top-like view
# For web apps (FastAPI / Flask / Django)
pip install pyinstrument
# Wrap the request handler or add middleware:
# FastAPI: add PyinstrumentProfilerMiddleware
# Django: PYINSTRUMENT_PROFILE_DIR = '/tmp/profiles'Memory profiling
pip install memory-profiler
# Decorate the function:
# from memory_profiler import profile
# @profile
# def my_function(): ...
python -m memory_profiler your_script.py
# For live heap inspection
pip install memray
memray run -o output.bin your_script.py
memray flamegraph output.bin # opens a flame graph in the browserQuick in-process timing
import time
start = time.perf_counter()
do_the_thing()
print(f"do_the_thing: {(time.perf_counter() - start) * 1000:.2f}ms")Go
# pprof — built-in, industry standard
# 1. Import net/http/pprof in your main (or use runtime/pprof directly)
import _ "net/http/pprof"
# 2. Run the server and collect a 30-second CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# 3. Inside pprof interactive shell:
(pprof) top 20 # top functions by cumulative time
(pprof) web # open flame graph in browser (requires graphviz)
(pprof) list MyFunc # annotate source with per-line costs
# Heap / memory
go tool pprof http://localhost:6060/debug/pprof/heap
# For a script (not a server):
import "runtime/pprof"
f, _ := os.Create("cpu.prof")
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()Java / JVM
# JFR — low-overhead, built into the JDK (Java 11+)
java -XX:StartFlightRecording=duration=60s,filename=recording.jfr -jar app.jar
# Open recording.jfr in JDK Mission Control (jmc)
# async-profiler — flame graphs, attaches to running JVM
./asprof -d 30 -f profile.html <pid> # HTML flame graph
# Quick timing
long start = System.nanoTime();
doTheThing();
System.out.printf("doTheThing: %.2fms%n", (System.nanoTime() - start) / 1e6);Database queries
Slow queries are one of the most common performance killers. Always check here before profiling application code.
Find slow queries
-- PostgreSQL: queries taking > 100ms
SELECT query, calls, mean_exec_time, total_exec_time
FROM pg_stat_statements
WHERE mean_exec_time > 100
ORDER BY mean_exec_time DESC
LIMIT 20;
-- MySQL: slow query log
SHOW VARIABLES LIKE 'slow_query_log';
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 0.1; -- log queries > 100ms
-- SQLite: use EXPLAIN QUERY PLAN
EXPLAIN QUERY PLAN SELECT ...;Read the query plan
-- PostgreSQL
EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
-- Look for: Seq Scan on large tables, nested loop joins, high actual rows vs estimated rows
-- MySQL
EXPLAIN FORMAT=JSON SELECT ...;
-- Look for:
-- "Seq Scan" instead of "Index Scan" → probably missing index
-- Estimated rows wildly different from actual → stale statistics
-- Nested loop on large tables → consider a hash join or indexCommon query fixes
| Symptom | Fix |
Seq Scan on a large table with a WHERE clause | Add an index on the filtered column |
N+1 queries (1 query per row) | Fetch related data in one query or use eager loading |
SELECT * when only 2 columns are needed | List columns explicitly; composite index can cover the query |
| Stale statistics | ANALYZE table_name (Postgres) / ANALYZE TABLE t (MySQL) |
Large OFFSET pagination | Cursor-based pagination (keyset) instead of OFFSET |
Missing index on a JOIN column | Index the foreign key column |
Fix an N+1
# Bad — 1 query for users + N queries for their orders
users = db.query(User).all()
for user in users:
print(user.orders) # lazy-loads each user's orders
# Good — 2 queries total (or 1 with a JOIN)
users = db.query(User).options(joinedload(User.orders)).all()Common application-level patterns
Unnecessary work in the hot path
Read the code around the slow function. Ask:
- Is it reading a file or config on every request that could be loaded once at startup?
- Is it re-computing something that could be cached?
- Is it doing sequential I/O that could be parallel?
// Bad — reads config file on every request
app.get("/api/data", async (req, res) => {
const config = JSON.parse(fs.readFileSync("./config.json")); // every request!
...
});
// Good — load once at startup
const config = JSON.parse(fs.readFileSync("./config.json"));
app.get("/api/data", async (req, res) => { ... });Sequential I/O vs parallel I/O
// Bad — two independent fetches in series (~400ms)
const user = await fetchUser(id);
const orders = await fetchOrders(id);
// Good — run in parallel (~200ms)
const [user, orders] = await Promise.all([fetchUser(id), fetchOrders(id)]);# Python equivalent with asyncio
user, orders = await asyncio.gather(fetch_user(id), fetch_orders(id))Adding a cache
Only add a cache after confirming the operation is actually slow and called repeatedly.
// Simple in-memory cache with TTL (good for single-instance apps)
const cache = new Map<string, { value: unknown; expiresAt: number }>();
function getFromCache<T>(key: string): T | null {
const entry = cache.get(key);
if (!entry || Date.now() > entry.expiresAt) return null;
return entry.value as T;
}
function setInCache(key: string, value: unknown, ttlMs: number) {
cache.set(key, { value, expiresAt: Date.now() + ttlMs });
}For distributed caches, use Redis via the app's existing client. Don't introduce a new dependency without checking what's already available.
Memory leaks (Node.js)
Common causes:
| Cause | Signal |
| Growing global/module-level arrays or Maps | Memory climbs and never falls between requests |
| Event listeners not removed | process.on, emitter.on called in a request handler |
| Closures capturing large objects | Lambda or callback holds a reference to a large scope |
| Timers not cleared | setInterval inside a function that gets called repeatedly |
// Bad — listener accumulates on every request
app.get("/start", (req, res) => {
someEmitter.on("data", handleData); // never removed!
res.send("ok");
});
// Good — use once or clean up
app.get("/start", (req, res) => {
someEmitter.once("data", handleData);
res.send("ok");
});Measuring the fix
After applying a change, re-run the same measurement you started with.
# HTTP endpoint — compare before and after with autocannon (Node) or wrk
npx autocannon -c 10 -d 10 http://localhost:3000/api/slow
# look at: Req/Sec, Latency avg/p99
# Or with curl timing
curl -o /dev/null -s -w "time_total: %{time_total}s\n" http://localhost:3000/api/slow
# Python function — use timeit
python -m timeit -n 1000 "from mymodule import my_func; my_func()"
# Go benchmark
go test -bench=BenchmarkMyFunc -benchmem -count=5 ./...Present the result as a before/after table:
| Metric | Before | After | Change |
| p50 latency | 420 ms | 38 ms | −91 % |
| p99 latency | 1 200 ms | 95 ms | −92 % |
| Memory (peak) | 512 MB | 210 MB | −59 % |
When to stop
You are done when:
- The metric meets the target defined in Step 0.
- The fix is correct (existing tests pass).
- The improvement is confirmed with a real measurement, not an assumption.
Do not keep going once the target is met. Premature optimization beyond the bottleneck wastes time and adds complexity.
Checklist
- Baseline metric recorded before any change
- Profiler output read and the actual bottleneck identified (not guessed)
- One change applied at a time
- Fix verified by re-running the same measurement
- Before/after numbers compared
- Existing tests still pass
- No correctness regression introduced
- No new dependency added without checking what's already in the project
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

