Skip to main content

ferrum_types/
metrics.rs

1//! Metrics and observability types
2
3use crate::{ids::*, Device, EngineConfig, RequestId};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::collections::HashMap;
8
9/// Engine status information
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct EngineStatus {
12    /// Whether the engine is ready to accept requests
13    pub is_ready: bool,
14    /// Currently loaded models
15    pub loaded_models: Vec<ModelId>,
16    /// Number of active requests
17    pub active_requests: usize,
18    /// Number of queued requests
19    pub queued_requests: usize,
20    /// Current memory usage
21    pub memory_usage: MemoryUsage,
22    /// Engine uptime
23    pub uptime_seconds: u64,
24    /// Last heartbeat timestamp
25    pub last_heartbeat: DateTime<Utc>,
26    /// Engine version
27    pub version: String,
28}
29
30/// Memory usage statistics
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct MemoryUsage {
33    /// Total system memory in bytes
34    pub total_bytes: usize,
35    /// Used memory in bytes
36    pub used_bytes: usize,
37    /// Free memory in bytes
38    pub free_bytes: usize,
39    /// GPU memory usage (if applicable)
40    pub gpu_memory_bytes: Option<usize>,
41    /// CPU memory usage
42    pub cpu_memory_bytes: Option<usize>,
43    /// Cache memory usage
44    pub cache_memory_bytes: usize,
45    /// Memory utilization percentage
46    pub utilization_percent: f32,
47}
48
49impl MemoryUsage {
50    /// Calculate memory utilization percentage
51    pub fn calculate_utilization(&mut self) {
52        if self.total_bytes > 0 {
53            self.utilization_percent = (self.used_bytes as f32 / self.total_bytes as f32) * 100.0;
54        } else {
55            self.utilization_percent = 0.0;
56        }
57    }
58}
59
60/// Scheduler statistics
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct SchedulerStats {
63    /// Number of waiting requests
64    pub waiting_requests: usize,
65    /// Number of running requests
66    pub running_requests: usize,
67    /// Number of preempted requests
68    pub preempted_requests: usize,
69    /// Total completed requests
70    pub completed_requests: u64,
71    /// Total failed requests
72    pub failed_requests: u64,
73    /// Total cancelled requests
74    pub cancelled_requests: u64,
75    /// Average wait time in milliseconds
76    pub avg_wait_time_ms: f64,
77    /// Average execution time in milliseconds
78    pub avg_execution_time_ms: f64,
79    /// Current throughput (requests per second)
80    pub throughput_rps: f64,
81    /// Queue utilization percentage
82    pub queue_utilization: f32,
83}
84
85/// Cache statistics
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct CacheStats {
88    /// Total number of cache blocks
89    pub total_blocks: usize,
90    /// Number of used blocks
91    pub used_blocks: usize,
92    /// Number of free blocks
93    pub free_blocks: usize,
94    /// Cache hit rate (0.0 to 1.0)
95    pub cache_hit_rate: f32,
96    /// Total number of cache hits
97    pub cache_hits: u64,
98    /// Total number of cache misses
99    pub cache_misses: u64,
100    /// Number of cache evictions
101    pub eviction_count: u64,
102    /// Average block utilization
103    pub avg_block_utilization: f32,
104    /// Prefix cache statistics
105    pub prefix_cache_stats: Option<PrefixCacheStats>,
106}
107
108/// Prefix cache statistics
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct PrefixCacheStats {
111    /// Number of cached prefixes
112    pub cached_prefixes: usize,
113    /// Prefix hit rate
114    pub prefix_hit_rate: f32,
115    /// Average prefix length
116    pub avg_prefix_length: f32,
117    /// Memory saved by prefix caching (bytes)
118    pub memory_saved_bytes: u64,
119}
120
121/// Batch processing metrics
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct BatchingMetrics {
124    /// Average batch size
125    pub avg_batch_size: f32,
126    /// Batch utilization rate
127    pub batch_utilization: f32,
128    /// Number of batches created
129    pub batches_created: u64,
130    /// Number of batches completed
131    pub batches_completed: u64,
132    /// Average batch processing time
133    pub avg_batch_time_ms: f64,
134    /// Tokens per second across all batches
135    pub tokens_per_second: f64,
136}
137
138/// Request latency metrics
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct LatencyMetrics {
141    /// Average end-to-end latency
142    pub avg_latency_ms: f64,
143    /// P50 latency
144    pub p50_latency_ms: f64,
145    /// P90 latency
146    pub p90_latency_ms: f64,
147    /// P95 latency
148    pub p95_latency_ms: f64,
149    /// P99 latency
150    pub p99_latency_ms: f64,
151    /// P99.9 latency
152    pub p999_latency_ms: f64,
153    /// Time to first token (TTFT)
154    pub avg_ttft_ms: f64,
155    /// Inter-token latency
156    pub avg_inter_token_latency_ms: f64,
157}
158
159/// Throughput metrics
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct ThroughputMetrics {
162    /// Requests per second
163    pub requests_per_second: f64,
164    /// Tokens per second
165    pub tokens_per_second: f64,
166    /// Characters per second
167    pub characters_per_second: f64,
168    /// Batch throughput
169    pub batches_per_second: f64,
170    /// Peak throughput achieved
171    pub peak_tokens_per_second: f64,
172}
173
174/// Model execution metrics
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct ModelMetrics {
177    /// Model identifier
178    pub model_id: ModelId,
179    /// Number of forward passes
180    pub forward_passes: u64,
181    /// Average forward pass time
182    pub avg_forward_time_ms: f64,
183    /// Prefill metrics
184    pub prefill_metrics: PhaseMetrics,
185    /// Decode metrics
186    pub decode_metrics: PhaseMetrics,
187    /// Total tokens generated
188    pub tokens_generated: u64,
189}
190
191/// Metrics for different execution phases
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct PhaseMetrics {
194    /// Number of operations
195    pub operations: u64,
196    /// Average time per operation
197    pub avg_time_ms: f64,
198    /// Total time spent
199    pub total_time_ms: f64,
200    /// Tokens processed
201    pub tokens_processed: u64,
202}
203
204/// Request-level metrics
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct RequestMetrics {
207    /// Request identifier
208    pub request_id: RequestId,
209    /// Client identifier
210    pub client_id: Option<ClientId>,
211    /// Model used
212    pub model_id: ModelId,
213    /// Request creation time
214    pub created_at: DateTime<Utc>,
215    /// Request completion time
216    pub completed_at: Option<DateTime<Utc>>,
217    /// Total processing time
218    pub total_time_ms: u64,
219    /// Time waiting in queue
220    pub queue_time_ms: u64,
221    /// Time spent in prefill phase
222    pub prefill_time_ms: u64,
223    /// Time spent in decode phase
224    pub decode_time_ms: u64,
225    /// Number of input tokens
226    pub input_tokens: usize,
227    /// Number of output tokens
228    pub output_tokens: usize,
229    /// Whether request was preempted
230    pub was_preempted: bool,
231    /// Number of preemptions
232    pub preemption_count: u32,
233}
234
235/// System resource metrics
236#[derive(Debug, Clone, Serialize, Deserialize)]
237pub struct SystemMetrics {
238    /// CPU usage percentage
239    pub cpu_usage_percent: f32,
240    /// Memory usage
241    pub memory_usage: MemoryUsage,
242    /// GPU utilization (if applicable)
243    pub gpu_utilization: Option<GpuMetrics>,
244    /// Network I/O statistics
245    pub network_io: NetworkMetrics,
246    /// Disk I/O statistics
247    pub disk_io: DiskMetrics,
248    /// System load average
249    pub load_average: [f32; 3], // 1min, 5min, 15min
250}
251
252/// GPU-specific metrics
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct GpuMetrics {
255    /// GPU utilization percentage
256    pub utilization_percent: f32,
257    /// GPU memory usage in bytes
258    pub memory_used_bytes: usize,
259    /// GPU memory total in bytes
260    pub memory_total_bytes: usize,
261    /// GPU temperature in Celsius
262    pub temperature_celsius: f32,
263    /// Power consumption in watts
264    pub power_watts: f32,
265}
266
267/// Network I/O metrics
268#[derive(Debug, Clone, Serialize, Deserialize)]
269pub struct NetworkMetrics {
270    /// Bytes received per second
271    pub rx_bytes_per_sec: u64,
272    /// Bytes transmitted per second
273    pub tx_bytes_per_sec: u64,
274    /// Packets received per second
275    pub rx_packets_per_sec: u64,
276    /// Packets transmitted per second
277    pub tx_packets_per_sec: u64,
278}
279
280/// Disk I/O metrics
281#[derive(Debug, Clone, Serialize, Deserialize)]
282pub struct DiskMetrics {
283    /// Bytes read per second
284    pub read_bytes_per_sec: u64,
285    /// Bytes written per second
286    pub write_bytes_per_sec: u64,
287    /// Read operations per second
288    pub read_ops_per_sec: u64,
289    /// Write operations per second
290    pub write_ops_per_sec: u64,
291}
292
293/// Error statistics
294#[derive(Debug, Clone, Serialize, Deserialize, Default)]
295pub struct ErrorStats {
296    /// Total number of errors
297    pub total_errors: u64,
298    /// Errors by type
299    pub errors_by_type: HashMap<String, u64>,
300    /// Error rate (errors per request)
301    pub error_rate: f32,
302    /// Recent errors
303    pub recent_errors: Vec<ErrorEvent>,
304}
305
306/// Individual error event
307#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct ErrorEvent {
309    /// When the error occurred
310    pub timestamp: DateTime<Utc>,
311    /// Error type/category
312    pub error_type: String,
313    /// Error message
314    pub message: String,
315    /// Request ID that caused the error (if applicable)
316    pub request_id: Option<RequestId>,
317    /// Additional context
318    pub context: HashMap<String, serde_json::Value>,
319}
320
321/// Aggregated engine metrics
322#[derive(Debug, Clone, Serialize, Deserialize, Default)]
323pub struct EngineMetrics {
324    pub total_requests: u64,
325    pub successful_requests: u64,
326    pub failed_requests: u64,
327    pub avg_request_latency_ms: f64,
328    pub p95_request_latency_ms: f64,
329    pub p99_request_latency_ms: f64,
330    pub throughput_rps: f32,
331    pub tokens_per_second: f32,
332    pub queue_metrics: QueueMetrics,
333    pub resource_utilization: ResourceMetrics,
334    pub error_stats: ErrorStats,
335    pub performance_breakdown: PerformanceBreakdown,
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize, Default)]
339pub struct QueueMetrics {
340    pub current_queue_length: usize,
341    pub avg_queue_wait_time_ms: f64,
342    pub queue_throughput_rps: f32,
343    pub queue_rejection_rate: f32,
344}
345
346#[derive(Debug, Clone, Serialize, Deserialize, Default)]
347pub struct ResourceMetrics {
348    pub cpu_utilization: f32,
349    pub memory_utilization: f32,
350    pub gpu_utilization: Option<f32>,
351    pub network_utilization: f32,
352    pub disk_utilization: f32,
353}
354
355#[derive(Debug, Clone, Serialize, Deserialize, Default)]
356pub struct PerformanceBreakdown {
357    pub tokenization_time_ms: f64,
358    pub model_execution_time_ms: f64,
359    pub sampling_time_ms: f64,
360    pub scheduling_time_ms: f64,
361    pub memory_operations_time_ms: f64,
362    pub other_overhead_time_ms: f64,
363}
364
365/// Health check status
366#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct HealthStatus {
368    /// Overall health status
369    pub status: HealthStatusType,
370    /// Individual component health
371    pub component_status: ComponentStatus,
372    /// Last health check time
373    pub last_check: DateTime<Utc>,
374}
375
376impl HealthStatus {
377    /// Construct a healthy status with default component health
378    pub fn healthy() -> Self {
379        Self {
380            status: HealthStatusType::Healthy,
381            component_status: ComponentStatus::healthy(),
382            last_check: Utc::now(),
383        }
384    }
385}
386
387/// Health status types
388#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
389pub enum HealthStatusType {
390    /// System is healthy
391    Healthy,
392    /// System has warnings but is functional
393    Warning,
394    /// System is unhealthy
395    Unhealthy,
396}
397
398/// Individual component health snapshot
399#[derive(Debug, Clone, Serialize, Deserialize)]
400pub struct ComponentHealth {
401    /// Component health status
402    pub status: HealthStatusType,
403    /// Health message
404    pub message: String,
405    /// Component-specific metrics
406    pub metrics: HashMap<String, f64>,
407    /// Last check time
408    pub last_check: DateTime<Utc>,
409}
410
411impl ComponentHealth {
412    /// Construct a healthy component entry with default state
413    pub fn healthy(component: &str) -> Self {
414        Self {
415            status: HealthStatusType::Healthy,
416            message: format!("{} healthy", component),
417            metrics: HashMap::new(),
418            last_check: Utc::now(),
419        }
420    }
421}
422
423/// Aggregated component health map
424#[derive(Debug, Clone, Serialize, Deserialize)]
425pub struct ComponentStatus {
426    pub scheduler: ComponentHealth,
427    pub model_executor: ComponentHealth,
428    pub tokenizer: ComponentHealth,
429    pub kv_cache: ComponentHealth,
430    pub memory_manager: ComponentHealth,
431    pub backend: ComponentHealth,
432}
433
434impl ComponentStatus {
435    /// Construct a fully healthy component status snapshot
436    pub fn healthy() -> Self {
437        Self {
438            scheduler: ComponentHealth::healthy("scheduler"),
439            model_executor: ComponentHealth::healthy("model"),
440            tokenizer: ComponentHealth::healthy("tokenizer"),
441            kv_cache: ComponentHealth::healthy("kv_cache"),
442            memory_manager: ComponentHealth::healthy("memory"),
443            backend: ComponentHealth::healthy("backend"),
444        }
445    }
446
447    /// Iterate over component entries for aggregation helpers
448    pub fn entries(&self) -> [&ComponentHealth; 6] {
449        [
450            &self.scheduler,
451            &self.model_executor,
452            &self.tokenizer,
453            &self.kv_cache,
454            &self.memory_manager,
455            &self.backend,
456        ]
457    }
458}
459
460/// Component health status alias for backwards compatibility
461pub type ComponentHealthStatus = HealthStatusType;
462
463/// Diagnostics report aggregating engine state
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct DiagnosticsReport {
466    /// Engine configuration snapshot
467    pub config_snapshot: EngineConfig,
468    /// Current metrics
469    pub current_metrics: EngineMetrics,
470    /// Resource usage details
471    pub resource_usage: DetailedResourceUsage,
472    /// Performance analysis
473    pub performance_analysis: PerformanceAnalysis,
474    /// Component diagnostics
475    pub component_diagnostics: HashMap<String, Value>,
476    /// System information
477    pub system_info: SystemInfo,
478}
479
480/// Detailed resource usage information
481#[derive(Debug, Clone, Serialize, Deserialize, Default)]
482pub struct DetailedResourceUsage {
483    pub memory_by_component: HashMap<String, u64>,
484    pub cpu_by_thread: HashMap<String, f32>,
485    pub gpu_memory_details: Option<GpuMemoryDetails>,
486    pub network_io_details: NetworkIODetails,
487}
488
489/// GPU memory usage details
490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
491pub struct GpuMemoryDetails {
492    pub total_memory: u64,
493    pub used_memory: u64,
494    pub memory_by_type: HashMap<String, u64>,
495    pub large_allocations: Vec<AllocationInfo>,
496}
497
498/// Allocation detail record
499#[derive(Debug, Clone, Serialize, Deserialize)]
500pub struct AllocationInfo {
501    pub size: u64,
502    pub allocation_type: String,
503    pub timestamp: DateTime<Utc>,
504}
505
506/// Network I/O details
507#[derive(Debug, Clone, Serialize, Deserialize, Default)]
508pub struct NetworkIODetails {
509    pub bytes_received_per_sec: u64,
510    pub bytes_sent_per_sec: u64,
511    pub connection_count: usize,
512    pub request_rate_per_sec: f32,
513}
514
515/// Performance analysis report
516#[derive(Debug, Clone, Serialize, Deserialize, Default)]
517pub struct PerformanceAnalysis {
518    pub bottlenecks: Vec<PerformanceBottleneck>,
519    pub recommendations: Vec<PerformanceRecommendation>,
520    pub trends: PerformanceTrends,
521}
522
523/// Performance bottleneck metadata
524#[derive(Debug, Clone, Serialize, Deserialize)]
525pub struct PerformanceBottleneck {
526    pub bottleneck_type: String,
527    pub severity: f32,
528    pub description: String,
529    pub performance_impact: f32,
530}
531
532/// Optimization recommendation record
533#[derive(Debug, Clone, Serialize, Deserialize)]
534pub struct PerformanceRecommendation {
535    pub category: String,
536    pub description: String,
537    pub expected_impact: f32,
538    pub complexity: f32,
539}
540
541/// Performance trend indicators
542#[derive(Debug, Clone, Serialize, Deserialize, Default)]
543pub struct PerformanceTrends {
544    pub latency_trend: TrendDirection,
545    pub throughput_trend: TrendDirection,
546    pub error_rate_trend: TrendDirection,
547    pub resource_utilization_trend: TrendDirection,
548}
549
550/// Trend direction enum
551#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
552pub enum TrendDirection {
553    Improving,
554    Stable,
555    Degrading,
556    Volatile,
557}
558
559impl Default for TrendDirection {
560    fn default() -> Self {
561        TrendDirection::Stable
562    }
563}
564
565/// System information snapshot
566#[derive(Debug, Clone, Serialize, Deserialize, Default)]
567pub struct SystemInfo {
568    pub os: String,
569    pub cpu_info: String,
570    pub total_memory: u64,
571    pub devices: Vec<Device>,
572    pub runtime_info: RuntimeInfo,
573}
574
575/// Runtime information block
576#[derive(Debug, Clone, Serialize, Deserialize, Default)]
577pub struct RuntimeInfo {
578    pub rust_version: String,
579    pub engine_version: String,
580    pub build_info: BuildInfo,
581    pub feature_flags: Vec<String>,
582}
583
584/// Build information metadata
585#[derive(Debug, Clone, Serialize, Deserialize, Default)]
586pub struct BuildInfo {
587    pub build_timestamp: String,
588    pub git_commit: Option<String>,
589    pub build_config: String,
590    pub compiler_flags: Vec<String>,
591}
592
593/// Engine state export for diagnostics
594#[derive(Debug, Clone, Serialize, Deserialize)]
595pub struct EngineState {
596    pub config: EngineConfig,
597    pub metrics: EngineMetrics,
598    pub component_states: HashMap<String, Value>,
599    pub active_requests: Vec<EngineRequestState>,
600    pub timestamp: DateTime<Utc>,
601}
602
603/// Request state for debugging
604#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct EngineRequestState {
606    pub request_id: RequestId,
607    pub current_phase: String,
608    pub progress: EngineRequestProgress,
609    pub allocated_resources: HashMap<String, Value>,
610}
611
612/// Request progress summary
613#[derive(Debug, Clone, Serialize, Deserialize, Default)]
614pub struct EngineRequestProgress {
615    pub tokens_processed: usize,
616    pub tokens_remaining: usize,
617    pub elapsed_time_ms: u64,
618    pub estimated_remaining_ms: Option<u64>,
619}
620
621/// Speculation configuration for speculative decoding
622#[derive(Debug, Clone, Serialize, Deserialize)]
623pub struct SpeculationConfig {
624    pub speculation_depth: usize,
625    pub acceptance_threshold: f32,
626    pub draft_model_config: Option<crate::ModelConfig>,
627}
628
629/// Warmup result structure
630#[derive(Debug, Clone, Serialize, Deserialize, Default)]
631pub struct WarmupResult {
632    pub requests_processed: usize,
633    pub total_time_ms: u64,
634    pub avg_latency_ms: f64,
635    pub memory_allocated_bytes: u64,
636    pub success: bool,
637    pub issues: Vec<String>,
638}
639
640/// Hardware constraints for recommendations
641#[derive(Debug, Clone, Serialize, Deserialize)]
642pub struct HardwareConstraints {
643    pub available_devices: Vec<Device>,
644    pub total_memory: u64,
645    pub expected_request_rate: f32,
646    pub request_characteristics: RequestCharacteristics,
647}
648
649/// Request characteristics summary
650#[derive(Debug, Clone, Serialize, Deserialize)]
651pub struct RequestCharacteristics {
652    pub avg_input_tokens: usize,
653    pub avg_output_tokens: usize,
654    pub typical_batch_size: usize,
655    pub latency_requirements: LatencyRequirements,
656}
657
658/// Latency requirements for configuration
659#[derive(Debug, Clone, Serialize, Deserialize)]
660pub struct LatencyRequirements {
661    pub target_p95_latency_ms: u64,
662    pub target_p99_latency_ms: u64,
663    pub max_latency_ms: u64,
664}