use std::time::Duration;
use super::super::device::DeviceId;
#[derive(Debug, Clone)]
pub struct StressTestConfig {
pub target: StressTarget,
pub duration: Duration,
pub intensity: f64,
pub ramp_up: Duration,
pub chaos_preset: Option<ChaosPreset>,
pub collect_metrics: bool,
pub export_report: bool,
}
impl Default for StressTestConfig {
fn default() -> Self {
Self {
target: StressTarget::All,
duration: Duration::from_secs(60),
intensity: 1.0,
ramp_up: Duration::from_secs(5),
chaos_preset: None,
collect_metrics: true,
export_report: true,
}
}
}
impl StressTestConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_target(mut self, target: StressTarget) -> Self {
self.target = target;
self
}
#[must_use]
pub fn with_duration(mut self, duration: Duration) -> Self {
self.duration = duration;
self
}
#[must_use]
pub fn with_intensity(mut self, intensity: f64) -> Self {
self.intensity = intensity.clamp(0.0, 1.0);
self
}
#[must_use]
pub fn with_ramp_up(mut self, ramp_up: Duration) -> Self {
self.ramp_up = ramp_up;
self
}
#[must_use]
pub fn with_chaos(mut self, preset: ChaosPreset) -> Self {
self.chaos_preset = Some(preset);
self
}
#[must_use]
pub fn parse_duration(s: &str) -> Option<Duration> {
let s = s.trim();
if s.is_empty() {
return None;
}
let (num, unit) = s.split_at(s.len() - 1);
let value: u64 = num.parse().ok()?;
match unit {
"s" => Some(Duration::from_secs(value)),
"m" => Some(Duration::from_secs(value * 60)),
"h" => Some(Duration::from_secs(value * 3600)),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum StressTarget {
All,
Cpu,
Gpu(Option<DeviceId>),
Memory,
Pcie,
Custom(Vec<StressTarget>),
}
impl StressTarget {
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
let s = s.trim().to_lowercase();
if s == "all" {
return Some(Self::All);
}
if s == "cpu" {
return Some(Self::Cpu);
}
if s == "memory" {
return Some(Self::Memory);
}
if s == "pcie" {
return Some(Self::Pcie);
}
if s == "gpu" {
return Some(Self::Gpu(None));
}
if let Some(idx_str) = s.strip_prefix("gpu:") {
let idx: u32 = idx_str.parse().ok()?;
return Some(Self::Gpu(Some(DeviceId::nvidia(idx))));
}
None
}
#[must_use]
pub fn includes_cpu(&self) -> bool {
match self {
Self::All | Self::Cpu => true,
Self::Custom(targets) => targets.iter().any(|t| t.includes_cpu()),
_ => false,
}
}
#[must_use]
pub fn includes_gpu(&self) -> bool {
match self {
Self::All | Self::Gpu(_) => true,
Self::Custom(targets) => targets.iter().any(|t| t.includes_gpu()),
_ => false,
}
}
#[must_use]
pub fn includes_memory(&self) -> bool {
match self {
Self::All | Self::Memory => true,
Self::Custom(targets) => targets.iter().any(|t| t.includes_memory()),
_ => false,
}
}
#[must_use]
pub fn includes_pcie(&self) -> bool {
match self {
Self::All | Self::Pcie => true,
Self::Custom(targets) => targets.iter().any(|t| t.includes_pcie()),
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChaosPreset {
Gentle,
Moderate,
Aggressive,
Extreme,
}
impl ChaosPreset {
#[must_use]
pub fn parse(s: &str) -> Option<Self> {
match s.trim().to_lowercase().as_str() {
"gentle" => Some(Self::Gentle),
"moderate" => Some(Self::Moderate),
"aggressive" => Some(Self::Aggressive),
"extreme" => Some(Self::Extreme),
_ => None,
}
}
#[must_use]
pub fn memory_limit_factor(&self) -> f64 {
match self {
Self::Gentle => 0.9, Self::Moderate => 0.75, Self::Aggressive => 0.5, Self::Extreme => 0.25, }
}
#[must_use]
pub fn cpu_throttle_factor(&self) -> f64 {
match self {
Self::Gentle => 1.0, Self::Moderate => 0.9, Self::Aggressive => 0.7, Self::Extreme => 0.5, }
}
#[must_use]
pub fn network_latency_ms(&self) -> u32 {
match self {
Self::Gentle => 0,
Self::Moderate => 10,
Self::Aggressive => 50,
Self::Extreme => 200,
}
}
#[must_use]
pub fn failure_rate(&self) -> f64 {
match self {
Self::Gentle => 0.0,
Self::Moderate => 0.01,
Self::Aggressive => 0.05,
Self::Extreme => 0.10,
}
}
}