Skip to Content

hotspots

Rank nodes by optimization leverage — “what is worth optimizing?” — returning the top-N symbols for a chosen metric, each with its score. It is the opinionated counterpart to the raw traversal queries: where who-calls and blast-radius answer questions about one node, hotspots scores the whole graph and hands back a ranking. Takes no argument.

Source: src/commands/hotspots_command.ts · query: GraphQuery.hotspots in src/query/graph_query.ts

Synopsis

npx codespine hotspots [options]

Arguments

None. The command scans the whole graph.

Options

OptionDefaultDescription
-o, --output-folder <dir>./.codespineOutput folder; the Kùzu database is read from <dir>/graph.kuzu.
--by <metric>self-time when enriched, else callersRanking metric (see table below).
--limit <n>20Maximum number of hotspots. Clamped to the range 11000.
--measured-onlyfalseRestrict ranking to nodes that carry metadata.runtime.
--jsonfalseEmit the raw JSON report instead of the formatted table.

What it does

Reads the graph once and ranks every node by the chosen metric, descending, dropping nodes that score zero (a symbol nothing calls is not a fan-in hotspot) and returning the top --limit.

Metrics

--bySourceMeaning
self-timemetadata.runtime.selfMsWhere measured CPU time is actually spent. Default when the graph is enriched.
samplesmetadata.runtime.samplesProfiler hit count — a coarser stand-in for self time.
callersinbound CALLS edge countStatic fan-in / centrality: how many distinct sites call this symbol. Default when the graph is not enriched.
call-countsum of inbound CALLS edge metadata.countHow often the symbol is actually invoked across all call sites in source.
blast-radiustransitive inbound CALLS sizeChange-risk / centrality: how many symbols would be impacted by changing it.

The runtime metrics (self-time, samples) read the metadata.runtime written by enrich. The static metrics (callers, call-count, blast-radius) are derived from the CALLS graph and need no enrichment, but do need a --semantic extraction — on a structural-only graph there are no CALLS edges and the ranking is empty.

call-count differs from callers whenever a symbol is called many times from a few sites (a tight loop): callers counts the distinct callers, call-count sums the call-site multiplicity preserved as edge metadata.count. blast-radius differs from callers by following the call chain transitively, so a deep helper at the bottom of a long chain ranks above a leaf with the same direct fan-in.

Default and fallback

With no --by, the metric is chosen from the graph: self-time if any node carries metadata.runtime, otherwise callers. Asking for a runtime metric on an un-enriched graph does not return empty — it falls back to callers, prints a one-line notice, and sets fellBack: true in the JSON report:

! no runtime data in graph — run `enrich` first. Ranking by `callers` (static fan-in) instead.

Ties are broken by file path, then declaration line, so the order is stable across runs.

Output

Formatted (default) — a header naming the metric, then one ranked line per hotspot (rank, score, kind, name, location):

Hotspots by self-time 1. 4.625 ms Method isValueRead src/extract/semantic_extractor.ts:265 2. 3.334 ms Method forDeclaration src/extract/node_id.ts:9 3. 1.292 ms Class KuzuStore src/store/kuzu_store.ts:24 3 hotspot(s)

JSON (--json) — the full report. Each entry in hotspots is a SymbolRef plus score and metric; the envelope records the metric used, what was requested, and whether the graph is enriched / a fallback occurred:

{ "metric": "callers", "requested": "callers", "enriched": true, "fellBack": false, "measuredOnly": false, "hotspots": [ { "id": "MethodDeclaration:src/extract/node_id.ts#forDeclaration@9", "kind": "Method", "name": "forDeclaration", "filePath": "src/extract/node_id.ts", "startLine": 9, "metadata": { "runtime": { "source": "v8-cpuprofile", "samples": 4, "selfMicros": 3334, "selfMs": 3.334 } }, "score": 10, "metric": "callers" } ] }

Examples

# the default ranking — measured self time on an enriched graph, else fan-in npx codespine hotspots # the most-called symbols in source (loop-heavy call sites rise to the top) npx codespine hotspots --by call-count --limit 10 # highest change-risk symbols — what the most code transitively depends on npx codespine hotspots --by blast-radius # of the measured nodes, which has the highest static fan-in npx codespine hotspots --by callers --measured-only # machine-readable — the shape the optimization agent consumes npx codespine hotspots --by self-time --json

Notes and caveats

  • Runtime metrics need enrich. Without it the graph has no metadata.runtime; --by self-time/samples fall back to callers.
  • Static metrics need a --semantic extraction. CALLS edges only exist on a semantic graph; a structural-only graph ranks empty for callers, call-count, and blast-radius.
  • blast-radius here is unbounded, unlike the blast-radius command’s --depth cap: this metric counts the full transitive inbound set so the ranking is comparable across nodes. It is cycle-safe.
  • Static call edges only. Dynamic dispatch is invisible, so a real hotspot can rank lower than its true impact — confirm a candidate with who-calls / blast-radius before acting.
  • Re-extract before trusting it. The loader merges by id and does not remove stale nodes; for a clean reading, delete the database, re-extract, and reload — see load.

See also

  • enrich — attach the metadata.runtime the runtime metrics rank by.
  • blast-radius — the depth-bounded, single-node version of the transitive-reach metric.
  • dead-exports — the other opinionated detector: the safest edits (removable code) rather than the highest-leverage ones.
  • /codespine-interview — scopes an optimization target; consumes this ranking instead of re-deriving it by hand.
Last updated on