Skip to main content

ripwire-perf-target

A MEASURED performance problem: start from a benchmark, flame graph, perf sample or profiler run, locate the hot symbol the profile names, test structural hypotheses (memory-bound → cache-line data layout). Static metrics are change-risk signals, not runtime heat. Inspect only the symbols the profile names.

インストールへ移動

ソース情報

リポジトリ
redhat-et/ripwire
ソースの最終更新活動
2026年9月13日 02:43
検出された SKILL.md の言語
英語
スター
2,312
フォーク
149

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
ripwire-perf-target
description
A MEASURED performance problem: start from a benchmark, flame graph, perf sample or profiler run, locate the hot symbol the profile names, test structural hypotheses (memory-bound → cache-line data layout). Static metrics are change-risk signals, not runtime heat. Inspect only the symbols the profile names.
allowed-tools
Bash, Read
# Performance targeting with ripwire > Nearest neighbours: > • Repo-wide quality/health sweep (not perf-specific) → **ripwire-fresh-eyes** (also uses --hotspots). > • Finding a specific BUG, not a slow path → **ripwire-find-bug**. Trigger: a representative benchmark, flame graph, trace, or profiler has identified a slow operation, file, stack, or symbol and you need to understand where a safe optimization belongs. If you have no measurement yet, create the smallest representative benchmark/profile first; ripwire cannot infer runtime cost from source shape. `<dir>` = repo root. 1. **Pin the measured evidence** — record the workload, baseline, profiler/trace result, and the symbol or subsystem it implicates. Keep the same workload for the after measurement. 2. **Navigate the measured surface** — `ripwire <dir> --for="measured operation or symbol" --detail=3`, then `--callers=SYM`, `--callees=SYM`, or `--around=SYM` as needed. This turns runtime evidence into a bounded source-reading set without pretending the graph measured execution. 3. **Maintenance/change-risk context** — `ripwire <dir> --hotspots --legend=compact` Output: `<hotspots>` ranked by `score = churn × ccx` (churn = git commit frequency over 12mo; ccx = cognitive complexity). The `top=` attribute names the highest-complexity function in each file. High-score files are frequently changed and structurally complex: useful evidence about optimization risk and validation scope, but structural evidence, not runtime heat. **A slowdown/regression traced to a specific change, not an all-time read** — use the recent-churn lens: `ripwire <dir> --hotspots --legend=compact --since="2 weeks ago"` (or `--since=HEAD~20` for a deterministic rev) ranks by commits after that point instead of all-history, which is the right lens for "this got slower after X" rather than a static hot-function scan. 4. **Static dependency + shape hypotheses** — `ripwire <dir> --metrics --legend=compact --top-k=50` Output: the ranked map with `in=` (fan-in), `cx=`/`ccx=` (complexity), `cbo=` (coupling between objects — how many other types this symbol touches), `loc=` (body size), and `nest=` (max nesting depth) on each symbol. `in=` is static dependency fan-in, not execution frequency. Use `cbo`/`nest`/`loc` to form code-reading hypotheses inside the already-measured surface: coupling may constrain a rewrite, nesting may hide branchy or quadratic work, and large bodies may combine unrelated work. **Read `nest=` with its profile, never alone** — it is a max, so `humps=` (regions reaching the nesting bar) and `deep=` (lines inside them, a floor) on the same row are what separate a body that *sustains* depth from a long flat one whose max is a single inner loop; `deep/loc` is the discriminator (→ **ripwire-quality-bar**). Confirm every suspected bottleneck with the benchmark/profile. **On C-family/C# code, discount a `ppalt=`-carrying body:** `cx=`/`ccx=`/`nest=`/`loc=`/`locals=` sum ALL `#else`/`#ifdef` branches, not just the one your build compiles, so a hot function that also happens to be preprocessor-heavy can look structurally worse than the code path actually executing. 4a2. **Join the measured heat onto the static findings** — `ripwire <dir> --lint --legend=compact --with-profile=REPORT` REPORT is a RIPWIRE_PROFILE build's own stderr report (its `#PROF_TSV` block, verbatim). Every `--lint` finding whose enclosing symbol contains a `PROFILE_SCOPE` site gains `heat_*` attributes — the scope's measured calls, total_ms, and whichever counter columns that run armed (`heat_l1d_mpki` etc.; an ABSENT column was not measured, never zero). This is the one-command answer to "which of these cache-* rows are actually HOT": static shape × PMU weight (SYZYGY's advice mode, Hundt CGO 2006). `heat_joined="0"` on the root is honest — no finding sits inside a profiled scope — never an error. 4b. **If the profile points at MEMORY, not compute** — cheapest first, `ripwire <dir> --lint --legend=compact` runs the built-in **cache-\* pack** (8 static data-layout checks, e.g. `cache-gather-subscript`, `cache-vector-of-indirect`, `cache-pointer-chase-loop`) as part of an ordinary lint pass — no profile required, so it is worth a look before reaching for the heavier lens below. When a specific struct is already implicated, `--field-affinity[=STRUCT]` **When to reach for it.** The measurement already implicates a struct-heavy path and the *shape* of the evidence says data layout, not algorithm: cache-miss or memory-stall counters dominating the profile, a loop whose cost does not track its instruction count, a hot/cold field mix (a couple of fields read on every pass, a dozen touched only on cold paths), or a wide struct threaded through many callers. Bare = every aggregate in the repo ranked by separation cost; `=STRUCT` narrows to the one the profile named — prefer the narrow form, per this skill's stop rule. Output: per struct, which fields the indexed C/C++/ObjC functions access TOGETHER, diffed against the declared field order and 64-byte cache-line geometry (Chilimbi's separation weight, PLDI 1999 — cited, not invented here). Exactly two findings fire, both with a direction defensible in one sentence: `split-line` (a co-accessed pair at `wt="0.00"`, i.e. ≥64 bytes apart — **no** field order can put them on one line) and `straddle` (one co-accessed field crossing a line boundary, so every access to that ONE field touches two lines). **What it does NOT detect** — the boundary matters more than the findings, because a layout change made on the wrong evidence is expensive and hard to unwind: - **Runtime frequency.** `fns=` counts distinct indexed functions (`counts_floor="1"`) and `w=` is a static call-graph reachability proxy (`weighting="fanin-floor"`) — a struct can top the ranking and cost nothing because it is constructed once. - **False sharing.** That is the *inverse* question (which fields to SEPARATE), and this lens has no opinion on it. It is also why no packing advice is emitted: tight packing co-locates independently written fields and can *induce* false sharing, so the axis is not monotonic. - **Reordering, packing, padding.** No rewrite mode, no "sort by size", no hole report. Advice only. - **AoS vs SoA.** Not modeled at all — there is no verdict here on changing a container's shape. - **Which instance, or what a pointer points at.** No points-to analysis: an access is approximated by `<function, struct type>`. Only dot/arrow syntax counts, so a bare field name inside its own method is invisible, and a field name declared by two aggregates is REFUSED into `amb_skipped=` rather than guessed. - **True `sizeof`/alignment** under templates, virtuals, bases and your target ABI. All geometry is an LP64 model (`model="lp64-approx"`); a definition the layout model refuses (`modeled="0"`) contributes its co-access graph and **no** geometry finding. - **Pointer-chasing stalls** — with one narrow exception, in the other direction: the same verb also classifies each C-style `for` loop's advance as `index`/`chase`/`mixed`/`unknown` and can flag a declared field as the traversal's chase pointer (`chase="1" loops="N"`). It is purely syntactic, C-family only, and range-for/while/recursion always read `unknown` (`as_unknown=`), so a zero there means "not classified", never "no chases." It ships **report-only** — it does not move the ranking. **This is a HYPOTHESIS GENERATOR, not a measurement** — same rule as every static signal on this page. For runtime truth, go back to the counters: `<validate>` names the instrumented `PROFILE_SCOPE` whose hardware counters would confirm or refute the hypothesis (the PMC backend is `src/infra/profilePmc.h` — kpep on macOS, `perf_event_open` on Linux), `bench/bench_field_ab.cpp` is the A/B harness, and `docs/FIELDAFFINITY.md` records a worked example in which the static hypothesis was **refuted** under one access pattern. Confirm on hardware before changing a layout, exactly as with every other item on this list. Exit is always 0: a report, not a gate. 5. **Expand measured candidates** — `ripwire <dir> --expand=SYM --legend=compact` for the implicated symbols. Output: full body + callee signatures. Look for inner-loop allocations, redundant work, or O(N²) patterns that profiler data would confirm. 6. **Re-measure** — make one bounded change, rerun the same workload, and report latency/throughput plus any correctness/determinism gate. A structurally attractive refactor with no measured improvement is not a performance win. ## Output Measured baseline and workload; the profiler/trace evidence; the bounded symbol/caller/callee surface; structural hypotheses clearly labeled as non-runtime evidence; the change; and the same after measurement.
GitHubで見る