Strong dependencies:
clarifying-question-discipline(hard active-questioning discipline) andknown-issue-research(known performance-pattern quick search, §2.1). If either is missing, abort and print the install command (npx skills add FuDesign2008/open-skills -g --skill '*' --yes).
Scope
This workflow is responsible for finding the root cause of a performance bottleneck: who triggered what expensive operation, and under what conditions. Once the root cause is confirmed, it can be used to design a fix, implement code/config optimizations, and verify the result. How to release, roll out, or ship the fix is out of scope — that is decided by the project itself.
Trigger Recognition
All triggers start with 「性能」 (performance), which makes them easy to recognize and remember. Saying a trigger word alone, or using the 「trigger + colon + space + description」 form, enters this workflow or the corresponding stage. When a colon is used, both the colon and the space are language-agnostic (Chinese or English punctuation both work).
- 「性能分析」 or 「性能分析: xxx」 → enter this workflow, starting at Stage 1 (Gather Evidence)
- 「性能证据」 or 「性能证据: xxx」 → Stage 1: Gather Evidence
- 「性能定位」 or 「性能定位: xxx」 → Stage 2: Locate the Bottleneck
- 「性能假设」 or 「性能假设: xxx」 → Stage 3: Hypothesize the Root Cause
- 「性能监控」 or 「性能监控: xxx」 → Stage 4: Build Monitoring
- 「性能优化」 or 「性能优化: xxx」 → Stage 5: Implement Optimization
- 「性能验证」 or 「性能验证: xxx」 → Stage 6: Verify
- 「性能深入」 or 「性能深入: xxx」 → continue or deepen the analysis within Stage 2 (Locate the Bottleneck)
When the user says「性能问题」("performance issue"),「卡顿」("stutter/jank"),「很慢」("it's slow"), etc., this may also be treated as entering the workflow, starting at Stage 1 (Gather Evidence). When the user provides performance-related logs or a profile and wants it analyzed, treat this as entering the workflow, starting at Stage 1 (Gather Evidence) or Stage 2 (Locate the Bottleneck).
General Principles
「First define the problem and break down the pipeline, then collect data and filter for bottlenecks, drill down to derive hypotheses, control variables to verify root causes, and optimize and solidify into a closed loop.」 (Pin down the problem and break down the chain first; then gather data to filter bottlenecks; drill down to derive a hypothesis; control variables to verify the root cause; and consolidate the optimization into a closed loop.)
- Data-driven: get the data before drawing a conclusion — never hypothesize a problem first and then hunt for supporting evidence. When there is no reproduction path or analyzable data, help the user collect it first (repro steps, logs, profiles, screen recordings, etc.).
- Top-down: start from the full chain as perceived by the user, macro before micro. First identify where it's slow (time spent / blocking / render volume, etc.), then trace back to who triggered it and under what conditions.
- Single variable, reproducible: a root-cause hypothesis must be resolvable to a yes/no verdict using existing data or a small amount of targeted instrumentation. When verifying, change only one variable at a time; the result must be reproducible and falsifiable — never treat correlation as causation.
- Full-chain coverage: analyze the complete execution chain from the problem's start to its end, not just local data — avoid the blind-men-and-the-elephant trap.
- Toggleable, production-grade monitoring: performance observability should be designed as a proper, production-grade monitoring capability that lives permanently in the codebase, gated by a toggle (environment variable, config item, feature flag, etc.). When off, it emits nothing and samples nothing, with no impact on the live product; when analysis is needed, flip the toggle to collect data — no need to bolt on temporary instrumentation and rip it out later.
- No premature optimization: only optimize performance problems that are backed by data, affect user experience, and exceed a threshold. Do not perform preventive optimization for "performance issues that might happen someday" without measurement data behind them — it only adds unnecessary code complexity and maintenance cost.
- ⚠️ Ask proactively: follow
clarifying-question-discipline(one question per turn; multi-round until clear; clarify first, don't rush to answer; strong dependency — abort if missing). - 🚩 Red Flag: dumping multiple questions/open points on the user to answer one by one at once (violates the hard discipline) — ask only the single most critical question each time, and ask the next only after getting an answer.
Stage Flow
Forward flow: evidence → locate → hypothesize → monitor → optimize → verify.
Common jumps:
- Stage 1 finds data is missing and monitoring needs to be built → go directly to Stage 4 (Build Monitoring) to add it, then return to Stage 2.
- Stage 2 has enough data and the bottleneck is clear → skip Stage 3 and go directly to Stage 4 or 5.
- Stage 6 refutes the hypothesis → go back to Stage 2 or 3 to re-analyze.
- Stage 6 shows the optimization fell short → go back to Stage 3 to re-hypothesize, or Stage 5 to adjust the optimization.
- An intermittent issue is hard to capture data for in Stage 1 → prioritize Stage 4 to build long-term monitoring, then return to Stage 2 once it reproduces.
Stage 1: Gather Evidence (性能证据)
Goal
Obtain reproducible, analyzable performance data instead of just guessing from a description — and turn a vague "it's laggy/slow" into a quantified metric and performance baseline, with a clear optimization target and a hard red line.
Information to Clarify
- Symptom: which action triggers the slowdown (click, scroll, typing, drag, an API request, etc.)? What does "slow" look like (jank, blank screen, spinner, unresponsive)? Quantify wherever possible (e.g. a given endpoint's P99 in ms, an action's frame rate/latency), and pin down the analysis boundary (the problem's start and end point, to avoid unbounded scope).
- Data available: are there existing logs, a Performance/CPU profile, a network capture, or custom instrumentation? If not, first determine "in what environment, with what method" data can be captured.
- Reproduction conditions: always reproducible or intermittent? Are there requirements on data volume/concurrency/device?
Common Data Sources (pick by scenario)
| Scenario | Candidate data sources |
|---|---|
| Frontend jank / main-thread blocking | Console logs, Chrome Performance recording, Long Task / custom performance monitoring |
| Excessive rendering / expensive repaint | Framework render stats, React DevTools Profiler, custom commit/render instrumentation |
| Slow API / backend | Network panel, server-side logs, APM, traces |
| Memory / leak | Heap snapshot, memory trend graph |
Not tied to any specific tech stack — choose based on whatever monitoring and tools the project actually has.
Output
- State clearly what data is already available and what is still missing.
- If data is missing: specify the action the user needs to take and what needs to be captured (e.g. repro steps, flip a given toggle, reproduce, and export console/profile output).
- Recommended output includes: the symptom (with quantified metrics), reproduction conditions, analysis boundary, current performance baseline, and target threshold or red line; this can be organized into a structured "performance problem definition sheet" for later comparison.
Stage 2: Locate the Bottleneck (性能定位)
Goal
Find the anomalies in the raw data (who spent how much time/resources, and when), and trace the trigger chain (event / call stack / data flow); build a full-chain topology from start to end, and use two data dimensions (time + resources) to do an initial bottleneck screen, narrowing the analysis scope to 1-2 core segments.
Analysis Approach (general)
- Full-chain topology: break down every segment from the user action to the end of the problem, in execution order (code execution, system calls, network/storage, etc.), forming a topology with no gaps and no overlap; each segment should be independently timeable with clear inputs/outputs.
- Two-dimensional capture: time dimension (time spent per segment, share of the total chain) + resource dimension (CPU/memory/IO/network, etc.) — neither can be skipped.
- Initial bottleneck screen: rank segments by time-share to pin down the high-cost ones (e.g. share >20%); pin down abnormal segments by resource anomaly (saturation, sustained rise, error rate); rule out segments that are both low-cost and resource-normal. Resource utilization >70% is a common alert line — beyond this threshold, response time tends to rise non-linearly, so it deserves priority investigation even when the absolute value looks modest.
-
Find the anomaly In the timeline or aggregated stats, find metrics that stand out, e.g.:
- a single task/request whose time exceeds a threshold (e.g. a main-thread task >50ms, >200ms);
- an abnormally large single-operation volume (e.g. one update touching a huge number of nodes, one request returning a huge payload);
- an abnormally high frequency (e.g. an event firing far more often than expected).
-
Locate it For each anomaly, determine:
- which layer it occurs in (frontend/backend/network/storage);
- the corresponding code or module (file, function, component, endpoint);
- the call stack or event chain (from the user action or entry point to that time/resource sink).
-
Build the causal chain Chain it together as "user action → event/request → handler function → expensive operation → observed metric", so you don't end up seeing only the symptom without the trigger condition.
Working Method
- For text logs: filter with search (grep/ripgrep, etc.) by keyword, duration, error code, etc., then read the relevant snippets and call stacks.
- For profiles: first look at the "wide bars" or "high-share" areas on the timeline or flame graph, then drill down to the specific function/component.
- For code: read the code and search call relationships, cross-referencing stack info from the logs, to work out "who called whom under what condition".
Output
- Anomaly summary: what's slow / high-volume / high-frequency, and its approximate location.
- Causal chain: describe "action → ... → bottleneck" in a sentence or two, or a simple diagram.
- Hypotheses to verify (preliminary direction): list 1-3 "possible root cause" directions, and for each, state what evidence would confirm or refute it. Refinement and categorization happen in Stage 3 (Hypothesize the Root Cause).
- Core bottleneck segment list: 1-2 segments, with time-share or resource-anomaly summary attached.
Known Performance-Pattern Quick Search (optional, use when locating stalls)
When known-issue-research §2.1's trigger conditions are met, load that skill and follow §2.1 (Performance-pattern variant). This workflow's own pattern table and stage orchestration stay in this file.
Stage 3: Hypothesize the Root Cause (性能假设)
Goal
Distill the anomalies and trigger chain into a verifiable root-cause hypothesis, and classify it against common performance-problem patterns to guide later instrumentation and fixes. Hypotheses must be verifiable and falsifiable — no vague guessing; industry methods can help classify them (see below).
Root-Cause Reasoning References
- USE method (resource-type bottlenecks): judge resource saturation (CPU/memory/IO/network) along three dimensions — utilization, saturation, errors.
- RED method (execution/request-type bottlenecks): judge execution-logic or call-chain problems along three dimensions — rate, errors, duration.
Use these alongside the "Common Patterns" table below; the specific steps aren't expanded further here.
Common Patterns (tech-agnostic description)
| Pattern | Characteristic | Typical trigger |
|---|---|---|
| Response scope too broad | An update that should be local instead triggers a global or large-scale recompute/re-render | A coarse-grained event (e.g. "any change") drives a broad update; missing fine-grained subscription or diffing |
| Updates not batched/coalesced | One operation causes multiple independent recomputes or re-renders | Multiple consecutive state updates aren't batched; async callbacks each trigger their own update |
| High-frequency triggering | A high-frequency event runs expensive logic every time | scroll/resize/mousemove etc. not throttled/debounced; heavy recompute on every frame or every event |
| Backlog fires all at once | When the main thread is busy or a queue backs up, many delayed tasks fire together | Multiple throttle/debounce timers fire at the same instant; timers/microtasks pile up |
| Resource leak | Memory/connections/handles keep growing and are never released | Unclosed connections, uncleared caches/timers, unremoved listeners |
| Synchronous blocking | The main thread or a critical path is held by a synchronous operation for a long time | Synchronous I/O, lock contention, long transactions, heavy synchronous computation |
| Repeated/redundant computation | The same result is recomputed repeatedly without caching | Missing memoization/caching, N+1 queries, repeated serialize/deserialize |
In a specific project this might show up as "some framework's setState", "some event bus's emit", "some RPC call", etc. — but at the abstract level they all fall into the categories above.
Output
- The 1-2 most likely root-cause hypotheses right now; each hypothesis must be verifiable and falsifiable (e.g. resolvable via "is it a full table scan?" or "what value does this variable have?" into a yes/no verdict) — avoid unverifiable statements like "the query is slow because the SQL is poorly written".
- If there are multiple hypotheses, rank them by "highest user-perceived impact + lowest verification cost", and verify the top-ranked one first.
- The verification method for each hypothesis: can existing logs answer it? If not, which points on which path need toggleable monitoring added (see Stage 4: Build Monitoring)? Once the root cause is confirmed, proceed to Stage 5 (Implement Optimization) to make the change, then verify the hypothesis and the optimization's effect in Stage 6 (Verify).
Stage 4: Build Monitoring (性能监控)
Goal
When existing data can't verify the hypothesis, add toggleable, production-grade performance observability on the critical path. The monitoring logic ships as real code and is gated by a toggle; when off it has no effect on the live product, and flipping it on enables performance monitoring for analysis.
When Additional Monitoring Is Needed
- Existing logs/profiles don't show "who triggered it", "under what condition it was triggered", or "what a given variable's value was at the time".
- You need to compare behavior between "hypothesis true" and "hypothesis false" cases (e.g. behavior when some flag is true vs. false).
- The project doesn't yet have toggleable performance monitoring for this path, and it needs to be designed and shipped.
Monitoring Design Principles (general)
-
Toggle-controlled Use a runtime toggle (environment variable, config center, feature flag, local debug switch, etc.) to control whether it's enabled. Default off in production, or enabled only for specific users/sessions; turn it on when investigating an issue, to avoid overhead or noise for normal users.
-
Permanent, not temporary The monitoring code is a permanent capability, not "add it to verify, then delete it". The logic stays long-term, and behavior is entirely controlled by the toggle: off means no output, no sampling, no extra overhead (or only a negligible one); on means it emits output or reports in an agreed format, aligned with existing logs/profiles.
-
Alignable Emit stable timestamps (e.g.
performance.now()or server-side nanosecond time) and location identifiers, so output can be aligned with existing logs/profiles on the same timeline for causal and sequence analysis. -
Just enough information Each record should include at least: a location identifier, a timestamp, and the small number of key variables needed to confirm or refute the hypothesis (e.g. which branch was hit, an ID, a count, an error code). Reuse the project's existing performance-log format where possible, to keep analysis consistent.
Choosing Monitoring Points
- Priority: the suspected direct trigger point (e.g. the call that updates state, the call that fires the request, the entry point of the function doing the recompute).
- Next: intermediate nodes on the trigger chain (e.g. an event-handler entry point, a callback entry point), to confirm call order and frequency.
- Then: the entry/exit of the expensive computation, to confirm per-call duration and call count.
Output
- A list of monitoring points (file:line or function/endpoint name), each with its purpose and a suggested toggle name.
- The action the user needs to take: how to enable the toggle, how to reproduce, and how to capture and provide the new logs/profile.
- If the root cause is already confirmed, or will be verified in Stage 6, proceed to Stage 5 (Implement Optimization) to make the change.
Stage 5: Implement Optimization (性能优化)
Goal
Based on Stage 3's root-cause conclusion (and Stage 4's monitoring; if the hypothesis was already verified in Stage 6, that can also inform this), implement a code- or config-level optimization that eliminates or mitigates the bottleneck. This stage only produces "changes targeting the root cause" and a change list — a multi-option evaluation or detailed task breakdown is out of scope here.
Principles
- Fix the root cause, not the symptom: the change should map to the root-cause pattern identified in Stage 3 (e.g. narrow the response scope, batch updates, throttle/debounce), not a generic optimization.
- Use monitoring for comparison: prefer using Stage 4's toggleable monitoring to compare before/after under the same repro scenario in Stage 6, confirming the change actually worked.
- Control-variable verification: verify the root cause with a single-variable experiment before changing anything; each optimization should touch only one root-cause point at a time, so Stage 6 can attribute the benefit to a single change.
- Layering and cost-effectiveness: consider layers from high to low — business logic → application code → framework/dependency → system/hardware — preferring the upper layers; prefer solutions with "low change cost, high payoff" (e.g. simplifying logic, reusing a cache).
- Prioritize by time-share: optimize the segments with the highest time-share first; a segment with <10% time-share isn't worth optimizing even a 100x improvement in it barely moves the overall number, so skip it and focus on the real primary bottleneck.
- Stability: don't change business semantics, don't introduce functional bugs, and don't introduce new performance side effects.
Output
- Change list: file, location (function/module), summary of the change.
- Suggested verification method: which repro scenario to use and which metrics to watch (aligned with Stage 4's monitoring), so Stage 6 can verify the optimization's effect.
Stage 6: Verify (性能验证)
Goal
- Use new data to render a yes/no verdict on the hypothesis from Stage 3 (Hypothesize the Root Cause), revising the hypothesis or returning to Stage 2 (Locate the Bottleneck) if needed.
- If Stage 5 (Implement Optimization) has been completed, use the same repro scenario and Stage 4's monitoring data to do a before/after comparison, confirming whether the optimization worked and whether the metrics hit the target.
Verification Method
- For each hypothesis, state clearly "what the logs/profile should show if it's true" and "what they should show if it's false".
- Search the new logs for the corresponding pattern and check whether it matches the "true" expectation.
- If timestamps are available, align instrumentation points from different modules/layers onto the same timeline to confirm order and whether they occurred within the same task/request.
- After the optimization, compare key metrics (duration, call count, render volume, etc.) before and after under the same repro path, and state the pass criteria.
- Effectiveness verification (when Stage 5 has been completed):
- Baseline re-test: compare full-dimension metrics under the same repro conditions and environment as before the optimization.
- Functional regression: confirm normal, edge-case, and peak-load scenarios still work correctly.
- Side-effect check: confirm no secondary performance issues were introduced (e.g. optimizing response time with a cache but causing memory to rise).
- If feasible: do a production/canary rollout verification with real traffic to confirm the effect.
Output
- The verdict for each hypothesis: confirmed / refuted / still uncertain.
- If still uncertain: state what information is still missing, and whether the next step is adding toggleable monitoring to gather more data, or re-analyzing from a different angle.
- If confirmed: summarize the root cause in a sentence or two (who, under what condition, triggered what), as input for designing and implementing the fix.
- If Stage 5 (Implement Optimization) was completed: report the before/after comparison and whether the target was met.
- Close the loop (optional follow-up): once verification passes, consider folding the key metrics into standing monitoring and alerting; if there's CI/CD, consider adding a performance baseline or gate to the pipeline to prevent regression; and feed the metrics and best practices from this optimization into team conventions for continuous improvement.
- Stop condition: once every hypothesis has been verified and key metrics hit the target — or the cost-effectiveness of optimizing the remaining bottleneck is too low (change cost far exceeds the payoff) — this round of optimization can conclude.
Output Detail Level (adaptive)
- Simple problem, ample data: can be condensed to "anomaly + causal chain + root-cause conclusion".
- Complex problem, many modules: give a brief output per stage (what was collected, main anomalies, hypotheses, monitoring-point list, optimization highlights, verification conclusion and effectiveness conclusion), attaching key log snippets or call-stack excerpts where necessary.
- When a specific tech stack is involved, fold it in conversationally for that session — don't hardcode specific tags or commands into this SKILL file.