use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ProcessingStrategy {
CPU(RayonConfig),
GPU(ComputeConfig),
Streaming(StreamConfig),
Hybrid(HybridConfig),
}
impl ProcessingStrategy {
pub fn name(&self) -> &'static str {
match self {
ProcessingStrategy::CPU(_) => "CPU",
ProcessingStrategy::GPU(_) => "GPU",
ProcessingStrategy::Streaming(_) => "Streaming",
ProcessingStrategy::Hybrid(_) => "Hybrid",
}
}
pub fn supports_parallel(&self) -> bool {
match self {
ProcessingStrategy::CPU(_)
| ProcessingStrategy::GPU(_)
| ProcessingStrategy::Hybrid(_) => true,
ProcessingStrategy::Streaming(_) => false,
}
}
pub fn estimated_memory_usage(&self, data_size: usize) -> usize {
match self {
ProcessingStrategy::CPU(config) => {
let threads = config.num_threads.unwrap_or(num_cpus::get());
data_size / threads
}
ProcessingStrategy::GPU(config) => config.memory_budget,
ProcessingStrategy::Streaming(config) => config.buffer_size,
ProcessingStrategy::Hybrid(config) => config
.cpu_config
.memory_budget()
.max(config.gpu_config.memory_budget),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RayonConfig {
pub num_threads: Option<usize>,
pub chunk_size: Option<usize>,
pub enable_simd: bool,
}
impl RayonConfig {
pub fn new() -> Self {
Self {
num_threads: None,
chunk_size: None,
enable_simd: true,
}
}
pub fn with_threads(mut self, threads: usize) -> Self {
self.num_threads = Some(threads);
self
}
pub fn with_chunk_size(mut self, size: usize) -> Self {
self.chunk_size = Some(size);
self
}
pub fn with_simd(mut self, enable: bool) -> Self {
self.enable_simd = enable;
self
}
pub fn memory_budget(&self) -> usize {
let threads = self.num_threads.unwrap_or(num_cpus::get());
let chunk_size = self.chunk_size.unwrap_or(1024);
threads * chunk_size * 8 }
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ComputeConfig {
pub workgroup_size: u32,
pub memory_budget: usize,
pub enable_shared_memory: bool,
}
impl ComputeConfig {
pub fn new() -> Self {
Self {
workgroup_size: 64,
memory_budget: 1024 * 1024 * 1024, enable_shared_memory: true,
}
}
pub fn with_workgroup_size(mut self, size: u32) -> Self {
self.workgroup_size = size;
self
}
pub fn with_memory_budget(mut self, budget: usize) -> Self {
self.memory_budget = budget;
self
}
pub fn with_shared_memory(mut self, enable: bool) -> Self {
self.enable_shared_memory = enable;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StreamConfig {
pub buffer_size: usize,
pub batch_size: usize,
pub enable_backpressure: bool,
pub compression: bool,
}
impl StreamConfig {
pub fn new() -> Self {
Self {
buffer_size: 1024 * 1024, batch_size: 1000,
enable_backpressure: true,
compression: false,
}
}
pub fn with_buffer_size(mut self, size: usize) -> Self {
self.buffer_size = size;
self
}
pub fn with_batch_size(mut self, size: usize) -> Self {
self.batch_size = size;
self
}
pub fn with_backpressure(mut self, enable: bool) -> Self {
self.enable_backpressure = enable;
self
}
pub fn with_compression(mut self, enable: bool) -> Self {
self.compression = enable;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridConfig {
pub cpu_threshold: usize,
pub gpu_threshold: usize,
pub cpu_config: RayonConfig,
pub gpu_config: ComputeConfig,
}
impl HybridConfig {
pub fn new() -> Self {
Self {
cpu_threshold: 1000,
gpu_threshold: 10000,
cpu_config: RayonConfig::new(),
gpu_config: ComputeConfig::new(),
}
}
pub fn with_cpu_threshold(mut self, threshold: usize) -> Self {
self.cpu_threshold = threshold;
self
}
pub fn with_gpu_threshold(mut self, threshold: usize) -> Self {
self.gpu_threshold = threshold;
self
}
pub fn with_cpu_config(mut self, config: RayonConfig) -> Self {
self.cpu_config = config;
self
}
pub fn with_gpu_config(mut self, config: ComputeConfig) -> Self {
self.gpu_config = config;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceMetric {
pub strategy: String,
pub data_size: usize,
pub duration: f64,
pub timestamp: SystemTime,
pub memory_usage: usize,
pub cpu_usage: f64,
pub gpu_usage: Option<f64>,
}
impl PerformanceMetric {
pub fn new(strategy: impl Into<String>, data_size: usize, duration: f64) -> Self {
Self {
strategy: strategy.into(),
data_size,
duration,
timestamp: SystemTime::now(),
memory_usage: 0,
cpu_usage: 0.0,
gpu_usage: None,
}
}
pub fn with_memory_usage(mut self, usage: usize) -> Self {
self.memory_usage = usage;
self
}
pub fn with_cpu_usage(mut self, usage: f64) -> Self {
self.cpu_usage = usage;
self
}
pub fn with_gpu_usage(mut self, usage: f64) -> Self {
self.gpu_usage = Some(usage);
self
}
pub fn throughput(&self) -> f64 {
if self.duration > 0.0 {
self.data_size as f64 / self.duration
} else {
0.0
}
}
pub fn efficiency(&self) -> f64 {
let resource_usage = self.cpu_usage + self.gpu_usage.unwrap_or(0.0);
if resource_usage > 0.0 {
self.throughput() / resource_usage
} else {
0.0
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeviceCapabilities {
pub cpu_cores: usize,
pub cpu_frequency: f64,
pub memory_total: usize,
pub memory_available: usize,
pub gpu_available: bool,
pub gpu_memory: Option<usize>,
pub gpu_compute_units: Option<usize>,
pub simd_support: bool,
pub avx_support: bool,
pub sse_support: bool,
}
impl DeviceCapabilities {
pub fn new() -> Self {
Self {
cpu_cores: num_cpus::get(),
cpu_frequency: 0.0, memory_total: 0, memory_available: 0, gpu_available: false,
gpu_memory: None,
gpu_compute_units: None,
simd_support: true,
avx_support: true,
sse_support: true,
}
}
pub fn should_use_gpu(&self, data_size: usize) -> bool {
self.gpu_available
&& data_size > 10000
&& self.gpu_memory.map_or(false, |mem| mem > data_size * 8)
}
pub fn should_use_cpu(&self, data_size: usize) -> bool {
data_size < 1000 || !self.gpu_available
}
pub fn should_use_hybrid(&self, data_size: usize) -> bool {
self.gpu_available && data_size > 1000 && data_size < 100000
}
pub fn optimal_cpu_threads(&self) -> usize {
self.cpu_cores
}
pub fn optimal_chunk_size(&self) -> usize {
if self.avx_support {
1024
} else if self.sse_support {
512
} else {
256
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataSpec {
pub columns: Vec<ColumnSpec>,
pub row_count: usize,
pub memory_size: usize,
pub data_types: HashMap<String, String>,
pub nullable_columns: Vec<String>,
pub indexed_columns: Vec<String>,
}
impl DataSpec {
pub fn new() -> Self {
Self {
columns: Vec::new(),
row_count: 0,
memory_size: 0,
data_types: HashMap::new(),
nullable_columns: Vec::new(),
indexed_columns: Vec::new(),
}
}
pub fn add_column(&mut self, column: ColumnSpec) {
self.columns.push(column);
}
pub fn with_row_count(mut self, count: usize) -> Self {
self.row_count = count;
self
}
pub fn with_memory_size(mut self, size: usize) -> Self {
self.memory_size = size;
self
}
pub fn add_data_type(&mut self, column: String, data_type: String) {
self.data_types.insert(column, data_type);
}
pub fn add_nullable_column(&mut self, column: String) {
if !self.nullable_columns.contains(&column) {
self.nullable_columns.push(column);
}
}
pub fn add_indexed_column(&mut self, column: String) {
if !self.indexed_columns.contains(&column) {
self.indexed_columns.push(column);
}
}
pub fn column_count(&self) -> usize {
self.columns.len()
}
pub fn is_small(&self) -> bool {
self.row_count < 1000
}
pub fn is_large(&self) -> bool {
self.row_count > 100000
}
pub fn estimated_processing_time(&self) -> Duration {
let base_time = self.row_count as u64 * 100; Duration::from_nanos(base_time)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnSpec {
pub name: String,
pub data_type: String,
pub nullable: bool,
pub indexed: bool,
pub unique: bool,
pub min_value: Option<String>,
pub max_value: Option<String>,
pub distinct_count: Option<usize>,
}
impl ColumnSpec {
pub fn new(name: impl Into<String>, data_type: impl Into<String>) -> Self {
Self {
name: name.into(),
data_type: data_type.into(),
nullable: false,
indexed: false,
unique: false,
min_value: None,
max_value: None,
distinct_count: None,
}
}
pub fn with_nullable(mut self, nullable: bool) -> Self {
self.nullable = nullable;
self
}
pub fn with_indexed(mut self, indexed: bool) -> Self {
self.indexed = indexed;
self
}
pub fn with_unique(mut self, unique: bool) -> Self {
self.unique = unique;
self
}
pub fn with_value_range(mut self, min: impl Into<String>, max: impl Into<String>) -> Self {
self.min_value = Some(min.into());
self.max_value = Some(max.into());
self
}
pub fn with_distinct_count(mut self, count: usize) -> Self {
self.distinct_count = Some(count);
self
}
}