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_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}