327 lines
10 KiB
Rust
327 lines
10 KiB
Rust
//! 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<ProfileResult>,
|
|
},
|
|
/// Results response
|
|
Results {
|
|
/// Profile results
|
|
results: Vec<ProfileResult>,
|
|
},
|
|
/// Device availability status
|
|
DeviceAvailability {
|
|
/// Available devices
|
|
available_devices: Vec<String>,
|
|
},
|
|
/// 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);
|
|
}
|
|
}
|
|
}
|