Skip to main content

vyre_driver/
benchmark_pass_selection.rs

1//! Benchmark-driven optimization pass selection.
2//!
3//! Expensive passes must not fire because a static list says so. They need
4//! graph/frontier/reuse evidence showing that the launch, memory, or readback
5//! cost they remove is larger than their own planning cost. This module makes
6//! that decision explicit and deterministic.
7
8use crate::accounting::{
9    checked_add_u64_count as checked_add, checked_add_usize_count as checked_add_usize,
10    ArithmeticOverflow,
11};
12use crate::numeric::checked_compose_basis_points_u64;
13use crate::reservation_policy::{
14    reserved_typed_vec as reserved_vec, ReservationPolicy, ReusableIndexScratch,
15};
16
17const BENCHMARK_PASS_SELECTION_RESERVATION: ReservationPolicy = ReservationPolicy::new(
18    "benchmark pass selection",
19    "shard the optimization candidate set before pass selection",
20);
21
22/// One optimization candidate with benchmark-derived thresholds.
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct BenchmarkPassCandidate {
25    /// Registered optimization pass id.
26    pub pass_id: &'static str,
27    /// Minimum active frontier items required before this pass is profitable.
28    pub min_frontier_items: u64,
29    /// Minimum repeated graph executions required before this pass is profitable.
30    pub min_reuse_count: u64,
31    /// Minimum readback bytes avoided before this pass is profitable.
32    pub min_avoided_readback_bytes: u64,
33    /// Estimated planning/compile cost in nanoseconds.
34    pub planning_cost_ns: u64,
35    /// Scratch bytes needed by the pass while planning/executing.
36    pub scratch_bytes: u64,
37    /// Expected speedup in basis points from committed benchmark evidence.
38    pub expected_speedup_bps: u32,
39    /// Whether the pass is mandatory when its thresholds are met.
40    pub mandatory_when_profitable: bool,
41}
42
43/// Runtime benchmark sample used to select optimization passes.
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub struct BenchmarkPassSelectionSample {
46    /// Active frontier items in the current graph/query batch.
47    pub frontier_items: u64,
48    /// Number of repeated executions over the same resident graph shape.
49    pub reuse_count: u64,
50    /// Readback bytes the workload can avoid with compaction/aggregation.
51    pub avoidable_readback_bytes: u64,
52    /// Maximum total planning cost allowed.
53    pub planning_budget_ns: u64,
54    /// Maximum scratch bytes allowed for selected passes.
55    pub scratch_budget_bytes: u64,
56}
57
58/// One skipped optimization with a stable reason.
59#[derive(Clone, Debug, Eq, PartialEq)]
60pub struct SkippedBenchmarkPass {
61    /// Registered optimization pass id.
62    pub pass_id: &'static str,
63    /// Stable reason.
64    pub reason: BenchmarkPassSkipReason,
65}
66
67/// Stable skip reason for an optimization candidate.
68#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub enum BenchmarkPassSkipReason {
70    /// Frontier is too small for this pass to pay for itself.
71    FrontierBelowThreshold,
72    /// Graph reuse is too low for residency/cache/fusion work to amortize.
73    ReuseBelowThreshold,
74    /// Readback pressure is too low for compaction/aggregation to pay off.
75    ReadbackBelowThreshold,
76    /// Planning budget would be exceeded.
77    PlanningBudgetExceeded,
78    /// Scratch budget would be exceeded.
79    ScratchBudgetExceeded,
80}
81
82/// Pass-selection output.
83#[derive(Clone, Debug, Eq, PartialEq)]
84pub struct BenchmarkPassSelectionPlan {
85    /// Selected pass ids in benchmark-value order.
86    pub selected_pass_ids: Vec<&'static str>,
87    /// Skipped pass ids with stable reasons.
88    pub skipped_passes: Vec<SkippedBenchmarkPass>,
89    /// Total selected planning cost.
90    pub total_planning_cost_ns: u64,
91    /// Total selected scratch bytes.
92    pub total_scratch_bytes: u64,
93    /// Product of selected speedup multipliers in basis points.
94    pub projected_speedup_bps: u64,
95}
96
97/// Caller-owned scratch for repeated benchmark pass selection.
98#[derive(Debug, Default)]
99pub struct BenchmarkPassSelectionScratch {
100    index_scratch: ReusableIndexScratch<&'static str>,
101}
102
103impl BenchmarkPassSelectionScratch {
104    /// Allocate empty reusable pass-selection scratch.
105    #[must_use]
106    pub fn new() -> Self {
107        Self::default()
108    }
109
110    /// Allocate reusable pass-selection scratch for a known candidate count.
111    ///
112    /// # Errors
113    ///
114    /// Returns [`BenchmarkPassSelectionError`] when scratch storage cannot be reserved.
115    pub fn try_with_capacity(candidate_count: usize) -> Result<Self, BenchmarkPassSelectionError> {
116        let mut scratch = Self::default();
117        scratch.try_reserve_candidates(candidate_count)?;
118        Ok(scratch)
119    }
120
121    /// Reserve reusable pass-selection scratch for a known candidate count.
122    ///
123    /// # Errors
124    ///
125    /// Returns [`BenchmarkPassSelectionError`] when scratch storage cannot be reserved.
126    pub fn try_reserve_candidates(
127        &mut self,
128        candidate_count: usize,
129    ) -> Result<(), BenchmarkPassSelectionError> {
130        self.index_scratch.try_reserve_with(
131            BENCHMARK_PASS_SELECTION_RESERVATION,
132            candidate_count,
133            "scratch.seen",
134            "scratch.ordered_indices",
135            storage_reserve_failed,
136        )
137    }
138
139    /// Retained duplicate-detection capacity.
140    #[must_use]
141    pub fn seen_capacity(&self) -> usize {
142        self.index_scratch.seen_capacity()
143    }
144
145    /// Retained candidate-ordering capacity.
146    #[must_use]
147    pub fn ordered_index_capacity(&self) -> usize {
148        self.index_scratch.ordered_index_capacity()
149    }
150}
151
152/// Benchmark-driven pass-selection errors.
153#[derive(Clone, Debug, Eq, PartialEq)]
154pub enum BenchmarkPassSelectionError {
155    /// Candidate pass id is empty.
156    EmptyPassId,
157    /// Duplicate candidate pass id.
158    DuplicatePassId {
159        /// Duplicate pass id.
160        pass_id: &'static str,
161    },
162    /// Candidate has no benchmark speedup evidence.
163    MissingSpeedupEvidence {
164        /// Invalid pass id.
165        pass_id: &'static str,
166    },
167    /// Mandatory profitable pass could not fit the explicit budgets.
168    MandatoryProfitablePassOverBudget {
169        /// Pass id.
170        pass_id: &'static str,
171        /// Reason it could not fit.
172        reason: BenchmarkPassSkipReason,
173    },
174    /// Arithmetic overflowed.
175    CountOverflow {
176        /// Field being computed.
177        field: &'static str,
178    },
179    /// Scratch or result-vector storage reservation failed before pass selection.
180    StorageReserveFailed {
181        /// Field being reserved.
182        field: &'static str,
183        /// Requested total capacity.
184        requested: usize,
185        /// Allocator failure details.
186        message: String,
187    },
188}
189
190impl ArithmeticOverflow for BenchmarkPassSelectionError {
191    fn arithmetic_overflow(field: &'static str) -> Self {
192        Self::CountOverflow { field }
193    }
194}
195
196impl std::fmt::Display for BenchmarkPassSelectionError {
197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198        match self {
199            Self::EmptyPassId => write!(
200                f,
201                "benchmark pass selection received an empty pass id. Fix: register every pass before selection."
202            ),
203            Self::DuplicatePassId { pass_id } => write!(
204                f,
205                "benchmark pass selection received duplicate pass `{pass_id}`. Fix: keep one benchmark row per pass."
206            ),
207            Self::MissingSpeedupEvidence { pass_id } => write!(
208                f,
209                "benchmark pass `{pass_id}` has no positive speedup evidence. Fix: add committed benchmark evidence or remove the candidate."
210            ),
211            Self::MandatoryProfitablePassOverBudget { pass_id, reason } => write!(
212                f,
213                "mandatory profitable pass `{pass_id}` was blocked by {reason:?}. Fix: raise the explicit budget or shard before pass selection."
214            ),
215            Self::CountOverflow { field } => write!(
216                f,
217                "benchmark pass selection overflowed while computing {field}. Fix: shard the optimization candidate set."
218            ),
219            Self::StorageReserveFailed {
220                field,
221                requested,
222                message,
223            } => write!(
224                f,
225                "benchmark pass selection failed to reserve {field} for {requested} entries: {message}. Fix: shard the optimization candidate set before pass selection."
226            ),
227        }
228    }
229}
230
231impl std::error::Error for BenchmarkPassSelectionError {}
232
233/// Select optimization passes from benchmark evidence and workload stats.
234///
235/// # Errors
236///
237/// Returns [`BenchmarkPassSelectionError`] when candidates are invalid, budget
238/// accounting overflows, mandatory profitable passes cannot fit the budget, or
239/// planner storage cannot be reserved.
240pub fn select_benchmark_passes(
241    candidates: &[BenchmarkPassCandidate],
242    sample: BenchmarkPassSelectionSample,
243) -> Result<BenchmarkPassSelectionPlan, BenchmarkPassSelectionError> {
244    let mut scratch = BenchmarkPassSelectionScratch::try_with_capacity(candidates.len())?;
245    select_benchmark_passes_with_scratch(candidates, sample, &mut scratch)
246}
247
248/// Select optimization passes using caller-owned temporary storage.
249///
250/// # Errors
251///
252/// Returns [`BenchmarkPassSelectionError`] when candidates are invalid, budget
253/// accounting overflows, mandatory profitable passes cannot fit the budget, or
254/// planner storage cannot be reserved.
255pub fn select_benchmark_passes_with_scratch(
256    candidates: &[BenchmarkPassCandidate],
257    sample: BenchmarkPassSelectionSample,
258    scratch: &mut BenchmarkPassSelectionScratch,
259) -> Result<BenchmarkPassSelectionPlan, BenchmarkPassSelectionError> {
260    scratch.index_scratch.clear();
261    scratch.try_reserve_candidates(candidates.len())?;
262    for (index, candidate) in candidates.iter().enumerate() {
263        if candidate.pass_id.is_empty() {
264            return Err(BenchmarkPassSelectionError::EmptyPassId);
265        }
266        if !scratch.index_scratch.insert_seen(candidate.pass_id) {
267            return Err(BenchmarkPassSelectionError::DuplicatePassId {
268                pass_id: candidate.pass_id,
269            });
270        }
271        if candidate.expected_speedup_bps <= 10_000 {
272            return Err(BenchmarkPassSelectionError::MissingSpeedupEvidence {
273                pass_id: candidate.pass_id,
274            });
275        }
276        scratch.index_scratch.push_index(index);
277    }
278    scratch
279        .index_scratch
280        .ordered_indices_mut()
281        .sort_unstable_by(|&left, &right| {
282            candidates[right]
283                .mandatory_when_profitable
284                .cmp(&candidates[left].mandatory_when_profitable)
285                .then_with(|| {
286                    pass_value(&candidates[right])
287                        .cmp(&pass_value(&candidates[left]))
288                        .then_with(|| candidates[left].pass_id.cmp(candidates[right].pass_id))
289                })
290        });
291
292    let (selected_pass_capacity, skipped_pass_capacity) =
293        count_final_pass_buckets(candidates, sample, scratch.index_scratch.ordered_indices())?;
294    let mut selected_pass_ids =
295        reserved_selection_vec(selected_pass_capacity, "selected_pass_ids")?;
296    let mut skipped_passes = reserved_selection_vec(skipped_pass_capacity, "skipped_passes")?;
297    let mut total_planning_cost_ns = 0_u64;
298    let mut total_scratch_bytes = 0_u64;
299    let mut projected_speedup_bps = 10_000_u64;
300
301    for &index in scratch.index_scratch.ordered_indices() {
302        let candidate = candidates[index];
303        if sample.frontier_items < candidate.min_frontier_items {
304            skipped_passes.push(skipped(
305                candidate.pass_id,
306                BenchmarkPassSkipReason::FrontierBelowThreshold,
307            ));
308            continue;
309        }
310        if sample.reuse_count < candidate.min_reuse_count {
311            skipped_passes.push(skipped(
312                candidate.pass_id,
313                BenchmarkPassSkipReason::ReuseBelowThreshold,
314            ));
315            continue;
316        }
317        if sample.avoidable_readback_bytes < candidate.min_avoided_readback_bytes {
318            skipped_passes.push(skipped(
319                candidate.pass_id,
320                BenchmarkPassSkipReason::ReadbackBelowThreshold,
321            ));
322            continue;
323        }
324
325        let next_planning = checked_add(
326            total_planning_cost_ns,
327            candidate.planning_cost_ns,
328            "planning cost",
329        )?;
330        if next_planning > sample.planning_budget_ns {
331            handle_budget_skip(
332                candidate,
333                BenchmarkPassSkipReason::PlanningBudgetExceeded,
334                &mut skipped_passes,
335            )?;
336            continue;
337        }
338        let next_scratch = checked_add(
339            total_scratch_bytes,
340            candidate.scratch_bytes,
341            "scratch bytes",
342        )?;
343        if next_scratch > sample.scratch_budget_bytes {
344            handle_budget_skip(
345                candidate,
346                BenchmarkPassSkipReason::ScratchBudgetExceeded,
347                &mut skipped_passes,
348            )?;
349            continue;
350        }
351
352        selected_pass_ids.push(candidate.pass_id);
353        total_planning_cost_ns = next_planning;
354        total_scratch_bytes = next_scratch;
355        projected_speedup_bps = checked_compose_basis_points_u64(
356            projected_speedup_bps,
357            u64::from(candidate.expected_speedup_bps),
358        )
359        .ok_or(BenchmarkPassSelectionError::CountOverflow {
360            field: "projected speedup product",
361        })?;
362    }
363
364    Ok(BenchmarkPassSelectionPlan {
365        selected_pass_ids,
366        skipped_passes,
367        total_planning_cost_ns,
368        total_scratch_bytes,
369        projected_speedup_bps,
370    })
371}
372
373fn pass_value(candidate: &BenchmarkPassCandidate) -> u128 {
374    u128::from(candidate.expected_speedup_bps)
375        * (u128::from(candidate.min_frontier_items)
376            + u128::from(candidate.min_reuse_count)
377            + u128::from(candidate.min_avoided_readback_bytes))
378}
379
380fn count_final_pass_buckets(
381    candidates: &[BenchmarkPassCandidate],
382    sample: BenchmarkPassSelectionSample,
383    ordered_indices: &[usize],
384) -> Result<(usize, usize), BenchmarkPassSelectionError> {
385    let mut selected = 0usize;
386    let mut skipped = 0usize;
387    let mut total_planning_cost_ns = 0_u64;
388    let mut total_scratch_bytes = 0_u64;
389    for &index in ordered_indices {
390        let candidate = candidates[index];
391        if sample.frontier_items < candidate.min_frontier_items
392            || sample.reuse_count < candidate.min_reuse_count
393            || sample.avoidable_readback_bytes < candidate.min_avoided_readback_bytes
394        {
395            skipped = checked_add_usize(skipped, 1, "skipped pass count")?;
396            continue;
397        }
398        let next_planning = checked_add(
399            total_planning_cost_ns,
400            candidate.planning_cost_ns,
401            "planning cost",
402        )?;
403        if next_planning > sample.planning_budget_ns {
404            if candidate.mandatory_when_profitable {
405                return Err(
406                    BenchmarkPassSelectionError::MandatoryProfitablePassOverBudget {
407                        pass_id: candidate.pass_id,
408                        reason: BenchmarkPassSkipReason::PlanningBudgetExceeded,
409                    },
410                );
411            }
412            skipped = checked_add_usize(skipped, 1, "skipped pass count")?;
413            continue;
414        }
415        let next_scratch = checked_add(
416            total_scratch_bytes,
417            candidate.scratch_bytes,
418            "scratch bytes",
419        )?;
420        if next_scratch > sample.scratch_budget_bytes {
421            if candidate.mandatory_when_profitable {
422                return Err(
423                    BenchmarkPassSelectionError::MandatoryProfitablePassOverBudget {
424                        pass_id: candidate.pass_id,
425                        reason: BenchmarkPassSkipReason::ScratchBudgetExceeded,
426                    },
427                );
428            }
429            skipped = checked_add_usize(skipped, 1, "skipped pass count")?;
430            continue;
431        }
432        selected = checked_add_usize(selected, 1, "selected pass count")?;
433        total_planning_cost_ns = next_planning;
434        total_scratch_bytes = next_scratch;
435    }
436    Ok((selected, skipped))
437}
438
439fn skipped(pass_id: &'static str, reason: BenchmarkPassSkipReason) -> SkippedBenchmarkPass {
440    SkippedBenchmarkPass { pass_id, reason }
441}
442
443fn handle_budget_skip(
444    candidate: BenchmarkPassCandidate,
445    reason: BenchmarkPassSkipReason,
446    skipped_passes: &mut Vec<SkippedBenchmarkPass>,
447) -> Result<(), BenchmarkPassSelectionError> {
448    if candidate.mandatory_when_profitable {
449        return Err(
450            BenchmarkPassSelectionError::MandatoryProfitablePassOverBudget {
451                pass_id: candidate.pass_id,
452                reason,
453            },
454        );
455    }
456    skipped_passes.push(skipped(candidate.pass_id, reason));
457    Ok(())
458}
459
460fn reserved_selection_vec<T>(
461    capacity: usize,
462    field: &'static str,
463) -> Result<Vec<T>, BenchmarkPassSelectionError> {
464    reserved_vec(
465        BENCHMARK_PASS_SELECTION_RESERVATION,
466        capacity,
467        field,
468        storage_reserve_failed,
469    )
470}
471
472fn storage_reserve_failed(
473    field: &'static str,
474    requested: usize,
475    message: String,
476) -> BenchmarkPassSelectionError {
477    BenchmarkPassSelectionError::StorageReserveFailed {
478        field,
479        requested,
480        message,
481    }
482}
483
484#[cfg(test)]
485mod tests {
486    use super::*;
487
488    #[test]
489    fn benchmark_pass_selection_picks_profitable_passes_by_value() {
490        let plan = select_benchmark_passes(
491            &[
492                candidate(
493                    "device.adjacent-launch-fusion",
494                    1_000,
495                    4,
496                    0,
497                    100,
498                    64,
499                    18_000,
500                    true,
501                ),
502                candidate(
503                    "device.result-compaction",
504                    1,
505                    1,
506                    4_096,
507                    20,
508                    16,
509                    12_000,
510                    false,
511                ),
512                candidate(
513                    "device.megakernel-plan-cache",
514                    1,
515                    64,
516                    0,
517                    50,
518                    32,
519                    25_000,
520                    true,
521                ),
522            ],
523            BenchmarkPassSelectionSample {
524                frontier_items: 2_000,
525                reuse_count: 128,
526                avoidable_readback_bytes: 8_192,
527                planning_budget_ns: 200,
528                scratch_budget_bytes: 128,
529            },
530        )
531        .expect("Fix: profitable passes should select");
532
533        assert_eq!(plan.selected_pass_ids.len(), 3);
534        assert!(plan
535            .selected_pass_ids
536            .contains(&"device.megakernel-plan-cache"));
537        assert!(plan
538            .selected_pass_ids
539            .contains(&"device.adjacent-launch-fusion"));
540        assert!(plan.selected_pass_ids.contains(&"device.result-compaction"));
541        assert_eq!(plan.total_planning_cost_ns, 170);
542        assert_eq!(plan.total_scratch_bytes, 112);
543        assert!(plan.projected_speedup_bps > 50_000);
544    }
545
546    #[test]
547    fn benchmark_pass_selection_skips_unprofitable_passes_with_stable_reasons() {
548        let plan = select_benchmark_passes(
549            &[
550                candidate(
551                    "device.adjacent-launch-fusion",
552                    1_000,
553                    4,
554                    0,
555                    10,
556                    8,
557                    15_000,
558                    false,
559                ),
560                candidate(
561                    "device.result-compaction",
562                    1,
563                    1,
564                    4_096,
565                    10,
566                    8,
567                    11_000,
568                    false,
569                ),
570            ],
571            BenchmarkPassSelectionSample {
572                frontier_items: 10,
573                reuse_count: 1,
574                avoidable_readback_bytes: 128,
575                planning_budget_ns: 100,
576                scratch_budget_bytes: 100,
577            },
578        )
579        .expect("Fix: unprofitable optional passes should skip");
580
581        assert_eq!(plan.selected_pass_ids, Vec::<&'static str>::new());
582        assert_eq!(plan.skipped_passes.len(), 2);
583        assert!(plan.skipped_passes.contains(&SkippedBenchmarkPass {
584            pass_id: "device.adjacent-launch-fusion",
585            reason: BenchmarkPassSkipReason::FrontierBelowThreshold,
586        }));
587        assert!(plan.skipped_passes.contains(&SkippedBenchmarkPass {
588            pass_id: "device.result-compaction",
589            reason: BenchmarkPassSkipReason::ReadbackBelowThreshold,
590        }));
591    }
592
593    #[test]
594    fn benchmark_pass_selection_ranks_huge_values_without_saturation_ties() {
595        let plan = select_benchmark_passes(
596            &[
597                candidate(
598                    "device.a-lexicographic-low-value",
599                    u64::MAX,
600                    u64::MAX,
601                    u64::MAX - 1,
602                    1,
603                    1,
604                    11_000,
605                    false,
606                ),
607                candidate(
608                    "device.z-lexicographic-high-value",
609                    u64::MAX,
610                    u64::MAX,
611                    u64::MAX,
612                    1,
613                    1,
614                    11_000,
615                    false,
616                ),
617            ],
618            BenchmarkPassSelectionSample {
619                frontier_items: u64::MAX,
620                reuse_count: u64::MAX,
621                avoidable_readback_bytes: u64::MAX,
622                planning_budget_ns: 10,
623                scratch_budget_bytes: 10,
624            },
625        )
626        .expect("Fix: huge benchmark evidence should rank without saturating value ties");
627
628        assert_eq!(
629            plan.selected_pass_ids[0],
630            "device.z-lexicographic-high-value",
631            "Fix: pass ranking must use widened arithmetic; saturating u64 scoring would tie these candidates and incorrectly choose lexicographic order."
632        );
633    }
634
635    #[test]
636    fn benchmark_pass_selection_rejects_missing_evidence_and_blocked_mandatory() {
637        assert_eq!(
638            select_benchmark_passes(
639                &[candidate("device.bad", 1, 1, 0, 1, 1, 10_000, false)],
640                sample(),
641            )
642            .expect_err("zero speedup evidence should fail"),
643            BenchmarkPassSelectionError::MissingSpeedupEvidence {
644                pass_id: "device.bad",
645            }
646        );
647        assert_eq!(
648            select_benchmark_passes(
649                &[candidate("device.mandatory", 1, 1, 0, 101, 1, 11_000, true,)],
650                sample(),
651            )
652            .expect_err("mandatory profitable pass cannot exceed budget"),
653            BenchmarkPassSelectionError::MandatoryProfitablePassOverBudget {
654                pass_id: "device.mandatory",
655                reason: BenchmarkPassSkipReason::PlanningBudgetExceeded,
656            }
657        );
658    }
659
660    #[test]
661    fn benchmark_pass_selection_does_not_let_optional_passes_starve_mandatory_passes() {
662        let plan = select_benchmark_passes(
663            &[
664                candidate(
665                    "device.optional-high-value",
666                    1,
667                    1,
668                    1_000_000,
669                    100,
670                    1,
671                    20_000,
672                    false,
673                ),
674                candidate("device.mandatory-low-value", 1, 1, 1, 100, 1, 11_000, true),
675            ],
676            BenchmarkPassSelectionSample {
677                frontier_items: 1,
678                reuse_count: 1,
679                avoidable_readback_bytes: 1_000_000,
680                planning_budget_ns: 100,
681                scratch_budget_bytes: 8,
682            },
683        )
684        .expect("Fix: mandatory profitable pass must reserve budget before optional passes");
685
686        assert_eq!(plan.selected_pass_ids, vec!["device.mandatory-low-value"]);
687        assert_eq!(
688            plan.skipped_passes,
689            vec![SkippedBenchmarkPass {
690                pass_id: "device.optional-high-value",
691                reason: BenchmarkPassSkipReason::PlanningBudgetExceeded,
692            }]
693        );
694    }
695
696    #[test]
697    fn benchmark_pass_selection_reuses_caller_owned_candidate_scratch() {
698        let mut scratch =
699            BenchmarkPassSelectionScratch::try_with_capacity(64).expect("Fix: scratch capacity");
700        let names = [
701            "device.synthetic.00",
702            "device.synthetic.01",
703            "device.synthetic.02",
704            "device.synthetic.03",
705            "device.synthetic.04",
706            "device.synthetic.05",
707            "device.synthetic.06",
708            "device.synthetic.07",
709            "device.synthetic.08",
710            "device.synthetic.09",
711            "device.synthetic.10",
712            "device.synthetic.11",
713            "device.synthetic.12",
714            "device.synthetic.13",
715            "device.synthetic.14",
716            "device.synthetic.15",
717        ];
718        let mut wide = Vec::new();
719        wide.try_reserve_exact(names.len())
720            .expect("Fix: synthetic pass vector capacity");
721        for (index, name) in names.iter().copied().enumerate() {
722            wide.push(candidate(
723                name,
724                1,
725                1,
726                1,
727                1,
728                1,
729                11_000 + u32::try_from(index).expect("Fix: synthetic pass index fits in u32"),
730                false,
731            ));
732        }
733        let first = select_benchmark_passes_with_scratch(
734            &wide,
735            BenchmarkPassSelectionSample {
736                frontier_items: 64,
737                reuse_count: 64,
738                avoidable_readback_bytes: 64,
739                planning_budget_ns: 128,
740                scratch_budget_bytes: 128,
741            },
742            &mut scratch,
743        )
744        .expect("Fix: wide benchmark pass selection should plan with reusable scratch");
745        let seen_capacity = scratch.seen_capacity();
746        let ordered_index_capacity = scratch.ordered_index_capacity();
747
748        assert_eq!(first.selected_pass_ids.len(), names.len());
749
750        let second = select_benchmark_passes_with_scratch(
751            &[
752                candidate("device.reused.high", 1, 1, 1, 10, 8, 20_000, false),
753                candidate("device.reused.low", 1, 1, 1, 10, 8, 12_000, false),
754            ],
755            sample(),
756            &mut scratch,
757        )
758        .expect("Fix: smaller benchmark pass selection should reuse previous scratch");
759
760        assert_eq!(second.selected_pass_ids[0], "device.reused.high");
761        assert!(scratch.seen_capacity() >= seen_capacity);
762        assert!(scratch.ordered_index_capacity() >= ordered_index_capacity);
763    }
764
765    #[test]
766    fn generated_benchmark_pass_profiles_preserve_budget_priority_and_ordering_contracts() {
767        let mut scratch = BenchmarkPassSelectionScratch::default();
768        for candidate_count in 1usize..=64 {
769            for budget_multiplier in 1u64..=16 {
770                let mut candidates = Vec::new();
771                candidates
772                    .try_reserve_exact(candidate_count)
773                    .expect("Fix: generated candidate capacity");
774                for index in 0..candidate_count {
775                    let mandatory = index % 5 == 0;
776                    candidates.push(candidate(
777                        if mandatory {
778                            "device.generated.mandatory"
779                        } else {
780                            "device.generated.optional"
781                        },
782                        1,
783                        1,
784                        u64::try_from(index % 4).expect("Fix: index fits"),
785                        1 + u64::try_from(index % 3).expect("Fix: index fits"),
786                        1,
787                        11_000 + u32::try_from(index % 1_000).expect("Fix: index fits"),
788                        mandatory,
789                    ));
790                    candidates[index].pass_id = generated_pass_id(index);
791                }
792
793                let plan = select_benchmark_passes_with_scratch(
794                    &candidates,
795                    BenchmarkPassSelectionSample {
796                        frontier_items: 128,
797                        reuse_count: 128,
798                        avoidable_readback_bytes: 128,
799                        planning_budget_ns: budget_multiplier * 64,
800                        scratch_budget_bytes: budget_multiplier * 64,
801                    },
802                    &mut scratch,
803                )
804                .expect("Fix: generated benchmark pass selection profile should plan");
805
806                let mut used_planning = 0u64;
807                let mut used_scratch = 0u64;
808                for pass_id in &plan.selected_pass_ids {
809                    let candidate = candidates
810                        .iter()
811                        .find(|candidate| candidate.pass_id == *pass_id)
812                        .expect("Fix: selected pass must map to a generated candidate");
813                    used_planning += candidate.planning_cost_ns;
814                    used_scratch += candidate.scratch_bytes;
815                }
816                assert_eq!(plan.total_planning_cost_ns, used_planning);
817                assert_eq!(plan.total_scratch_bytes, used_scratch);
818                assert!(plan.total_planning_cost_ns <= budget_multiplier * 64);
819                assert!(plan.total_scratch_bytes <= budget_multiplier * 64);
820                assert!(plan.projected_speedup_bps >= 10_000);
821            }
822        }
823    }
824
825    fn generated_pass_id(index: usize) -> &'static str {
826        const IDS: [&str; 64] = [
827            "device.generated.00",
828            "device.generated.01",
829            "device.generated.02",
830            "device.generated.03",
831            "device.generated.04",
832            "device.generated.05",
833            "device.generated.06",
834            "device.generated.07",
835            "device.generated.08",
836            "device.generated.09",
837            "device.generated.10",
838            "device.generated.11",
839            "device.generated.12",
840            "device.generated.13",
841            "device.generated.14",
842            "device.generated.15",
843            "device.generated.16",
844            "device.generated.17",
845            "device.generated.18",
846            "device.generated.19",
847            "device.generated.20",
848            "device.generated.21",
849            "device.generated.22",
850            "device.generated.23",
851            "device.generated.24",
852            "device.generated.25",
853            "device.generated.26",
854            "device.generated.27",
855            "device.generated.28",
856            "device.generated.29",
857            "device.generated.30",
858            "device.generated.31",
859            "device.generated.32",
860            "device.generated.33",
861            "device.generated.34",
862            "device.generated.35",
863            "device.generated.36",
864            "device.generated.37",
865            "device.generated.38",
866            "device.generated.39",
867            "device.generated.40",
868            "device.generated.41",
869            "device.generated.42",
870            "device.generated.43",
871            "device.generated.44",
872            "device.generated.45",
873            "device.generated.46",
874            "device.generated.47",
875            "device.generated.48",
876            "device.generated.49",
877            "device.generated.50",
878            "device.generated.51",
879            "device.generated.52",
880            "device.generated.53",
881            "device.generated.54",
882            "device.generated.55",
883            "device.generated.56",
884            "device.generated.57",
885            "device.generated.58",
886            "device.generated.59",
887            "device.generated.60",
888            "device.generated.61",
889            "device.generated.62",
890            "device.generated.63",
891        ];
892        IDS[index]
893    }
894
895    fn sample() -> BenchmarkPassSelectionSample {
896        BenchmarkPassSelectionSample {
897            frontier_items: 10,
898            reuse_count: 10,
899            avoidable_readback_bytes: 10,
900            planning_budget_ns: 100,
901            scratch_budget_bytes: 100,
902        }
903    }
904
905    fn candidate(
906        pass_id: &'static str,
907        min_frontier_items: u64,
908        min_reuse_count: u64,
909        min_avoided_readback_bytes: u64,
910        planning_cost_ns: u64,
911        scratch_bytes: u64,
912        expected_speedup_bps: u32,
913        mandatory_when_profitable: bool,
914    ) -> BenchmarkPassCandidate {
915        BenchmarkPassCandidate {
916            pass_id,
917            min_frontier_items,
918            min_reuse_count,
919            min_avoided_readback_bytes,
920            planning_cost_ns,
921            scratch_bytes,
922            expected_speedup_bps,
923            mandatory_when_profitable,
924        }
925    }
926}