use std::collections::HashMap;
pub mod compute_intensive;
pub mod io_intensive;
pub mod memory_intensive;
pub mod concurrent;
pub mod ai_workload;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use super::{BenchmarkError, BenchmarkResult, BenchmarkResult as Result};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum WorkloadType {
ComputeIntensive,
IoIntensive,
MemoryIntensive,
Concurrent,
AiWorkload,
Mixed,
}
#[derive(Debug)]
pub struct WorkloadExecutor {
pub workload_type: WorkloadType,
pub parameters: HashMap<String, serde_json::Value>>,
pub concurrency: u32,
pub duration: Option<Duration>,
pub iterations: Option<u32>,
}
impl WorkloadExecutor {
pub fn new(workload_type: WorkloadType) -> Self {
Self {
workload_type,
parameters: HashMap::new(),
concurrency: 1,
duration: None,
iterations: None,
}
}
pub fn parameters(mut self, parameters: HashMap<String, serde_json::Value>) -> Self {
self.parameters = parameters;
self
}
pub fn add_parameter(mut self, key: &str, value: serde_json::Value) -> Self {
self.parameters.insert(key.to_string(), value);
self
}
pub fn concurrency(mut self, concurrency: u32) -> Self {
self.concurrency = concurrency;
self
}
pub fn duration(mut self, duration: Duration) -> Self {
self.duration = Some(duration);
self
}
pub fn iterations(mut self, iterations: u32) -> Self {
self.iterations = Some(iterations);
self
}
pub async fn execute(&self) -> Result<WorkloadResult> {
match self.workload_type {
WorkloadType::ComputeIntensive => {
self.execute_compute_intensive().await
}
WorkloadType::IoIntensive => {
self.execute_io_intensive().await
}
WorkloadType::MemoryIntensive => {
self.execute_memory_intensive().await
}
WorkloadType::Concurrent => {
self.execute_concurrent().await
}
WorkloadType::AiWorkload => {
self.execute_ai_workload().await
}
WorkloadType::Mixed => {
self.execute_mixed().await
}
}
}
async fn execute_compute_intensive(&self) -> Result<WorkloadResult> {
let compute_workload: _ = compute_intensive::ComputeWorkload::new();
compute_workload.execute(self.parameters.clone(), self.concurrency).await
}
async fn execute_io_intensive(&self) -> Result<WorkloadResult> {
let io_workload: _ = io_intensive::IOWorkload::new();
io_workload.execute(self.parameters.clone(), self.concurrency).await
}
async fn execute_memory_intensive(&self) -> Result<WorkloadResult> {
let memory_workload: _ = memory_intensive::MemoryWorkload::new();
memory_workload.execute(self.parameters.clone(), self.concurrency).await
}
async fn execute_concurrent(&self) -> Result<WorkloadResult> {
let concurrent_workload: _ = concurrent::ConcurrentWorkload::new();
concurrent_workload.execute(self.parameters.clone(), self.concurrency).await
}
async fn execute_ai_workload(&self) -> Result<WorkloadResult> {
let ai_workload: _ = ai_workload::AIWorkload::new();
ai_workload.execute(self.parameters.clone(), self.concurrency).await
}
async fn execute_mixed(&self) -> Result<WorkloadResult> {
let mut results = Vec::new();
let workloads: _ = vec![
WorkloadType::ComputeIntensive,
WorkloadType::IoIntensive,
WorkloadType::MemoryIntensive,
];
for workload_type in workloads {
let executor: _ = WorkloadExecutor::new(workload_type)
.parameters(self.parameters.clone())
.concurrency(self.concurrency);
let result: _ = executor.execute().await?;
results.push(result);
}
Ok(WorkloadResult::merge(results))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkloadResult {
pub workload_type: WorkloadType,
pub start_time: Instant,
pub end_time: Instant,
pub total_duration: Duration,
pub iterations: u32,
pub throughput: f64,
pub resource_usage: ResourceUsage,
pub custom_metrics: HashMap<String, serde_json::Value>>,
pub error: Option<String>,
pub success: bool,
}
impl WorkloadResult {
pub fn new(workload_type: WorkloadType) -> Self {
Self {
workload_type,
start_time: Instant::now(),
end_time: Instant::now(),
total_duration: Duration::from_secs(0),
iterations: 0,
throughput: 0.0,
resource_usage: ResourceUsage::default(),
custom_metrics: HashMap::new(),
error: None,
success: false,
}
}
pub fn start(&mut self) {
self.start_time = Instant::now();
}
pub fn finish(&mut self, iterations: u32) {
self.end_time = Instant::now();
self.total_duration = self.end_time.duration_since(self.start_time);
self.iterations = iterations;
self.throughput = if self.total_duration.as_secs_f64() > 0.0 {
iterations as f64 / self.total_duration.as_secs_f64()
} else {
0.0
};
self.success = self.error.is_none();
}
pub fn add_error(&mut self, error: &str) {
self.error = Some(error.to_string());
}
pub fn add_metric(&mut self, key: &str, value: serde_json::Value) {
self.custom_metrics.insert(key.to_string(), value);
}
pub fn resource_usage(mut self, usage: ResourceUsage) -> Self {
self.resource_usage = usage;
self
}
pub fn merge(results: Vec<Self>) -> Self {
if results.is_empty() {
panic!("Cannot merge empty results");
}
let workload_type: _ = results[0].workload_type;
let start_time: _ = results.iter().map(|r| r.start_time).min().unwrap();
let end_time: _ = results.iter().map(|r| r.end_time).max().unwrap();
let total_duration: _ = end_time.duration_since(start_time);
let total_iterations: u32 = results.iter().map(|r| r.iterations).sum();
let total_throughput: f64 = results.iter().map(|r| r.throughput).sum();
Self {
workload_type,
start_time,
end_time,
total_duration,
iterations: total_iterations,
throughput: total_throughput,
resource_usage: ResourceUsage::merge(results.iter().map(|r| &r.resource_usage).collect()),
custom_metrics: results[0].custom_metrics.clone(),
error: None,
success: results.iter().all(|r| r.success),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ResourceUsage {
pub cpu_usage_percent: f64,
pub memory_usage_bytes: u64,
pub memory_peak_bytes: u64,
pub io_operations: u64,
pub network_bytes: u64,
pub file_descriptors: u32,
pub thread_count: u32,
}
impl ResourceUsage {
pub fn new() -> Self {
Self::default()
}
pub fn cpu_usage(mut self, usage: f64) -> Self {
self.cpu_usage_percent = usage;
self
}
pub fn memory_usage(mut self, usage: u64) -> Self {
self.memory_usage_bytes = usage;
self
}
pub fn memory_peak(mut self, peak: u64) -> Self {
self.memory_peak_bytes = peak;
self
}
pub fn io_operations(mut self, operations: u64) -> Self {
self.io_operations = operations;
self
}
pub fn network_bytes(mut self, bytes: u64) -> Self {
self.network_bytes = bytes;
self
}
pub fn file_descriptors(mut self, fds: u32) -> Self {
self.file_descriptors = fds;
self
}
pub fn thread_count(mut self, count: u32) -> Self {
self.thread_count = count;
self
}
pub fn merge(usages: Vec<&Self>) -> Self {
if usages.is_empty() {
return Self::default();
}
let mut merged = Self::new();
merged.cpu_usage_percent = usages.iter()
.map(|u| u.cpu_usage_percent)
.sum::<f64>() / usages.len() as f64;
merged.memory_usage_bytes = usages.iter()
.map(|u| u.memory_usage_bytes)
.max()
.unwrap_or(0);
merged.memory_peak_bytes = usages.iter()
.map(|u| u.memory_peak_bytes)
.max()
.unwrap_or(0);
merged.io_operations = usages.iter()
.map(|u| u.io_operations)
.sum();
merged.network_bytes = usages.iter()
.map(|u| u.network_bytes)
.sum();
merged.file_descriptors = usages.iter()
.map(|u| u.file_descriptors)
.max()
.unwrap_or(0);
merged.thread_count = usages.iter()
.map(|u| u.thread_count)
.max()
.unwrap_or(0);
merged
}
}