Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion crates/devtools/src/bin/stage_pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@
// `cause` (a failed check: `accuracy_target_missed`,
// `count_min_weights_not_proven_non_negative`, `no_accuracy_guarantee`,
// `latency_bound_exceeded`, `latency_over_repeat_interval`,
// `over_cluster_capacity`; or a loss under the cost model: `costlier`,
// `over_cluster_capacity`, `cost_not_representable`; or a loss under
// the cost model: `costlier`,
// `slower`, `more_memory`, `tied_lost_on_enumeration_order`),
// `pruned_candidates_not_enumerated` (rejections naming no enumerated
// candidate) and `pruned_candidate_count_by_cause`.
Expand Down
2 changes: 2 additions & 0 deletions crates/devtools/tests/viewer_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ fn viewer_knows_every_view_refresh_and_rejection_cause() {
C::LatencyOverRepeatInterval,
C::OverClusterCapacity,
C::Infeasible,
C::CostNotRepresentable,
C::Costlier,
C::Slower,
C::MoreMemory,
Expand All @@ -368,6 +369,7 @@ fn viewer_knows_every_view_refresh_and_rejection_cause() {
| C::LatencyOverRepeatInterval
| C::OverClusterCapacity
| C::Infeasible
| C::CostNotRepresentable
| C::Costlier
| C::Slower
| C::MoreMemory
Expand Down
37 changes: 37 additions & 0 deletions crates/plan-selection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5691,6 +5691,43 @@ mod tests {
}
}

/// The reference pricer rejects a candidate it cannot price, as the
/// search does, rather than failing the whole selection.
#[test]
fn the_reference_pricer_rejects_an_unpriceable_candidate() {
let candidates = tumbling_window_candidates(10_000.0);
let kll = candidates[0]
.dag
.nodes
.iter()
.find_map(|node| match &node.payload {
Payload::ASAP(ASAPOp::SummaryTumblingWindowChain {
family: FieldDataType::Sketch(kind, _),
..
}) => Some(kind.params().clone()),
_ => None,
})
.unwrap();
let settings = measured(vec![OperatorCost {
memory_bytes_per_state: Some(u64::MAX as f64),
..sketch_entry(OperatorKind::SummaryTumblingWindowChain, kll, 1.0)
}]);
let entries = [entry_with(p99_target(), repeating(MINUTE))];
let models = SelectionModels {
cost_inputs: &settings,
..SelectionModels::builtin()
};
let Err(ErrorSelectingPlan::NoValidCandidate(rejected)) =
select_among_plans(&candidates, &entries, &arriving(10_000.0), models)
else {
panic!("every candidate overflows, so none is valid");
};
assert_eq!(rejected.len(), candidates.len());
assert!(rejected
.iter()
.all(|r| r.cause == RejectionCause::CostNotRepresentable));
}

/// The table of earlier versions, a JSON array of sketch operations,
/// still loads: each entry becomes its operator's entry at both phases,
/// an update both a `SummaryAgg` and a `SummaryTumblingWindowChain` entry.
Expand Down
8 changes: 6 additions & 2 deletions crates/plan-selection/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ pub enum RejectionCause {
LatencyOverRepeatInterval,
/// Under cost model 3, its usage is over one of the cluster's limits.
OverClusterCapacity,
/// Its cost overflows the cost model's arithmetic, so it cannot be
/// priced.
CostNotRepresentable,
/// Under cost models 1 and 2, its price is higher than the selected
/// candidate's.
Costlier,
Expand All @@ -94,8 +97,8 @@ pub enum RejectionCause {

impl RejectionCause {
/// Whether the candidate failed a check (accuracy, latency bound,
/// repeat interval or cluster capacity) rather than losing under the
/// cost model.
/// repeat interval, cluster capacity or a representable cost) rather
/// than losing under the cost model.
pub fn failed_a_check(self) -> bool {
matches!(
self,
Expand All @@ -106,6 +109,7 @@ impl RejectionCause {
| Self::LatencyOverRepeatInterval
| Self::OverClusterCapacity
| Self::Infeasible
| Self::CostNotRepresentable
)
}
}
Expand Down
27 changes: 24 additions & 3 deletions crates/plan-selection/src/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::checks::{accuracy_check, accuracy_targets, latency_violation};
use crate::report::{
AcceptedAccuracy, ErrorSelectingPlan, Rejection, RejectionCause, WholePlanSelection,
};
use crate::SelectionModels;
use crate::{AnalyticalCostError, SelectionModels};
use asap_cost::{
kept_tumbling_window_chains, node_map, plan_cost, query_reach, tumbling_window_retention_ms,
};
Expand Down Expand Up @@ -57,12 +57,33 @@ pub(crate) fn select_among_plans(
if selector.needs_calibration() {
let mut fit = CalibrationFit::default();
for candidate in cands {
fit.add(selector.calibration_fit(candidate)?);
match selector.calibration_fit(candidate) {
// Rejected below when offered.
Err(ErrorSelectingPlan::Cost {
error: AnalyticalCostError::Overflow,
..
}) => {}
fit_or_error => fit.add(fit_or_error?),
}
}
selector.set_calibration(fit);
}
// An unpriceable candidate is rejected, as the search rejects it
// (`cost_not_representable`), rather than failing the selection.
for candidate in cands {
selector.offer(candidate)?;
match selector.offer(candidate) {
Err(
error @ ErrorSelectingPlan::Cost {
error: AnalyticalCostError::Overflow,
..
},
) => selector.reject(
&candidate.id,
RejectionCause::CostNotRepresentable,
error.to_string(),
),
result => result?,
}
}
selector.finish().map(|(selection, _)| selection)
}
Expand Down
4 changes: 2 additions & 2 deletions docs/develop_docs/asap-aware-mapping-contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ asap-physical-asap-optimization -p asap-plan-selection -p asap-types
`CountMinWeightsNotProvenNonNegative`,
`NoAccuracyGuarantee`, `LatencyBoundExceeded`, `LatencyOverRepeatInterval`
(a repeating query's latency per evaluation is over its repeat interval,
checked with or without a latency bound), or `OverClusterCapacity` under
cost model 3) or a loss under the cost model (`Costlier`, `Slower`,
checked with or without a latency bound), `OverClusterCapacity` under
cost model 3, or `CostNotRepresentable` (its cost overflows)) or a loss under the cost model (`Costlier`, `Slower`,
`MoreMemory`, `TiedLostOnEnumerationOrder`). Stage 3 never resizes a summary: a candidate
whose Stage 1 sizes miss its composed accuracy target is rejected alone.
- Usage (`ResourceUsage`) is measured without prices; the `CostModel` in
Expand Down
3 changes: 2 additions & 1 deletion tools/dag-viewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ are ignored, `stage_pipeline`'s default.
(`accuracy_target_missed`,
`count_min_weights_not_proven_non_negative`,
`no_accuracy_guarantee`, `latency_bound_exceeded`,
`latency_over_repeat_interval`, `over_cluster_capacity`) or a loss under
`latency_over_repeat_interval`, `over_cluster_capacity`,
`cost_not_representable`) or a loss under
the cost model (`costlier`, `slower`, `more_memory`,
`tied_lost_on_enumeration_order`).
- `accuracy_guarantees` is `ignored` (`stage_pipeline`'s default: Stage 3
Expand Down
2 changes: 1 addition & 1 deletion tools/dag-viewer/stages.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ const FAILED_CHECK_CAUSES = [
'accuracy_target_missed',
'count_min_weights_not_proven_non_negative',
'no_accuracy_guarantee', 'latency_bound_exceeded', 'latency_over_repeat_interval',
'over_cluster_capacity', 'infeasible',
'over_cluster_capacity', 'infeasible', 'cost_not_representable',
];
// Every `reference_pricing.pruned_candidates[].cause` the reference pricer
// writes: the failed checks, then the losses under the cost model (priced,
Expand Down
Loading