//! IPC message types for profiler communication. use crate::config::ProfileConfig; use crate::error::ProfilerError; use crate::results::ProfileResult; use serde::{Deserialize, Serialize}; /// Request messages from UI to backend. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ProfilerRequest { /// Initialize profiler with configuration Initialize { /// Profile configuration config: ProfileConfig, }, /// Run profiling benchmark RunProfile, /// Get current results GetResults, /// Check device availability CheckDeviceAvailability, /// Reset profiler state Reset, } /// Response messages from backend to UI. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ProfilerResponse { /// Initialization successful InitializeSuccess, /// Profiling in progress ProfilingProgress { /// Current batch size index batch_index: usize, /// Total number of batches total_batches: usize, /// Current iteration iteration: usize, /// Total iterations for this batch total_iterations: usize, }, /// Profiling completed ProfilingComplete { /// All profile results results: Vec, }, /// Results response Results { /// Profile results results: Vec, }, /// Device availability status DeviceAvailability { /// Available devices available_devices: Vec, }, /// Reset successful ResetSuccess, /// Error occurred Error { /// Error details error: ProfilerError, }, } #[cfg(test)] mod tests { use super::*; use crate::config::{DeviceType, ModelType}; use crate::metrics::{LatencyMetrics, MemoryMetrics, ThroughputMetrics}; #[test] fn test_profiler_request_initialize_serialization() { let config = ProfileConfig::default(); let request = ProfilerRequest::Initialize { config: config.clone(), }; let json = serde_json::to_string(&request).expect("serialization failed"); assert!(json.contains("\"type\"")); assert!(json.contains("\"initialize\"")); assert!(json.contains("\"config\"")); } #[test] fn test_profiler_request_run_profile_serialization() { let request = ProfilerRequest::RunProfile; let json = serde_json::to_string(&request).expect("serialization failed"); assert!(json.contains("\"run-profile\"")); } #[test] fn test_profiler_request_get_results_serialization() { let request = ProfilerRequest::GetResults; let json = serde_json::to_string(&request).expect("serialization failed"); assert!(json.contains("\"get-results\"")); } #[test] fn test_profiler_request_check_device_serialization() { let request = ProfilerRequest::CheckDeviceAvailability; let json = serde_json::to_string(&request).expect("serialization failed"); assert!(json.contains("\"check-device-availability\"")); } #[test] fn test_profiler_request_reset_serialization() { let request = ProfilerRequest::Reset; let json = serde_json::to_string(&request).expect("serialization failed"); assert!(json.contains("\"reset\"")); } #[test] fn test_profiler_request_deserialization() { let json = r#"{"type":"run-profile"}"#; let request: ProfilerRequest = serde_json::from_str(json).expect("deserialization failed"); match request { ProfilerRequest::RunProfile => {} _ => panic!("wrong request variant"), } } #[test] fn test_profiler_request_initialize_deserialization() { let json = r#"{ "type": "initialize", "config": { "model_type": "resnet18", "device": "CPU", "batch_sizes": [1, 2, 4], "warmup_iterations": 10, "benchmark_iterations": 100, "input_shape": { "channels": 3, "height": 224, "width": 224 } } }"#; let request: ProfilerRequest = serde_json::from_str(json).expect("deserialization failed"); match request { ProfilerRequest::Initialize { config } => { assert_eq!(config.model_type, ModelType::ResNet18); assert_eq!(config.device, DeviceType::CPU); } _ => panic!("wrong request variant"), } } #[test] fn test_profiler_request_roundtrip() { let requests = vec![ ProfilerRequest::Initialize { config: ProfileConfig::default(), }, ProfilerRequest::RunProfile, ProfilerRequest::GetResults, ProfilerRequest::CheckDeviceAvailability, ProfilerRequest::Reset, ]; for request in requests { let json = serde_json::to_string(&request).expect("serialization failed"); let decoded: ProfilerRequest = serde_json::from_str(&json).expect("deserialization failed"); assert_eq!(request, decoded); } } #[test] fn test_profiler_response_initialize_success_serialization() { let response = ProfilerResponse::InitializeSuccess; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"initialize-success\"")); } #[test] fn test_profiler_response_profiling_progress_serialization() { let response = ProfilerResponse::ProfilingProgress { batch_index: 2, total_batches: 5, iteration: 50, total_iterations: 100, }; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"profiling-progress\"")); assert!(json.contains("\"batch_index\"")); assert!(json.contains("\"total_batches\"")); } #[test] fn test_profiler_response_profiling_complete_serialization() { let latency = LatencyMetrics::from_measurements(&[10.0, 20.0]).unwrap(); let memory = MemoryMetrics::new(100.0, 80.0, 120.0).unwrap(); let throughput = ThroughputMetrics::new(50.0, None).unwrap(); let result = ProfileResult::new( ModelType::ResNet18, DeviceType::CPU, 8, latency, memory, throughput, 1234567890, ); let response = ProfilerResponse::ProfilingComplete { results: vec![result], }; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"profiling-complete\"")); assert!(json.contains("\"results\"")); } #[test] fn test_profiler_response_results_serialization() { let response = ProfilerResponse::Results { results: vec![] }; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"results\"")); } #[test] fn test_profiler_response_device_availability_serialization() { let response = ProfilerResponse::DeviceAvailability { available_devices: vec!["CPU".to_string(), "CUDA".to_string()], }; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"device-availability\"")); assert!(json.contains("\"available_devices\"")); } #[test] fn test_profiler_response_reset_success_serialization() { let response = ProfilerResponse::ResetSuccess; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"reset-success\"")); } #[test] fn test_profiler_response_error_serialization() { let response = ProfilerResponse::Error { error: ProfilerError::DeviceUnavailable("CUDA not found".to_string()), }; let json = serde_json::to_string(&response).expect("serialization failed"); assert!(json.contains("\"error\"")); } #[test] fn test_profiler_response_deserialization() { let json = r#"{"type":"initialize-success"}"#; let response: ProfilerResponse = serde_json::from_str(json).expect("deserialization failed"); match response { ProfilerResponse::InitializeSuccess => {} _ => panic!("wrong response variant"), } } #[test] fn test_profiler_response_progress_deserialization() { let json = r#"{ "type": "profiling-progress", "batch_index": 3, "total_batches": 8, "iteration": 75, "total_iterations": 100 }"#; let response: ProfilerResponse = serde_json::from_str(json).expect("deserialization failed"); match response { ProfilerResponse::ProfilingProgress { batch_index, total_batches, iteration, total_iterations, } => { assert_eq!(batch_index, 3); assert_eq!(total_batches, 8); assert_eq!(iteration, 75); assert_eq!(total_iterations, 100); } _ => panic!("wrong response variant"), } } #[test] fn test_profiler_response_roundtrip() { let responses = vec![ ProfilerResponse::InitializeSuccess, ProfilerResponse::ProfilingProgress { batch_index: 1, total_batches: 4, iteration: 50, total_iterations: 100, }, ProfilerResponse::Results { results: vec![] }, ProfilerResponse::DeviceAvailability { available_devices: vec!["CPU".to_string()], }, ProfilerResponse::ResetSuccess, ProfilerResponse::Error { error: ProfilerError::ConfigError("test".to_string()), }, ]; for response in responses { let json = serde_json::to_string(&response).expect("serialization failed"); let decoded: ProfilerResponse = serde_json::from_str(&json).expect("deserialization failed"); assert_eq!(response, decoded); } } }