1use 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#[derive(Clone, Copy, Debug, Eq, PartialEq)]
24pub struct BenchmarkPassCandidate {
25 pub pass_id: &'static str,
27 pub min_frontier_items: u64,
29 pub min_reuse_count: u64,
31 pub min_avoided_readback_bytes: u64,
33 pub planning_cost_ns: u64,
35 pub scratch_bytes: u64,
37 pub expected_speedup_bps: u32,
39 pub mandatory_when_profitable: bool,
41}
42
43#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub struct BenchmarkPassSelectionSample {
46 pub frontier_items: u64,
48 pub reuse_count: u64,
50 pub avoidable_readback_bytes: u64,
52 pub planning_budget_ns: u64,
54 pub scratch_budget_bytes: u64,
56}
57
58#[derive(Clone, Debug, Eq, PartialEq)]
60pub struct SkippedBenchmarkPass {
61 pub pass_id: &'static str,
63 pub reason: BenchmarkPassSkipReason,
65}
66
67#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub enum BenchmarkPassSkipReason {
70 FrontierBelowThreshold,
72 ReuseBelowThreshold,
74 ReadbackBelowThreshold,
76 PlanningBudgetExceeded,
78 ScratchBudgetExceeded,
80}
81
82#[derive(Clone, Debug, Eq, PartialEq)]
84pub struct BenchmarkPassSelectionPlan {
85 pub selected_pass_ids: Vec<&'static str>,
87 pub skipped_passes: Vec<SkippedBenchmarkPass>,
89 pub total_planning_cost_ns: u64,
91 pub total_scratch_bytes: u64,
93 pub projected_speedup_bps: u64,
95}
96
97#[derive(Debug, Default)]
99pub struct BenchmarkPassSelectionScratch {
100 index_scratch: ReusableIndexScratch<&'static str>,
101}
102
103impl BenchmarkPassSelectionScratch {
104 #[must_use]
106 pub fn new() -> Self {
107 Self::default()
108 }
109
110 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 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 #[must_use]
141 pub fn seen_capacity(&self) -> usize {
142 self.index_scratch.seen_capacity()
143 }
144
145 #[must_use]
147 pub fn ordered_index_capacity(&self) -> usize {
148 self.index_scratch.ordered_index_capacity()
149 }
150}
151
152#[derive(Clone, Debug, Eq, PartialEq)]
154pub enum BenchmarkPassSelectionError {
155 EmptyPassId,
157 DuplicatePassId {
159 pass_id: &'static str,
161 },
162 MissingSpeedupEvidence {
164 pass_id: &'static str,
166 },
167 MandatoryProfitablePassOverBudget {
169 pass_id: &'static str,
171 reason: BenchmarkPassSkipReason,
173 },
174 CountOverflow {
176 field: &'static str,
178 },
179 StorageReserveFailed {
181 field: &'static str,
183 requested: usize,
185 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
233pub 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
248pub 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_avoids_tree_sets_and_candidate_vector_copies() {
698 let src = include_str!("benchmark_pass_selection.rs");
699 assert!(
700 !src.contains(concat!("BTree", "Set")),
701 "Fix: benchmark pass selection should hash pass ids and sort candidate indices by value."
702 );
703 assert!(
704 !src.contains(concat!("candidates", ".to_vec()")),
705 "Fix: benchmark pass selection should not copy all candidates before value ordering."
706 );
707 assert!(
708 src.contains("BenchmarkPassSelectionScratch::try_with_capacity(candidates.len())?"),
709 "Fix: benchmark pass selection must stage scratch with fallible release-path allocation."
710 );
711 assert!(
712 src.contains("scratch.try_reserve_candidates(candidates.len())?"),
713 "Fix: caller-owned benchmark pass-selection scratch must grow through fallible reservation."
714 );
715 assert!(
716 src.contains("ReusableIndexScratch"),
717 "Fix: benchmark pass-selection duplicate detection and ordering scratch must share the paired typed fallible reservation helper."
718 );
719 assert!(
720 src.contains("StorageReserveFailed"),
721 "Fix: benchmark pass-selection allocation failures must surface as actionable planning errors."
722 );
723 assert!(
724 !src.contains(concat!("FxHashSet::with_capacity", "_and_hasher")),
725 "Fix: benchmark pass-selection scratch hash storage must not allocate infallibly."
726 );
727 assert!(
728 !src.contains(concat!("Vec::with_capacity", "(candidate_count)"))
729 && !src.contains(concat!("Vec::with_capacity", "(candidates.len())")),
730 "Fix: benchmark pass-selection scratch/result vectors must not allocate infallibly."
731 );
732 }
733
734 #[test]
735 fn benchmark_pass_selection_reuses_caller_owned_candidate_scratch() {
736 let mut scratch =
737 BenchmarkPassSelectionScratch::try_with_capacity(64).expect("Fix: scratch capacity");
738 let names = [
739 "device.synthetic.00",
740 "device.synthetic.01",
741 "device.synthetic.02",
742 "device.synthetic.03",
743 "device.synthetic.04",
744 "device.synthetic.05",
745 "device.synthetic.06",
746 "device.synthetic.07",
747 "device.synthetic.08",
748 "device.synthetic.09",
749 "device.synthetic.10",
750 "device.synthetic.11",
751 "device.synthetic.12",
752 "device.synthetic.13",
753 "device.synthetic.14",
754 "device.synthetic.15",
755 ];
756 let mut wide = Vec::new();
757 wide.try_reserve_exact(names.len())
758 .expect("Fix: synthetic pass vector capacity");
759 for (index, name) in names.iter().copied().enumerate() {
760 wide.push(candidate(
761 name,
762 1,
763 1,
764 1,
765 1,
766 1,
767 11_000 + u32::try_from(index).expect("Fix: synthetic pass index fits in u32"),
768 false,
769 ));
770 }
771 let first = select_benchmark_passes_with_scratch(
772 &wide,
773 BenchmarkPassSelectionSample {
774 frontier_items: 64,
775 reuse_count: 64,
776 avoidable_readback_bytes: 64,
777 planning_budget_ns: 128,
778 scratch_budget_bytes: 128,
779 },
780 &mut scratch,
781 )
782 .expect("Fix: wide benchmark pass selection should plan with reusable scratch");
783 let seen_capacity = scratch.seen_capacity();
784 let ordered_index_capacity = scratch.ordered_index_capacity();
785
786 assert_eq!(first.selected_pass_ids.len(), names.len());
787
788 let second = select_benchmark_passes_with_scratch(
789 &[
790 candidate("device.reused.high", 1, 1, 1, 10, 8, 20_000, false),
791 candidate("device.reused.low", 1, 1, 1, 10, 8, 12_000, false),
792 ],
793 sample(),
794 &mut scratch,
795 )
796 .expect("Fix: smaller benchmark pass selection should reuse previous scratch");
797
798 assert_eq!(second.selected_pass_ids[0], "device.reused.high");
799 assert!(scratch.seen_capacity() >= seen_capacity);
800 assert!(scratch.ordered_index_capacity() >= ordered_index_capacity);
801 }
802
803 #[test]
804 fn generated_benchmark_pass_profiles_preserve_budget_priority_and_ordering_contracts() {
805 let mut scratch = BenchmarkPassSelectionScratch::default();
806 for candidate_count in 1usize..=64 {
807 for budget_multiplier in 1u64..=16 {
808 let mut candidates = Vec::new();
809 candidates
810 .try_reserve_exact(candidate_count)
811 .expect("Fix: generated candidate capacity");
812 for index in 0..candidate_count {
813 let mandatory = index % 5 == 0;
814 candidates.push(candidate(
815 if mandatory {
816 "device.generated.mandatory"
817 } else {
818 "device.generated.optional"
819 },
820 1,
821 1,
822 u64::try_from(index % 4).expect("Fix: index fits"),
823 1 + u64::try_from(index % 3).expect("Fix: index fits"),
824 1,
825 11_000 + u32::try_from(index % 1_000).expect("Fix: index fits"),
826 mandatory,
827 ));
828 candidates[index].pass_id = generated_pass_id(index);
829 }
830
831 let plan = select_benchmark_passes_with_scratch(
832 &candidates,
833 BenchmarkPassSelectionSample {
834 frontier_items: 128,
835 reuse_count: 128,
836 avoidable_readback_bytes: 128,
837 planning_budget_ns: budget_multiplier * 64,
838 scratch_budget_bytes: budget_multiplier * 64,
839 },
840 &mut scratch,
841 )
842 .expect("Fix: generated benchmark pass selection profile should plan");
843
844 let mut used_planning = 0u64;
845 let mut used_scratch = 0u64;
846 for pass_id in &plan.selected_pass_ids {
847 let candidate = candidates
848 .iter()
849 .find(|candidate| candidate.pass_id == *pass_id)
850 .expect("Fix: selected pass must map to a generated candidate");
851 used_planning += candidate.planning_cost_ns;
852 used_scratch += candidate.scratch_bytes;
853 }
854 assert_eq!(plan.total_planning_cost_ns, used_planning);
855 assert_eq!(plan.total_scratch_bytes, used_scratch);
856 assert!(plan.total_planning_cost_ns <= budget_multiplier * 64);
857 assert!(plan.total_scratch_bytes <= budget_multiplier * 64);
858 assert!(plan.projected_speedup_bps >= 10_000);
859 }
860 }
861 }
862
863 fn generated_pass_id(index: usize) -> &'static str {
864 const IDS: [&str; 64] = [
865 "device.generated.00",
866 "device.generated.01",
867 "device.generated.02",
868 "device.generated.03",
869 "device.generated.04",
870 "device.generated.05",
871 "device.generated.06",
872 "device.generated.07",
873 "device.generated.08",
874 "device.generated.09",
875 "device.generated.10",
876 "device.generated.11",
877 "device.generated.12",
878 "device.generated.13",
879 "device.generated.14",
880 "device.generated.15",
881 "device.generated.16",
882 "device.generated.17",
883 "device.generated.18",
884 "device.generated.19",
885 "device.generated.20",
886 "device.generated.21",
887 "device.generated.22",
888 "device.generated.23",
889 "device.generated.24",
890 "device.generated.25",
891 "device.generated.26",
892 "device.generated.27",
893 "device.generated.28",
894 "device.generated.29",
895 "device.generated.30",
896 "device.generated.31",
897 "device.generated.32",
898 "device.generated.33",
899 "device.generated.34",
900 "device.generated.35",
901 "device.generated.36",
902 "device.generated.37",
903 "device.generated.38",
904 "device.generated.39",
905 "device.generated.40",
906 "device.generated.41",
907 "device.generated.42",
908 "device.generated.43",
909 "device.generated.44",
910 "device.generated.45",
911 "device.generated.46",
912 "device.generated.47",
913 "device.generated.48",
914 "device.generated.49",
915 "device.generated.50",
916 "device.generated.51",
917 "device.generated.52",
918 "device.generated.53",
919 "device.generated.54",
920 "device.generated.55",
921 "device.generated.56",
922 "device.generated.57",
923 "device.generated.58",
924 "device.generated.59",
925 "device.generated.60",
926 "device.generated.61",
927 "device.generated.62",
928 "device.generated.63",
929 ];
930 IDS[index]
931 }
932
933 fn sample() -> BenchmarkPassSelectionSample {
934 BenchmarkPassSelectionSample {
935 frontier_items: 10,
936 reuse_count: 10,
937 avoidable_readback_bytes: 10,
938 planning_budget_ns: 100,
939 scratch_budget_bytes: 100,
940 }
941 }
942
943 fn candidate(
944 pass_id: &'static str,
945 min_frontier_items: u64,
946 min_reuse_count: u64,
947 min_avoided_readback_bytes: u64,
948 planning_cost_ns: u64,
949 scratch_bytes: u64,
950 expected_speedup_bps: u32,
951 mandatory_when_profitable: bool,
952 ) -> BenchmarkPassCandidate {
953 BenchmarkPassCandidate {
954 pass_id,
955 min_frontier_items,
956 min_reuse_count,
957 min_avoided_readback_bytes,
958 planning_cost_ns,
959 scratch_bytes,
960 expected_speedup_bps,
961 mandatory_when_profitable,
962 }
963 }
964}