Skip to main content

AlternativeSet

Struct AlternativeSet 

Source
pub struct AlternativeSet { /* private fields */ }
Expand description

Bounded collection of Candidates at one decision point. The optimizer ranker constructs one of these per kernel-bearing graph node, runs the filter chain, ranks survivors by composite cost, and retains the per-ending-device Pareto frontier (capped at KEEP_PER_DEVICE/device by crowding distance) for storage on the optimized graph — see Self::retain_per_device_frontier.

Stored as a SmallVec because:

  • Inline capacity 4 covers every decision point that exists today (CPU + CUDA + Vulkan + one cuBLAS/CUTLASS sibling once that registers).
  • Spilling to heap only happens when a decision point genuinely has more than 4 alternatives — rare, and the cost is amortized over a one-time enumeration anyway.

Implementations§

Source§

impl AlternativeSet

Source

pub fn empty() -> Self

Build an empty set. Tests + the candidate enumerator both use this. Retention (the per-device Pareto frontier + crowding cap) is applied later via Self::retain_per_device_frontier, not at construction.

Source

pub fn from_candidates(candidates: Vec<Candidate>) -> Self

Build a set from a pre-collected list of candidates. The enumerator path; retention (per-device Pareto frontier + crowding cap) happens after the filter chain + cost rank via Self::retain_per_device_frontier, not here.

Source

pub fn set_context(&mut self, ctx: DecisionContext)

Stamp the decision-point identity. compile_plan calls this once per kernel-bearing node; the context survives filtering, ranking, and truncation untouched (it describes the decision point, not the candidates).

Source

pub fn context(&self) -> Option<&DecisionContext>

The decision-point identity, if stamped. Dispatch-time selectors use this to key super::JudgeOracle lookups.

Source

pub fn push(&mut self, c: Candidate)

Append one candidate. Used by the enumerator as it walks (backend, device) combinations.

Source

pub fn len(&self) -> usize

How many alternatives remain. Drives the filter chain’s hard-vs-soft decision and (in later phases) the executor’s “we have N to choose from” telemetry.

Source

pub fn is_empty(&self) -> bool

Is the set empty? (i.e., no admissible alternative).

Source

pub fn alternatives(&self) -> &[Candidate]

Borrow the full candidate list. Read-only — the filter chain uses this to compute the keep-mask without mutating.

Source

pub fn retain_indices(&mut self, indices: &[usize])

Retain only the entries at indices (must be sorted ascending, distinct, and in-range). The filter-chain pipeline produces a Vec<usize> from each filter and calls this to apply it.

Panics in debug builds if indices is mis-shaped (out-of-range or unsorted). Release builds skip the check — the producer is always internal to the ranker.

Source

pub fn retain_per_device_frontier(&mut self, keep: usize)

Retain the per-ending-device Pareto frontier, backstopped by an NSGA-II crowding-distance cap of keep/device — Phase B PR-B2’s retention policy, replacing the retired fixed top-N truncation.

Production callers pass KEEP_PER_DEVICE. The set is expected to have been ranked (Self::rank_by_cost) so the arm-0 winner (lowest central time) is at index 0; this method preserves that winner and re-ranks the survivors so the winner stays at index 0 (realize follows arm-0, so its identity must not change).

§Algorithm
  1. Bucket by ending device (Candidate::device).
  2. Per-device Pareto frontier: within each bucket keep the candidates not dominated by any other candidate in the same bucket; drop the dominated.
  3. Never strand the last (device, backend): for every distinct (device, backend) present in the input, if the Pareto filter dropped all of its candidates, re-admit its time-best one. A (device, backend) with a single candidate therefore always survives, even if globally dominated.
  4. Crowding cap: if a device bucket still exceeds keep, drop the lowest-crowding-distance entries (NSGA-II: boundary points per axis get f64::INFINITY, interior points the sum of normalized neighbor gaps over the CostVector axes) until the bucket is ≤ keep — but never drop a candidate that is the sole survivor of its (device, backend), and never drop the global arm-0 winner.
§Invariants (asserted)
  • ≥1 path per device survives (each device bucket is non-empty after retention).
  • Total ≤ keep × devices.
  • The arm-0 winner is retained.

A keep of 0 is treated as 1 (a device bucket can never be emptied — that would strand the device).

Source

pub fn rank_by_cost(&mut self)

Rank candidates by the per-path cost vector (super::cost_vector::CostVector) — Phase B PR-B1.

The vector’s axes are one central time metric, per-tier memory, and discrete precision/accuracy (see the cost_vector module docs). Ranking uses CostVector::total_order_key, which keeps the winner time-first: the lowest-central-time candidate sorts to index 0 (arm-0), exactly preserving the old composite_ns winner, with ties broken precision → accuracy → memory (the constitution’s order).

Why time-first for the winner while CostVector::dominates exists: realize follows arm-0, so the winner must stay the lowest-time candidate to preserve realize behavior. Pareto dominance is the relation the frontier retention (Self::retain_per_device_frontier, PR-B2) uses — that retired the top-N truncation for a per-device Pareto frontier + crowding cap.

Stable sort — equal-key candidates keep their relative order, which matters when registration order is the residual tie-breaker (and, post-Stage-2, when decision-device candidates are enumerated ahead of off-device ones).

Source

pub fn rank_by_composite_cost(&mut self)

Sort candidates ascending by their composite static cost (Layer-1 score; see super::cost::composite_ns) plus the Stage-2 inbound-transfer term (Candidate::inbound_transfer_ns).

As of Phase B PR-B1 this delegates to Self::rank_by_cost: the cost VECTOR is now the ranking primitive, and its total_order_key is time-first, so for a single-device, single-precision candidate set (the common case + the entire CPU --lib suite) the winner is unchanged — lowest central time is exactly the old composite_ns winner. Retained as a named alias so existing callers (compile_plan, compile_run_view) and tests don’t churn.

Phase 1.4 of the picker-work arc. Composite cost is max(compute_ns, memory_ns) + overhead_ns, treating compute and memory as parallel (roofline model). Layer-2 Judge data refines static_cost before this call (compute_static_costs); the transfer term is added serially — the bytes must land before the kernel can run.

Source

pub fn set_static_cost(&mut self, index: usize, cost: CostEstimate)

Set the static_cost field of the candidate at index. Used by super::cost::compute_static_costs to populate the field after enumeration. Panics in debug builds if index >= len.

Source

pub fn set_inbound_transfer_ns(&mut self, index: usize, ns: u64)

Set the Stage-2 inbound-transfer term of the candidate at index. Used by super::cost::apply_inbound_transfer_costs. Panics in debug builds if index >= len.

Source

pub fn winner(&self) -> Option<&Candidate>

The current top candidate (first entry). After the full pipeline — filter → rank → retain — this is the runtime selector’s (Picker 2) default pick. None if the set is empty.

Trait Implementations§

Source§

impl Clone for AlternativeSet

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AlternativeSet

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more