//! Sweep presets — named workload sets + sweep params for the TUI's //! picker screen + the `--preset` CLI arg. Each builder returns a //! `Config` ready to hand to `Run::new`. //! //! Three presets: //! - `stability` — stress-ng-cpu → y-cruncher-sse → y-cruncher-avx2, //! 5 min (300s) each, all cores, 15s cooldown, looped to fill ~1 hour //! (4 loops ≈ 49 min, 5 loops ≈ 61 min — we pick 5 to hit the target). //! - `stability_core_cycle` — the same three workloads, but run on ONE //! logical core at a time (cycling through all 16 twice), shorter //! per-core duration (default 60s). Used to test peak single-core //! clocks on chips with per-core load-based multipliers. //! - `bench` — 7zip-bench → y-cruncher-sse → y-cruncher-avx2, 60s each, //! all cores, 15s cooldown, single pass (the scores are the point; //! looping doesn't improve the measurement). use crate::config::{Config, WorkloadSpec}; /// Workload names available in v1 (the from_spec match arms in workload.rs). /// The custom editor iterates this list for its toggle rows. pub const AVAILABLE_WORKLOADS: &[&str] = &[ "stress-ng-cpu", "y-cruncher-sse", "y-cruncher-avx2", "7zip-bench", ]; /// Cores range options for the custom editor's per-workload cores field. /// P = performance cores only, E = efficiency cores only, All = both. /// (Reserved for the editor's cores-field cycling; not yet wired into /// the TUI's cores edit — the editor currently accepts free-text cores /// input via the numeric/string edit buffer.) #[allow(dead_code)] pub const CORES_OPTIONS: &[&str] = &["0-15", "0-11", "12-15"]; fn spec(name: &str, duration_secs: u64, cores: &str) -> WorkloadSpec { WorkloadSpec { name: name.to_string(), duration_secs, cores: cores.to_string(), } } /// Stability preset: cycle the three ISA-rail stress tests, 5 min each, /// all cores, 15s cooldown, looped to fill ~1 hour. 4 loops = 49 min, /// 5 loops = 61 min — pick 5 to cross the hour. Cancelable mid-run /// (q in the TUI) so the user isn't committed to the full hour. pub fn stability() -> Config { Config { workloads: vec![ spec("stress-ng-cpu", 300, "0-15"), spec("y-cruncher-sse", 300, "0-15"), spec("y-cruncher-avx2", 300, "0-15"), ], cool_secs: 15, loop_count: 5, ..Config::default() } } /// Stability core-cycle preset: the same three workloads, but run on /// ONE logical core at a time. Cycles through all 16 logical cores /// twice. The `per_core_secs` arg sets the per-workload-per-core run /// length (default 60s). Total run time ≈ 16 cores × 2 passes × 3 /// workloads × per_core_secs + cooldowns. Long, but cancelable. /// /// This tests peak single-core clocks on chips with per-core load-based /// multipliers — the question is whether each individual core is stable /// at its own peak clock, not just whether the package is stable at the /// all-core clock. pub fn stability_core_cycle(per_core_secs: u64) -> Config { let mut workloads: Vec = Vec::new(); // Two full passes across all 16 logical cores (0-15). for pass in 0..2u32 { for cpu in 0..16u32 { // Three ISA rails, each on this single core. for name in ["stress-ng-cpu", "y-cruncher-sse", "y-cruncher-avx2"] { workloads.push(spec(name, per_core_secs, &cpu.to_string())); } } let _ = pass; // pass count is the loop bound, not a body var } Config { workloads, cool_secs: 5, // shorter cooldown — single-core load doesn't heat the package loop_count: 1, // the core-cycle IS the loop; don't loop the whole thing ..Config::default() } } /// Bench preset: the three score-producing workloads, 60s each, all /// cores, 15s cooldown, single pass. The scores (7z rating MIPS, /// y-cruncher FFTv4 Gb/s) are the comparative-perf signal across OC /// configs. pub fn bench() -> Config { Config { workloads: vec![ spec("7zip-bench", 60, "0-15"), spec("y-cruncher-sse", 60, "0-15"), spec("y-cruncher-avx2", 60, "0-15"), ], cool_secs: 15, loop_count: 1, ..Config::default() } } #[cfg(test)] mod tests { use super::*; #[test] fn stability_has_three_rails_five_loops() { let cfg = stability(); assert_eq!(cfg.workloads.len(), 3); assert_eq!(cfg.workloads[0].name, "stress-ng-cpu"); assert_eq!(cfg.workloads[1].name, "y-cruncher-sse"); assert_eq!(cfg.workloads[2].name, "y-cruncher-avx2"); assert_eq!(cfg.workloads[0].duration_secs, 300); assert_eq!(cfg.cool_secs, 15); assert_eq!(cfg.loop_count, 5); } #[test] fn stability_core_cycle_visits_each_core_twice() { let cfg = stability_core_cycle(60); // 16 cores × 2 passes × 3 workloads = 96 entries. assert_eq!(cfg.workloads.len(), 96); // First three are cpu0 (stress-ng, sse, avx2). assert_eq!(cfg.workloads[0].name, "stress-ng-cpu"); assert_eq!(cfg.workloads[0].cores, "0"); assert_eq!(cfg.workloads[1].name, "y-cruncher-sse"); assert_eq!(cfg.workloads[1].cores, "0"); assert_eq!(cfg.workloads[2].name, "y-cruncher-avx2"); assert_eq!(cfg.workloads[2].cores, "0"); // Last three are cpu15 on the second pass. let last = &cfg.workloads[95]; assert_eq!(last.name, "y-cruncher-avx2"); assert_eq!(last.cores, "15"); // All single-core (no "0-15" range anywhere). assert!(cfg.workloads.iter().all(|w| w.cores != "0-15")); assert_eq!(cfg.loop_count, 1); } #[test] fn stability_core_cycle_custom_duration() { let cfg = stability_core_cycle(30); assert_eq!(cfg.workloads[0].duration_secs, 30); } #[test] fn bench_has_three_scored_workloads_single_pass() { let cfg = bench(); assert_eq!(cfg.workloads.len(), 3); assert_eq!(cfg.workloads[0].name, "7zip-bench"); assert_eq!(cfg.workloads[1].name, "y-cruncher-sse"); assert_eq!(cfg.workloads[2].name, "y-cruncher-avx2"); assert_eq!(cfg.workloads[0].duration_secs, 60); assert_eq!(cfg.loop_count, 1); } #[test] fn available_workloads_lists_v1_impls() { assert!(AVAILABLE_WORKLOADS.contains(&"stress-ng-cpu")); assert!(AVAILABLE_WORKLOADS.contains(&"y-cruncher-sse")); assert!(AVAILABLE_WORKLOADS.contains(&"y-cruncher-avx2")); assert!(AVAILABLE_WORKLOADS.contains(&"7zip-bench")); // Deferred impls NOT in the list (c2c/dram/minecraft). assert!(!AVAILABLE_WORKLOADS.contains(&"c2c-latency")); } }