perf: 5.9x speedup in procstat post-processing via metric caching - #36
Conversation
k-rister
left a comment
There was a problem hiding this comment.
Logic looks correct across all three optimizations:
-
cpu_topo_cache —
get_cpu_topology()is a pure dict lookup that returns the same result for a given cpu_id, so memoizing it is safe and eliminates millions of redundant calls at scale. -
metric_idx_cache + log_sample_by_idx — caching the idx from the first
log_sample()call and usinglog_sample_by_idx()on subsequent calls skips label construction and dict lookup on the hot path. The cache key(irq, cpu)is correct sincedescand the non-irq/cpunamesfields are constant withinprocess_interrupts. -
Skip zero-value cold-path — the
elif ints_sec != 0guard is the subtlest change but is correct: a metric whose first-ever sample is zero would always be purged byfinish_samples(value==0 and no written samples → purge), so skipping registration avoids wasted work with identical output. The transition cases are handled correctly:- First zero, later non-zero: cache_key not in
metric_idx_cache, falls through toelif ints_sec != 0, registers on first non-zero sample ✓ - First non-zero, later zero: cache_key IS in cache,
log_sample_by_idxcalled with value 0, metric correctly recorded ✓
- First zero, later non-zero: cache_key not in
Note: This PR depends on toolbox PR #126, which needs a rebase before it can merge — see my review there.
Three optimizations that together give a ~6x wall-clock speedup on a representative procstat dataset (246s -> 42s): 1. cpu_topo_cache: memoize get_cpu_topology() per cpu_id. Topology is fixed for the lifetime of the process; previously looked up on every sample for every (irq, cpu) pair. 2. metric_idx_cache + log_sample_by_idx: on second and subsequent samples for a known (irq, cpu), skip label computation and metric_idx lookup entirely by caching the CDMMetrics idx returned by the first log_sample() call. Uses the new log_sample_by_idx() fast path added to CDMMetrics. Reduces warm-path log_sample work by ~800x on a 256-CPU system. 3. Skip zero-value cold-path registrations: if ints_sec is zero on the first occurrence of an (irq, cpu) pair, do not register the metric. A metric with zero as its first (and only) value is always purged by finish_samples anyway; registering it just to purge it wastes ~99.9% of the work on a typical system where most IRQ/CPU combinations are idle. Metrics that become active after being zero are registered on their first non-zero sample, so transitions are still correctly captured. Validated: non-zero metric values and the full set of non-purged metric types are identical between original and optimized output. The only difference is omission of leading zero-value segments before an IRQ's first active period, which were always purged. Depends on toolbox log_sample_by_idx() change.
7c30210 to
9d155e4
Compare
Summary
Three targeted optimizations that together deliver a 5.9x wall-clock speedup (246s → 42s) for
procstat-post-process.pyon a representative 256-CPU dataset, validated with identical output.cpu_topo_cache: memoizeget_cpu_topology()per cpu_id. CPU topology is fixed for the lifetime of the process; it was previously looked up on every sample for every (irq, cpu) pair (~14M redundant calls on a 256-CPU system).metric_idx_cache+log_sample_by_idx: on second and subsequent samples for a known (irq, cpu) pair, skip label computation andmetric_idxlookup entirely by caching theCDMMetricsidx from the firstlog_sample()call. Uses the newlog_sample_by_idx()fast path in the companion toolbox PR. Reduces warm-path work by ~800x.Skip zero-value cold-path registrations: if
ints_secis zero on the first occurrence of an (irq, cpu) pair, do not register the metric. A metric whose first (and only) value is zero is always purged byfinish_samples— registering it wastes ~99.9% of the work on a typical system where most IRQ/CPU combinations are idle. Metrics that become active after initially being zero are registered on their first non-zero sample, so active → zero → active transitions are still correctly captured.Validation
Output was diff-validated against the original code on a 1/16th-size dataset:
Merge order
Merge the toolbox PR first: perftool-incubator/toolbox#126 — this PR depends on
CDMMetrics.log_sample_by_idx()andlog_sample()returning the metric idx.Test plan
procstat-post-process.pyon a dataset from a many-core host and verify output matches original🤖 Generated with Claude Code