Struct CostSink¶
Defined in File cost_model_object.hpp
Struct Documentation¶
-
struct CostSink¶
Opt-in accumulator for the replay-tallied (recompute-aware) cost.
A static per-node cost walk reports order-/batching-blind DP-model quantities: each internal node is priced once, so such a walk never sees the per-occ-block replay recompute the batched evaluator incurs at runtime. This sink is the replay-side counterpart: when a non-null
CostSinkis attached to theCostModelshared by every dry-runResulttoken, each actual product-op execution during theTrace::Onreplay folds its own sliced-extent cost here (seeCostModel::tally_opandDryRunOps::prod). Because a sliced, occ-dependent op executed N times does ~1/N work each pass, its sliced-cost sum is work-neutral (~= its unsliced cost); only the occ-independent work re-executed at full size once per block inflates — so the totals here isolate the recompute the model walk cannot.Mirrors
sequant::eval::PeakSink(eval.hpp): an optional sink, defaulting off, so the production runtime path (which never constructs a dry-runCostModel) folds nothing. The atomics let a fold from a concurrent evaluator stay correct, though a metered replay itself is single-threaded.Per-node avoidable-recompute tally, keyed by the label signature (result + operand indices). Avoidable recompute is measured in FLOPs against the batching-free (unlimited-memory) ideal, where each distinct value is built once at full extent and reused:
total_flopsaccumulates the actual (possibly sliced) FLOPs over every build of this value;full_flopsis the FLOPs to build it once at full extent (constant per label). The rollup takes avoidable = max(0, total_flops - full_flops) — the arithmetic batching repeats beyond building the value once, which is exactly the recompute hoisting exists to avoid.FLOPs (unlike roofline exec) is linear in extents, hence additive across slices: disjoint slices that tile the full value sum to exactly
full_flops=> 0 avoidable (tiling repeats no arithmetic), while a value rebuilt full once per block sums to N*full => (N-1)*full avoidable. That additivity is why no slice-context bucketing is needed and why the pathological >100% roofline-spread of the exec-weighted metric cannot arise.Note: the per-distinct-value avoidable rollup does not live here. It is kept by
CacheManager::recompute_tally(), keyed by the exact cache node identity (TreeNodeHasher + TreeNodeEqualityComparator) so 64-bit hash collisions are not folded; a string-keyed sink here could not reproduce that identity (the node type is kept out of this header by the dryrun/eval_expr.hpp -> cost_model_object.hpp include cycle). This sink carries only the whole-forest scalar totals (flops/exec/n_ops viatally_op).