Extract scheme-selection policy into a pluggable CostModel#8698
Draft
connortsui20 wants to merge 6 commits into
Draft
Extract scheme-selection policy into a pluggable CostModel#8698connortsui20 wants to merge 6 commits into
connortsui20 wants to merge 6 commits into
Conversation
Merging this PR will not alter performance
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes
|
21 tasks
e39c549 to
e17a967
Compare
00ccec3 to
1c1ad1b
Compare
e17a967 to
83988a0
Compare
1c1ad1b to
29b6106
Compare
Pure refactor of choose_best_scheme and the sampling estimator: - estimate_compression_ratio_with_sampling now returns a SampledEstimate carrying the compressed sample array alongside its score, instead of measuring nbytes and dropping the array. - Selection bookkeeping switches from (scheme, EstimateScore) tuples to a crate-private Candidate carrying the mechanical facts about each option (scheme, score, input bytes, value count, sampled array, cascade ancestry). Candidates are still compared by ratio, ties still break by registration order, and the sampled array is dropped at the end of selection, so behavior is unchanged: same winners, same estimates, same output (golden suite has zero snapshot churn). The not-yet-read Candidate fields are the facts a pluggable cost model prices in the follow-up rungs (#7697) with no new Scheme API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
New vortex_compressor::cost module extracting selection policy into a pluggable model, per the compressor cost-model plan (#7697): - Cost: opaque finite f64 newtype, lower is better; units are defined per model since costs are only compared within one model. - CostModel: price a Candidate (None = reject) and price the canonical baseline every candidate must strictly beat. The module docs state the axioms that stay outside the model: AlwaysUse short-circuiting and the byte-acceptance gate (including its AnyScalarFn carve-out). - SizeCost: prices a candidate at Cost(-ratio) over the exact ratio signal and canonical at Cost(-1.0), reproducing ratio-argmax selection bit-exactly. Pricing off the ratio rather than recomputed bytes (input/ratio) avoids IEEE division collapsing strict ratio inequalities into ties and flipping winners via registration order. Candidate becomes public (it is the trait's argument), re-exported via the cost module. Unit tests pin the validity gate, pairwise ordering and tie behavior against the historical rules. Nothing consumes the module yet; the selection loop is wired to it in the next commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
choose_best_scheme now prices every scored candidate through the
compressor's CostModel: the winner is the argmin-cost candidate, and
eligibility is cost strictly below CostModel::canonical_cost. Strict <
comparisons preserve registration-order tie-breaking exactly as before.
The legacy comparators whose logic moved into SizeCost and the selection
loop (is_better_score, EstimateScore::{is_valid, beats}) are deleted.
CascadingCompressor gains with_cost_model(Arc<dyn CostModel>), holding
SizeCost by default, so default behavior is unchanged (bit-exact under
SizeCost by decision 1 of the cost-model plan; golden suite shows zero
snapshot churn). AlwaysUse short-circuiting, the deferred-callback ratio
threshold, and the byte-acceptance gate are untouched.
The winner_compress trace span gains estimated_cost alongside
estimated_ratio, keeping estimator observability at parity for
non-ratio models. WinnerEstimate::Score becomes a struct variant
carrying the winning cost; the choose_best_scheme unit tests' match
patterns are updated mechanically for the new variant shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
7672d77 to
cf51915
Compare
Signed-off-by: Connor Tsui <connor.tsui20@gmail.com>
The module docs' SizeCost link stopped resolving when SizeCost moved into the public cost::size submodule without a top-level re-export, and CostModel's module-docs link pointed at the now-private cost_model module. Point them at size::SizeCost and crate::cost respectively; rustdoc with -D warnings passes again. Signed-off-by: Connor Tsui <connor@spiraldb.com> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MVQ2n8mT9FPCf8cmqRNcw1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tracking Issue: #8701
Rationale for this change
The compressor's selection objective — maximize estimated compression ratio — is hardcoded into the selection loop, so it cannot be varied per workload (#7697). This PR makes the objective a pluggable
CostModel: schemes continue to produce model-independent estimate facts, the model converts those facts intoCost, and the compressor selects the lowest-cost candidate.The default
SizeCostpreserves today's ratio ordering and canonical-acceptance threshold. It prices the exact ratio signal (Cost(-ratio), canonical baselineCost(-1.0)) rather than recomputing bytes, so IEEE rounding cannot turn a strict ratio ordering into a cost tie.What changes are included in this PR?
Details
Candidate: an opaque, borrowed view of the mechanical facts available for each selection option, including its estimated ratio and optional compressed sample. Sampling exposes the compressed sample array to the model only while that candidate is priced; the selector does not retain it or clone cascade history.vortex_compressor::cost: a finite, totally orderedCost, theCostModeltrait, and the defaultSizeCost.Costis the only candidate-ranking value; compression ratios remain estimator input and tracing metadata.EstimateScoreis removed. Deferred estimate callbacks now receivebest_ratio: Option<f64>directly, and sampled estimates represent a zero-byte output as an absent ratio. The Delta and Sequence schemes are updated to the simplified callback contract.AlwaysUse, the final byte-acceptance gate, and extension-versus-storage selection — are documented explicitly.winner_compresstrace span gains model-definedestimated_costalongsideestimated_ratio.canonical_cost, sampled arrays are exposed only for sampled candidates, and custom models are not incorrectly pruned by ratio thresholds. The golden encoding-tree and size snapshots remain unchanged.This PR does not add model-driven pruning, scheme priors, Delta-specific policy, builder/session plumbing, or a production time-based model.
What APIs are changed? Are there any user-facing changes?
This adds
cost::{Cost, CostModel, SizeCost, Candidate}andCascadingCompressor::with_cost_model.It deliberately changes the scheme-facing deferred callback API:
EstimateFnreceivesOption<f64>(best_ratio) instead ofOption<EstimateScore>, andEstimateScoreis removed.Scheme::expected_compression_ratioitself retains the same signature. The defaultSizeCostpreserves existing selection ordering, and the golden encoding-tree and array-size snapshots remain unchanged.