1#![allow(dead_code)]
9
10use anyhow::Result;
11use chrono::{DateTime, Utc};
12use serde::{Deserialize, Serialize};
13use std::collections::{HashMap, VecDeque};
14use std::time::{Duration, SystemTime};
15use uuid::Uuid;
16
17#[derive(Debug)]
19pub struct AdvancedGpuMemoryProfiler {
20 device_count: i32,
21 memory_pools: HashMap<i32, GpuMemoryPool>,
22 memory_allocations: HashMap<Uuid, GpuMemoryAllocation>,
23 fragmentation_history: VecDeque<MemoryFragmentationSnapshot>,
24 bandwidth_monitors: HashMap<i32, GpuBandwidthMonitor>,
25 memory_pressure_monitor: MemoryPressureMonitor,
26 cross_device_transfers: Vec<CrossDeviceTransfer>,
27 system_info: sysinfo::System,
31 last_used_swap_bytes: Option<u64>,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct GpuMemoryAllocation {
40 pub allocation_id: Uuid,
41 pub device_id: i32,
42 pub size_bytes: usize,
43 pub alignment: usize,
44 pub memory_type: GpuMemoryType,
45 pub allocation_context: AllocationContext,
46 pub timestamp: SystemTime,
47 pub freed: bool,
48 pub free_timestamp: Option<SystemTime>,
49 pub access_pattern: MemoryAccessPattern,
50 pub usage_statistics: MemoryUsageStats,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub enum GpuMemoryType {
55 Global,
56 Shared,
57 Constant,
58 Texture,
59 Local,
60 Unified,
61 Pinned,
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct AllocationContext {
66 pub kernel_name: Option<String>,
67 pub tensor_name: Option<String>,
68 pub layer_name: Option<String>,
69 pub allocation_source: AllocationSource,
70 pub stack_trace: Vec<String>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub enum AllocationSource {
75 TensorCreation,
76 KernelLaunch,
77 IntermediateBuffer,
78 GradientBuffer,
79 WeightBuffer,
80 ActivationBuffer,
81 CacheBuffer,
82}
83
84#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct MemoryAccessPattern {
86 pub access_frequency: f64,
87 pub read_ratio: f64,
88 pub write_ratio: f64,
89 pub sequential_access_ratio: f64,
90 pub random_access_ratio: f64,
91 pub coalesced_access_ratio: f64,
92 pub cache_hit_rate: f64,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, Default)]
96pub struct MemoryUsageStats {
97 pub total_accesses: u64,
98 pub bytes_read: u64,
99 pub bytes_written: u64,
100 pub lifetime_duration: Option<Duration>,
101 pub peak_concurrent_usage: usize,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct MemoryFragmentationSnapshot {
107 pub timestamp: DateTime<Utc>,
108 pub device_id: i32,
109 pub total_memory: usize,
113 pub free_memory: usize,
119 pub largest_free_block: Option<usize>,
126 pub fragmentation_ratio: Option<f64>,
130 pub free_block_distribution: Option<Vec<usize>>,
134 pub external_fragmentation: Option<f64>,
136 pub internal_fragmentation: Option<f64>,
138}
139
140#[derive(Debug)]
142pub struct GpuBandwidthMonitor {
143 device_id: i32,
144 bandwidth_samples: VecDeque<BandwidthSample>,
145 theoretical_bandwidth: f64, peak_observed_bandwidth: f64,
147 sustained_bandwidth_history: Vec<SustainedBandwidthMeasurement>,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct BandwidthSample {
152 pub timestamp: SystemTime,
153 pub memory_type: GpuMemoryType,
154 pub operation_type: MemoryOperationType,
155 pub bytes_transferred: usize,
156 pub duration: Duration,
157 pub achieved_bandwidth_gb_s: f64,
158 pub efficiency_percentage: f64,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub enum MemoryOperationType {
163 HostToDevice,
164 DeviceToHost,
165 DeviceToDevice,
166 KernelMemoryAccess,
167 PeerToPeer,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct SustainedBandwidthMeasurement {
172 pub duration: Duration,
173 pub avg_bandwidth_gb_s: f64,
174 pub min_bandwidth_gb_s: f64,
175 pub max_bandwidth_gb_s: f64,
176 pub bandwidth_variability: f64,
177}
178
179#[derive(Debug)]
181pub struct MemoryPressureMonitor {
182 pressure_history: VecDeque<MemoryPressureSnapshot>,
183 pressure_thresholds: MemoryPressureThresholds,
184 auto_optimization_enabled: bool,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct MemoryPressureSnapshot {
189 pub timestamp: DateTime<Utc>,
190 pub device_id: i32,
191 pub pressure_level: MemoryPressureLevel,
192 pub available_memory_ratio: f64,
193 pub allocation_rate: f64, pub deallocation_rate: f64,
195 pub gc_pressure: Option<f64>,
199 pub swap_activity: Option<f64>,
211}
212
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub enum MemoryPressureLevel {
215 Low,
216 Medium,
217 High,
218 Critical,
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct MemoryPressureThresholds {
223 pub medium_threshold: f64, pub high_threshold: f64, pub critical_threshold: f64, }
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct CrossDeviceTransfer {
231 pub transfer_id: Uuid,
232 pub source_device: i32,
233 pub target_device: i32,
234 pub bytes_transferred: usize,
235 pub transfer_type: CrossDeviceTransferType,
236 pub duration: Duration,
237 pub bandwidth_achieved: f64,
238 pub p2p_enabled: Option<bool>,
243 pub timestamp: SystemTime,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
247pub enum CrossDeviceTransferType {
248 DirectMemoryAccess,
249 PeerToPeer,
250 HostBounced,
251 NvLink,
252 Infinity,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct KernelExecutionProfile {
257 pub kernel_name: String,
258 pub execution_count: usize,
259 pub total_execution_time: Duration,
260 pub avg_execution_time: Duration,
261 pub min_execution_time: Duration,
262 pub max_execution_time: Duration,
263 pub grid_sizes: Vec<(u32, u32, u32)>,
264 pub block_sizes: Vec<(u32, u32, u32)>,
265 pub shared_memory_usage: Vec<usize>,
266 pub register_usage: Vec<u32>,
267 pub occupancy_measurements: Vec<f64>,
268 pub compute_utilization: Vec<f64>,
269 pub memory_bandwidth_utilization: Vec<f64>,
270 pub warp_efficiency: Vec<f64>,
271 pub memory_efficiency: Vec<f64>,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct KernelOptimization {
276 pub optimization_type: OptimizationType,
277 pub current_value: OptimizationValue,
278 pub suggested_value: OptimizationValue,
279 pub expected_improvement: ExpectedImprovement,
280 pub confidence: f64,
281 pub explanation: String,
282 pub implementation_difficulty: ImplementationDifficulty,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
286pub enum OptimizationType {
287 BlockSize,
288 GridSize,
289 SharedMemory,
290 RegisterOptimization,
291 MemoryCoalescing,
292 WarpDivergence,
293 KernelFusion,
294 MemoryLayoutOptimization,
295 ComputeIntensityBalance,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub enum OptimizationValue {
300 IntegerValue(u32),
301 FloatValue(f64),
302 TupleValue((u32, u32, u32)),
303 LayoutPattern(String),
304 BooleanValue(bool),
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize)]
308pub struct ExpectedImprovement {
309 pub performance_gain_percentage: f64,
310 pub memory_usage_reduction_percentage: f64,
311 pub energy_efficiency_improvement: f64,
312 pub scalability_improvement: f64,
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
316pub enum ImplementationDifficulty {
317 Trivial,
318 Easy,
319 Moderate,
320 Difficult,
321 Expert,
322}
323
324#[derive(Debug)]
326pub struct LaunchConfigAnalyzer {
327 optimal_configs: HashMap<String, OptimalLaunchConfig>,
328 config_performance_history: HashMap<String, Vec<ConfigPerformanceMeasurement>>,
329 autotuning_enabled: bool,
330 search_space_cache: HashMap<String, LaunchConfigSearchSpace>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
334pub struct LaunchConfigSearchSpace {
335 pub kernel_name: String,
336 pub min_block_size: (u32, u32, u32),
337 pub max_block_size: (u32, u32, u32),
338 pub min_grid_size: (u32, u32, u32),
339 pub max_grid_size: (u32, u32, u32),
340 pub min_shared_memory: usize,
341 pub max_shared_memory: usize,
342 pub search_constraints: Vec<LaunchConstraint>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct OptimalLaunchConfig {
347 pub kernel_name: String,
348 pub optimal_block_size: (u32, u32, u32),
349 pub optimal_grid_size: (u32, u32, u32),
350 pub optimal_shared_memory: usize,
351 pub expected_occupancy: f64,
352 pub expected_performance: f64,
353 pub constraints: Vec<LaunchConstraint>,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub struct ConfigPerformanceMeasurement {
358 pub block_size: (u32, u32, u32),
359 pub grid_size: (u32, u32, u32),
360 pub shared_memory: usize,
361 pub achieved_occupancy: f64,
362 pub execution_time: Duration,
363 pub memory_bandwidth: f64,
364 pub compute_utilization: f64,
365 pub timestamp: SystemTime,
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize)]
369pub enum LaunchConstraint {
370 MaxSharedMemory(usize),
371 MaxRegisters(u32),
372 MinOccupancy(f64),
373 WorkgroupSizeLimit(u32),
374 MemoryBandwidthLimit(f64),
375}
376
377#[derive(Debug)]
379pub struct MemoryAccessAnalyzer {
380 access_patterns: HashMap<String, MemoryAccessAnalysis>,
381 coalescing_analysis: HashMap<String, CoalescingAnalysis>,
382 cache_performance: HashMap<String, CachePerformanceAnalysis>,
383 stride_analysis: HashMap<String, StrideAnalysisResult>,
384 bank_conflict_analyzer: BankConflictAnalyzer,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct StrideAnalysisResult {
389 pub kernel_name: String,
390 pub average_stride: f64,
391 pub stride_pattern: StridePattern,
392 pub optimization_potential: f64,
393 pub recommended_changes: Vec<String>,
394}
395
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub enum StridePattern {
398 Sequential,
399 Strided(i32),
400 Random,
401 Broadcast,
402}
403
404#[derive(Debug)]
405pub struct BankConflictAnalyzer {
406 conflict_patterns: HashMap<String, BankConflictPattern>,
407 resolution_strategies: HashMap<String, Vec<ConflictResolutionStrategy>>,
408}
409
410#[derive(Debug, Clone, Serialize, Deserialize)]
411pub struct BankConflictPattern {
412 pub kernel_name: String,
413 pub conflicts_detected: usize,
414 pub conflict_severity: ConflictSeverity,
415 pub affected_warps: Vec<u32>,
416}
417
418#[derive(Debug, Clone, Serialize, Deserialize)]
419pub enum ConflictSeverity {
420 Low,
421 Medium,
422 High,
423 Critical,
424}
425
426#[derive(Debug, Clone, Serialize, Deserialize)]
427pub struct ConflictResolutionStrategy {
428 pub strategy_type: ResolutionStrategyType,
429 pub description: String,
430 pub expected_improvement: f64,
431}
432
433#[derive(Debug, Clone, Serialize, Deserialize)]
434pub enum ResolutionStrategyType {
435 DataPadding,
436 AccessReordering,
437 SharedMemoryBanking,
438 AlgorithmicChange,
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct MemoryAccessAnalysis {
443 pub kernel_name: String,
444 pub total_memory_transactions: u64,
445 pub coalesced_transactions: u64,
446 pub uncoalesced_transactions: u64,
447 pub stride_patterns: Vec<StridePattern>,
448 pub access_locality: AccessLocalityMetrics,
449 pub bank_conflicts: u64,
450 pub cache_line_utilization: f64,
451}
452
453#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct DetectedStride {
455 pub stride_size: usize,
456 pub frequency: u64,
457 pub efficiency_impact: f64,
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize)]
461pub struct AccessLocalityMetrics {
462 pub temporal_locality_score: f64,
463 pub spatial_locality_score: f64,
464 pub working_set_size: usize,
465 pub reuse_distance_avg: f64,
466}
467
468#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct CoalescingAnalysis {
470 pub kernel_name: String,
471 pub coalescing_efficiency: f64,
472 pub uncoalesced_regions: Vec<UncoalescedRegion>,
473 pub suggested_improvements: Vec<CoalescingImprovement>,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize)]
477pub struct UncoalescedRegion {
478 pub memory_region: String,
479 pub access_pattern: String,
480 pub efficiency_loss: f64,
481 pub fix_difficulty: ImplementationDifficulty,
482}
483
484#[derive(Debug, Clone, Serialize, Deserialize)]
485pub struct CoalescingImprovement {
486 pub improvement_type: CoalescingImprovementType,
487 pub description: String,
488 pub expected_speedup: f64,
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize)]
492pub enum CoalescingImprovementType {
493 DataLayoutReorganization,
494 AccessPatternOptimization,
495 SharedMemoryBuffering,
496 VectorizedAccess,
497}
498
499#[derive(Debug, Clone, Serialize, Deserialize)]
500pub struct CachePerformanceAnalysis {
501 pub kernel_name: String,
502 pub l1_cache_hit_rate: f64,
503 pub l2_cache_hit_rate: f64,
504 pub texture_cache_hit_rate: f64,
505 pub shared_memory_bank_conflicts: u64,
506 pub cache_thrashing_detected: bool,
507 pub recommended_cache_optimizations: Vec<CacheOptimization>,
508}
509
510#[derive(Debug, Clone, Serialize, Deserialize)]
511pub struct CacheOptimization {
512 pub optimization_type: CacheOptimizationType,
513 pub description: String,
514 pub expected_improvement: f64,
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize)]
518pub enum CacheOptimizationType {
519 DataPrefetching,
520 CacheBlockingStrategy,
521 SharedMemoryUsage,
522 TextureMemoryUsage,
523 ConstantMemoryUsage,
524}
525
526#[derive(Debug)]
528pub struct ComputeUtilizationAnalyzer {
529 utilization_profiles: HashMap<String, ComputeUtilizationProfile>,
530 bottleneck_analysis: HashMap<String, ComputeBottleneckAnalysis>,
531 arithmetic_intensity_analyzer: ArithmeticIntensityAnalyzer,
532 resource_balancer: ResourceBalancer,
533}
534
535#[derive(Debug)]
536pub struct ArithmeticIntensityAnalyzer {
537 intensity_profiles: HashMap<String, ArithmeticIntensityProfile>,
538 roofline_models: HashMap<i32, RooflineModel>,
539}
540
541#[derive(Debug, Clone, Serialize, Deserialize)]
542pub struct ArithmeticIntensityProfile {
543 pub kernel_name: String,
544 pub arithmetic_intensity: f64,
545 pub operations_per_byte: f64,
546 pub peak_performance_percentage: f64,
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize)]
550pub struct RooflineModel {
551 pub device_id: i32,
552 pub peak_compute_flops: f64,
553 pub peak_memory_bandwidth: f64,
554 pub ridge_point: f64,
555}
556
557#[derive(Debug)]
558pub struct ResourceBalancer {
559 resource_profiles: HashMap<String, ResourceProfile>,
560 balancing_strategies: HashMap<String, BalancingStrategy>,
561}
562
563#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct ResourceProfile {
565 pub kernel_name: String,
566 pub register_usage: f64,
567 pub shared_memory_usage: f64,
568 pub occupancy: f64,
569 pub limiting_factor: LimitingFactor,
570}
571
572#[derive(Debug, Clone, Serialize, Deserialize)]
573pub enum LimitingFactor {
574 Registers,
575 SharedMemory,
576 Blocks,
577 Warps,
578}
579
580#[derive(Debug, Clone, Serialize, Deserialize)]
581pub struct BalancingStrategy {
582 pub strategy_name: String,
583 pub description: String,
584 pub expected_improvement: f64,
585 pub trade_offs: Vec<String>,
586}
587
588#[derive(Debug, Clone, Serialize, Deserialize)]
589pub struct ComputeUtilizationProfile {
590 pub kernel_name: String,
591 pub arithmetic_intensity: f64,
592 pub compute_throughput: f64,
593 pub memory_throughput: f64,
594 pub compute_to_memory_ratio: f64,
595 pub warp_execution_efficiency: f64,
596 pub instruction_mix: InstructionMixAnalysis,
597 pub resource_utilization: ResourceUtilizationMetrics,
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
601pub struct InstructionMixAnalysis {
602 pub integer_ops_percentage: f64,
603 pub float_ops_percentage: f64,
604 pub double_ops_percentage: f64,
605 pub special_function_ops_percentage: f64,
606 pub memory_ops_percentage: f64,
607 pub control_flow_ops_percentage: f64,
608}
609
610#[derive(Debug, Clone, Serialize, Deserialize)]
611pub struct ResourceUtilizationMetrics {
612 pub register_utilization: f64,
613 pub shared_memory_utilization: f64,
614 pub constant_memory_utilization: f64,
615 pub texture_cache_utilization: f64,
616 pub compute_unit_utilization: f64,
617}
618
619#[derive(Debug, Clone, Serialize, Deserialize)]
620pub struct ComputeBottleneckAnalysis {
621 pub kernel_name: String,
622 pub primary_bottleneck: ComputeBottleneckType,
623 pub bottleneck_severity: f64,
624 pub contributing_factors: Vec<BottleneckFactor>,
625 pub optimization_opportunities: Vec<ComputeOptimizationOpportunity>,
626}
627
628#[derive(Debug, Clone, Serialize, Deserialize)]
629pub enum ComputeBottleneckType {
630 MemoryBandwidth,
631 ComputeThroughput,
632 Latency,
633 Occupancy,
634 WarpDivergence,
635 SynchronizationOverhead,
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
639pub struct BottleneckFactor {
640 pub factor_type: String,
641 pub impact_percentage: f64,
642 pub description: String,
643}
644
645#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct ComputeOptimizationOpportunity {
647 pub opportunity_type: ComputeOptimizationType,
648 pub description: String,
649 pub expected_speedup: f64,
650 pub implementation_effort: ImplementationDifficulty,
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
654pub enum ComputeOptimizationType {
655 KernelFusion,
656 MemoryOptimization,
657 ParallelismIncrease,
658 AlgorithmicImprovement,
659 ResourceBalancing,
660}
661
662impl AdvancedGpuMemoryProfiler {
663 pub fn new(device_count: i32) -> Result<Self> {
664 let mut memory_pools = HashMap::new();
665 let mut bandwidth_monitors = HashMap::new();
666
667 for device_id in 0..device_count {
668 memory_pools.insert(device_id, GpuMemoryPool::new(device_id)?);
669 bandwidth_monitors.insert(device_id, GpuBandwidthMonitor::new(device_id)?);
670 }
671
672 Ok(Self {
673 device_count,
674 memory_pools,
675 memory_allocations: HashMap::new(),
676 fragmentation_history: VecDeque::with_capacity(1000),
677 bandwidth_monitors,
678 memory_pressure_monitor: MemoryPressureMonitor::new(),
679 cross_device_transfers: Vec::new(),
680 system_info: sysinfo::System::new(),
681 last_used_swap_bytes: None,
682 })
683 }
684
685 pub fn track_allocation(
687 &mut self,
688 device_id: i32,
689 size_bytes: usize,
690 memory_type: GpuMemoryType,
691 context: AllocationContext,
692 ) -> Result<Uuid> {
693 let allocation_id = Uuid::new_v4();
694 let allocation = GpuMemoryAllocation {
695 allocation_id,
696 device_id,
697 size_bytes,
698 alignment: self.calculate_optimal_alignment(size_bytes),
699 memory_type,
700 allocation_context: context,
701 timestamp: SystemTime::now(),
702 freed: false,
703 free_timestamp: None,
704 access_pattern: MemoryAccessPattern::default(),
705 usage_statistics: MemoryUsageStats::default(),
706 };
707
708 if let Some(pool) = self.memory_pools.get_mut(&device_id) {
710 pool.allocate(size_bytes)?;
711 }
712
713 self.memory_allocations.insert(allocation_id, allocation);
714
715 self.update_memory_pressure(device_id);
717
718 Ok(allocation_id)
719 }
720
721 pub fn track_deallocation(&mut self, allocation_id: Uuid) -> Result<()> {
723 let device_id = if let Some(allocation) = self.memory_allocations.get_mut(&allocation_id) {
724 allocation.freed = true;
725 allocation.free_timestamp = Some(SystemTime::now());
726
727 let device_id = allocation.device_id;
729 let size_bytes = allocation.size_bytes;
730
731 if let Some(pool) = self.memory_pools.get_mut(&device_id) {
733 pool.deallocate(size_bytes)?;
734 }
735
736 Some(device_id)
737 } else {
738 None
739 };
740
741 if let Some(device_id) = device_id {
743 self.update_memory_pressure(device_id);
744 }
745
746 Ok(())
747 }
748
749 pub fn analyze_fragmentation(&mut self) -> Result<Vec<MemoryFragmentationSnapshot>> {
751 let mut snapshots = Vec::new();
752
753 for (&_device_id, pool) in &self.memory_pools {
754 let snapshot = pool.get_fragmentation_snapshot()?;
755 snapshots.push(snapshot.clone());
756
757 self.fragmentation_history.push_back(snapshot);
759 if self.fragmentation_history.len() > 1000 {
760 self.fragmentation_history.pop_front();
761 }
762 }
763
764 Ok(snapshots)
765 }
766
767 pub fn record_bandwidth_sample(
769 &mut self,
770 device_id: i32,
771 sample: BandwidthSample,
772 ) -> Result<()> {
773 if let Some(monitor) = self.bandwidth_monitors.get_mut(&device_id) {
774 monitor.add_sample(sample)?;
775 }
776 Ok(())
777 }
778
779 pub fn track_cross_device_transfer(
781 &mut self,
782 source_device: i32,
783 target_device: i32,
784 bytes_transferred: usize,
785 transfer_type: CrossDeviceTransferType,
786 duration: Duration,
787 ) -> Result<Uuid> {
788 let transfer_id = Uuid::new_v4();
789 let bandwidth_achieved =
790 bytes_transferred as f64 / (1024.0 * 1024.0 * 1024.0) / duration.as_secs_f64();
791
792 let transfer = CrossDeviceTransfer {
793 transfer_id,
794 source_device,
795 target_device,
796 bytes_transferred,
797 transfer_type,
798 duration,
799 bandwidth_achieved,
800 p2p_enabled: self.detect_p2p_capability(source_device, target_device),
801 timestamp: SystemTime::now(),
802 };
803
804 self.cross_device_transfers.push(transfer);
805 Ok(transfer_id)
806 }
807
808 pub fn get_memory_analysis_report(&self) -> MemoryAnalysisReport {
810 let fragmentation_summary = self.analyze_fragmentation_trends();
811 let bandwidth_summary = self.analyze_bandwidth_utilization();
812 let pressure_summary = self.analyze_memory_pressure();
813 let allocation_summary = self.analyze_allocation_patterns();
814 let cross_device_summary = self.analyze_cross_device_transfers();
815
816 MemoryAnalysisReport {
817 fragmentation_summary,
818 bandwidth_summary,
819 pressure_summary,
820 allocation_summary,
821 cross_device_summary,
822 optimization_recommendations: self.generate_memory_optimization_recommendations(),
823 }
824 }
825
826 fn calculate_optimal_alignment(&self, size_bytes: usize) -> usize {
827 if size_bytes >= 128 {
829 128 } else if size_bytes >= 64 {
831 64
832 } else if size_bytes >= 32 {
833 32
834 } else {
835 16
836 }
837 }
838
839 fn update_memory_pressure(&mut self, device_id: i32) {
840 let Some((pressure_level, available_memory_ratio)) =
841 self.memory_pools.get(&device_id).map(|pool| {
842 (
843 pool.calculate_pressure_level(),
844 pool.get_available_memory_ratio(),
845 )
846 })
847 else {
848 return;
849 };
850 let allocation_rate = self.calculate_allocation_rate(device_id);
851 let deallocation_rate = self.calculate_deallocation_rate(device_id);
852 let swap_activity = self.compute_swap_activity_delta();
853
854 let pressure_snapshot = MemoryPressureSnapshot {
855 timestamp: Utc::now(),
856 device_id,
857 pressure_level,
858 available_memory_ratio,
859 allocation_rate,
860 deallocation_rate,
861 gc_pressure: None,
865 swap_activity,
866 };
867
868 self.memory_pressure_monitor.add_snapshot(pressure_snapshot);
869 }
870
871 fn compute_swap_activity_delta(&mut self) -> Option<f64> {
878 self.system_info.refresh_memory();
879 let used = self.system_info.used_swap();
880 let delta = self.last_used_swap_bytes.map(|prev| used as f64 - prev as f64);
881 self.last_used_swap_bytes = Some(used);
882 delta
883 }
884
885 fn detect_p2p_capability(&self, _source: i32, _target: i32) -> Option<bool> {
892 None
893 }
894
895 fn calculate_allocation_rate(&self, device_id: i32) -> f64 {
896 let recent_allocations = self
898 .memory_allocations
899 .values()
900 .filter(|a| a.device_id == device_id)
901 .filter(|a| a.timestamp.elapsed().unwrap_or_default().as_secs() < 60)
902 .count();
903
904 recent_allocations as f64 / 60.0
905 }
906
907 fn calculate_deallocation_rate(&self, device_id: i32) -> f64 {
908 let recent_deallocations = self
910 .memory_allocations
911 .values()
912 .filter(|a| a.device_id == device_id && a.freed)
913 .filter(|a| {
914 if let Some(free_time) = a.free_timestamp {
915 free_time.elapsed().unwrap_or_default().as_secs() < 60
916 } else {
917 false
918 }
919 })
920 .count();
921
922 recent_deallocations as f64 / 60.0
923 }
924
925 fn analyze_fragmentation_trends(&self) -> FragmentationSummary {
926 FragmentationSummary::new(&self.fragmentation_history)
928 }
929
930 fn analyze_bandwidth_utilization(&self) -> BandwidthSummary {
931 BandwidthSummary::new(&self.bandwidth_monitors)
932 }
933
934 fn analyze_memory_pressure(&self) -> MemoryPressureSummary {
935 self.memory_pressure_monitor.get_summary()
936 }
937
938 fn analyze_allocation_patterns(&self) -> AllocationPatternSummary {
939 AllocationPatternSummary::new(&self.memory_allocations)
940 }
941
942 fn analyze_cross_device_transfers(&self) -> CrossDeviceTransferSummary {
943 CrossDeviceTransferSummary::new(&self.cross_device_transfers)
944 }
945
946 fn generate_memory_optimization_recommendations(
947 &self,
948 ) -> Vec<MemoryOptimizationRecommendation> {
949 let mut recommendations = Vec::new();
950
951 for snapshot in self.fragmentation_history.iter().take(10) {
959 let Some(ratio) = snapshot.fragmentation_ratio else {
960 continue;
961 };
962 if ratio > 0.3 {
963 recommendations.push(MemoryOptimizationRecommendation {
964 recommendation_type: MemoryOptimizationType::DefragmentationStrategy,
965 priority: OptimizationPriority::High,
966 description: format!(
967 "High fragmentation detected on device {}: {:.1}%",
968 snapshot.device_id,
969 ratio * 100.0
970 ),
971 expected_benefit: ExpectedBenefit {
972 performance_improvement: 15.0,
973 memory_efficiency_improvement: 25.0,
974 implementation_effort: ImplementationDifficulty::Moderate,
975 },
976 implementation_steps: vec![
977 "Implement memory pooling with fixed-size blocks".to_string(),
978 "Add periodic defragmentation during idle periods".to_string(),
979 "Consider memory compaction strategies".to_string(),
980 ],
981 });
982 }
983 }
984
985 recommendations
986 }
987}
988
989#[derive(Debug, Clone, Serialize, Deserialize)]
992pub struct MemoryAnalysisReport {
993 pub fragmentation_summary: FragmentationSummary,
994 pub bandwidth_summary: BandwidthSummary,
995 pub pressure_summary: MemoryPressureSummary,
996 pub allocation_summary: AllocationPatternSummary,
997 pub cross_device_summary: CrossDeviceTransferSummary,
998 pub optimization_recommendations: Vec<MemoryOptimizationRecommendation>,
999}
1000
1001#[derive(Debug, Clone, Serialize, Deserialize)]
1002pub struct FragmentationSummary {
1003 pub avg_fragmentation_ratio: Option<f64>,
1009 pub peak_fragmentation_ratio: Option<f64>,
1010 pub fragmentation_trend: FragmentationTrend,
1011 pub most_fragmented_device: Option<i32>,
1012}
1013
1014#[derive(Debug, Clone, Serialize, Deserialize)]
1015pub enum FragmentationTrend {
1016 Improving,
1017 Stable,
1018 Worsening,
1019}
1020
1021#[derive(Debug, Clone, Serialize, Deserialize)]
1022pub struct BandwidthSummary {
1023 pub avg_bandwidth_utilization: Option<f64>,
1029 pub peak_bandwidth_achieved: f64,
1033 pub bandwidth_efficiency_by_operation: HashMap<String, f64>,
1034 pub underutilized_devices: Vec<i32>,
1035}
1036
1037#[derive(Debug, Clone, Serialize, Deserialize)]
1038pub struct MemoryPressureSummary {
1039 pub current_pressure_levels: HashMap<i32, MemoryPressureLevel>,
1040 pub pressure_trend: PressureTrend,
1041 pub devices_under_pressure: Vec<i32>,
1042 pub time_in_high_pressure: Duration,
1043}
1044
1045#[derive(Debug, Clone, Serialize, Deserialize)]
1046pub enum PressureTrend {
1047 Decreasing,
1048 Stable,
1049 Increasing,
1050}
1051
1052#[derive(Debug, Clone, Serialize, Deserialize)]
1053pub struct AllocationPatternSummary {
1054 pub total_allocations: usize,
1055 pub avg_allocation_size: usize,
1056 pub largest_allocation: usize,
1057 pub allocation_size_distribution: HashMap<String, usize>,
1058 pub memory_leaks_detected: usize,
1059 pub allocation_hot_spots: Vec<AllocationHotSpot>,
1060}
1061
1062#[derive(Debug, Clone, Serialize, Deserialize)]
1063pub struct AllocationHotSpot {
1064 pub location: String,
1065 pub allocation_frequency: f64,
1066 pub total_memory_allocated: usize,
1067 pub avg_allocation_lifetime: Duration,
1068}
1069
1070#[derive(Debug, Clone, Serialize, Deserialize)]
1071pub struct CrossDeviceTransferSummary {
1072 pub total_transfers: usize,
1073 pub total_bytes_transferred: usize,
1074 pub avg_transfer_bandwidth: f64,
1075 pub p2p_efficiency: Option<f64>,
1079 pub transfer_bottlenecks: Vec<TransferBottleneck>,
1080}
1081
1082#[derive(Debug, Clone, Serialize, Deserialize)]
1083pub struct TransferBottleneck {
1084 pub device_pair: (i32, i32),
1085 pub bottleneck_type: TransferBottleneckType,
1086 pub impact_severity: f64,
1087}
1088
1089#[derive(Debug, Clone, Serialize, Deserialize)]
1090pub enum TransferBottleneckType {
1091 BandwidthLimited,
1092 LatencyBound,
1093 SynchronizationOverhead,
1094 P2PNotAvailable,
1095}
1096
1097#[derive(Debug, Clone, Serialize, Deserialize)]
1098pub struct MemoryOptimizationRecommendation {
1099 pub recommendation_type: MemoryOptimizationType,
1100 pub priority: OptimizationPriority,
1101 pub description: String,
1102 pub expected_benefit: ExpectedBenefit,
1103 pub implementation_steps: Vec<String>,
1104}
1105
1106#[derive(Debug, Clone, Serialize, Deserialize)]
1107pub enum MemoryOptimizationType {
1108 DefragmentationStrategy,
1109 MemoryPoolingOptimization,
1110 AllocationPatternOptimization,
1111 CrossDeviceTransferOptimization,
1112 PressureReliefStrategy,
1113}
1114
1115#[derive(Debug, Clone, Serialize, Deserialize)]
1116pub enum OptimizationPriority {
1117 Critical,
1118 High,
1119 Medium,
1120 Low,
1121}
1122
1123#[derive(Debug, Clone, Serialize, Deserialize)]
1124pub struct ExpectedBenefit {
1125 pub performance_improvement: f64,
1126 pub memory_efficiency_improvement: f64,
1127 pub implementation_effort: ImplementationDifficulty,
1128}
1129
1130impl Default for MemoryAccessPattern {
1133 fn default() -> Self {
1134 Self {
1135 access_frequency: 0.0,
1136 read_ratio: 0.5,
1137 write_ratio: 0.5,
1138 sequential_access_ratio: 0.8,
1139 random_access_ratio: 0.2,
1140 coalesced_access_ratio: 0.9,
1141 cache_hit_rate: 0.85,
1142 }
1143 }
1144}
1145
1146const ASSUMED_DEVICE_MEMORY_BYTES: usize = 8 * 1024 * 1024 * 1024; impl GpuMemoryPool {
1159 fn new(device_id: i32) -> Result<Self> {
1160 Ok(Self {
1161 device_id,
1162 total_memory: ASSUMED_DEVICE_MEMORY_BYTES,
1163 free_memory: ASSUMED_DEVICE_MEMORY_BYTES,
1164 })
1165 }
1166
1167 fn allocate(&mut self, size: usize) -> Result<()> {
1168 if self.free_memory >= size {
1169 self.free_memory -= size;
1170 Ok(())
1171 } else {
1172 Err(anyhow::anyhow!("Insufficient memory"))
1173 }
1174 }
1175
1176 fn deallocate(&mut self, size: usize) -> Result<()> {
1177 self.free_memory += size;
1178 Ok(())
1179 }
1180
1181 fn get_fragmentation_snapshot(&self) -> Result<MemoryFragmentationSnapshot> {
1187 Ok(MemoryFragmentationSnapshot {
1188 timestamp: Utc::now(),
1189 device_id: self.device_id,
1190 total_memory: self.total_memory,
1191 free_memory: self.free_memory,
1192 largest_free_block: None,
1193 fragmentation_ratio: None,
1194 free_block_distribution: None,
1195 external_fragmentation: None,
1196 internal_fragmentation: None,
1197 })
1198 }
1199
1200 fn calculate_pressure_level(&self) -> MemoryPressureLevel {
1201 let usage_ratio = 1.0 - (self.free_memory as f64 / self.total_memory as f64);
1202
1203 if usage_ratio > 0.95 {
1204 MemoryPressureLevel::Critical
1205 } else if usage_ratio > 0.85 {
1206 MemoryPressureLevel::High
1207 } else if usage_ratio > 0.70 {
1208 MemoryPressureLevel::Medium
1209 } else {
1210 MemoryPressureLevel::Low
1211 }
1212 }
1213
1214 fn get_available_memory_ratio(&self) -> f64 {
1215 self.free_memory as f64 / self.total_memory as f64
1216 }
1217}
1218
1219impl GpuBandwidthMonitor {
1220 fn new(device_id: i32) -> Result<Self> {
1221 Ok(Self {
1222 device_id,
1223 bandwidth_samples: VecDeque::with_capacity(1000),
1224 theoretical_bandwidth: 900.0, peak_observed_bandwidth: 0.0,
1226 sustained_bandwidth_history: Vec::new(),
1227 })
1228 }
1229
1230 fn add_sample(&mut self, sample: BandwidthSample) -> Result<()> {
1231 if sample.achieved_bandwidth_gb_s > self.peak_observed_bandwidth {
1232 self.peak_observed_bandwidth = sample.achieved_bandwidth_gb_s;
1233 }
1234
1235 self.bandwidth_samples.push_back(sample);
1236 if self.bandwidth_samples.len() > 1000 {
1237 self.bandwidth_samples.pop_front();
1238 }
1239
1240 Ok(())
1241 }
1242}
1243
1244impl MemoryPressureMonitor {
1245 fn new() -> Self {
1246 Self {
1247 pressure_history: VecDeque::with_capacity(1000),
1248 pressure_thresholds: MemoryPressureThresholds {
1249 medium_threshold: 0.7,
1250 high_threshold: 0.85,
1251 critical_threshold: 0.95,
1252 },
1253 auto_optimization_enabled: true,
1254 }
1255 }
1256
1257 fn add_snapshot(&mut self, snapshot: MemoryPressureSnapshot) {
1258 self.pressure_history.push_back(snapshot);
1259 if self.pressure_history.len() > 1000 {
1260 self.pressure_history.pop_front();
1261 }
1262 }
1263
1264 fn get_summary(&self) -> MemoryPressureSummary {
1271 let mut current_pressure_levels: HashMap<i32, MemoryPressureLevel> = HashMap::new();
1275 for snapshot in &self.pressure_history {
1276 current_pressure_levels.insert(snapshot.device_id, snapshot.pressure_level.clone());
1277 }
1278
1279 let devices_under_pressure: Vec<i32> = current_pressure_levels
1280 .iter()
1281 .filter(|(_, level)| {
1282 matches!(
1283 level,
1284 MemoryPressureLevel::High | MemoryPressureLevel::Critical
1285 )
1286 })
1287 .map(|(&device_id, _)| device_id)
1288 .collect();
1289
1290 let pressure_trend = if self.pressure_history.len() < 4 {
1295 PressureTrend::Stable
1296 } else {
1297 let ordinals: Vec<f64> = self
1298 .pressure_history
1299 .iter()
1300 .map(|s| pressure_ordinal(&s.pressure_level))
1301 .collect();
1302 let mid = ordinals.len() / 2;
1303 let older_avg = ordinals[..mid].iter().sum::<f64>() / mid as f64;
1304 let recent_avg = ordinals[mid..].iter().sum::<f64>() / (ordinals.len() - mid) as f64;
1305 let trend_threshold = 0.25;
1306 if recent_avg > older_avg + trend_threshold {
1307 PressureTrend::Increasing
1308 } else if recent_avg < older_avg - trend_threshold {
1309 PressureTrend::Decreasing
1310 } else {
1311 PressureTrend::Stable
1312 }
1313 };
1314
1315 let mut by_device: HashMap<i32, Vec<&MemoryPressureSnapshot>> = HashMap::new();
1320 for snapshot in &self.pressure_history {
1321 by_device.entry(snapshot.device_id).or_default().push(snapshot);
1322 }
1323 let mut time_in_high_pressure = Duration::from_secs(0);
1324 for snapshots in by_device.values_mut() {
1325 snapshots.sort_by_key(|s| s.timestamp);
1326 for pair in snapshots.windows(2) {
1327 let (a, b) = (pair[0], pair[1]);
1328 if matches!(
1329 a.pressure_level,
1330 MemoryPressureLevel::High | MemoryPressureLevel::Critical
1331 ) {
1332 if let Ok(gap) = (b.timestamp - a.timestamp).to_std() {
1333 time_in_high_pressure += gap;
1334 }
1335 }
1336 }
1337 }
1338
1339 MemoryPressureSummary {
1340 current_pressure_levels,
1341 pressure_trend,
1342 devices_under_pressure,
1343 time_in_high_pressure,
1344 }
1345 }
1346}
1347
1348fn pressure_ordinal(level: &MemoryPressureLevel) -> f64 {
1352 match level {
1353 MemoryPressureLevel::Low => 0.0,
1354 MemoryPressureLevel::Medium => 1.0,
1355 MemoryPressureLevel::High => 2.0,
1356 MemoryPressureLevel::Critical => 3.0,
1357 }
1358}
1359
1360impl FragmentationSummary {
1366 fn new(history: &VecDeque<MemoryFragmentationSnapshot>) -> Self {
1367 let measured: Vec<(i32, f64)> = history
1368 .iter()
1369 .filter_map(|s| s.fragmentation_ratio.map(|r| (s.device_id, r)))
1370 .collect();
1371
1372 let Some(&(first_device, _)) = measured.first() else {
1373 return Self {
1377 avg_fragmentation_ratio: None,
1378 peak_fragmentation_ratio: None,
1379 fragmentation_trend: FragmentationTrend::Stable,
1380 most_fragmented_device: None,
1381 };
1382 };
1383
1384 let avg = measured.iter().map(|(_, r)| r).sum::<f64>() / measured.len() as f64;
1385 let (peak_device, peak_ratio) =
1386 measured.iter().fold((first_device, f64::MIN), |(bd, br), &(d, r)| {
1387 if r > br {
1388 (d, r)
1389 } else {
1390 (bd, br)
1391 }
1392 });
1393
1394 let fragmentation_trend = if measured.len() < 4 {
1395 FragmentationTrend::Stable
1396 } else {
1397 let mid = measured.len() / 2;
1398 let older_avg = measured[..mid].iter().map(|(_, r)| r).sum::<f64>() / mid as f64;
1399 let recent_avg =
1400 measured[mid..].iter().map(|(_, r)| r).sum::<f64>() / (measured.len() - mid) as f64;
1401 let trend_threshold = 0.05;
1402 if recent_avg > older_avg + trend_threshold {
1403 FragmentationTrend::Worsening
1404 } else if recent_avg < older_avg - trend_threshold {
1405 FragmentationTrend::Improving
1406 } else {
1407 FragmentationTrend::Stable
1408 }
1409 };
1410
1411 Self {
1412 avg_fragmentation_ratio: Some(avg),
1413 peak_fragmentation_ratio: Some(peak_ratio),
1414 fragmentation_trend,
1415 most_fragmented_device: Some(peak_device),
1416 }
1417 }
1418}
1419
1420impl BandwidthSummary {
1421 fn new(monitors: &HashMap<i32, GpuBandwidthMonitor>) -> Self {
1422 let peak_bandwidth_achieved =
1423 monitors.values().map(|m| m.peak_observed_bandwidth).fold(0.0_f64, f64::max);
1424
1425 let mut efficiency_sum: HashMap<String, (f64, usize)> = HashMap::new();
1429 for monitor in monitors.values() {
1430 for sample in &monitor.bandwidth_samples {
1431 let entry = efficiency_sum
1432 .entry(format!("{:?}", sample.operation_type))
1433 .or_insert((0.0, 0));
1434 entry.0 += sample.efficiency_percentage;
1435 entry.1 += 1;
1436 }
1437 }
1438 let bandwidth_efficiency_by_operation: HashMap<String, f64> = efficiency_sum
1439 .into_iter()
1440 .map(|(op, (sum, count))| (op, sum / count as f64))
1441 .collect();
1442
1443 let underutilized_devices: Vec<i32> = if peak_bandwidth_achieved > 0.0 {
1449 monitors
1450 .iter()
1451 .filter(|(_, m)| !m.bandwidth_samples.is_empty())
1452 .filter(|(_, m)| m.peak_observed_bandwidth < peak_bandwidth_achieved * 0.5)
1453 .map(|(&device_id, _)| device_id)
1454 .collect()
1455 } else {
1456 Vec::new()
1457 };
1458
1459 Self {
1460 avg_bandwidth_utilization: None,
1461 peak_bandwidth_achieved,
1462 bandwidth_efficiency_by_operation,
1463 underutilized_devices,
1464 }
1465 }
1466}
1467
1468impl AllocationPatternSummary {
1469 fn new(allocations: &HashMap<Uuid, GpuMemoryAllocation>) -> Self {
1470 let total_allocations = allocations.len();
1471 let total_bytes: u128 = allocations.values().map(|a| a.size_bytes as u128).sum();
1472 let avg_allocation_size = if total_allocations > 0 {
1473 (total_bytes / total_allocations as u128) as usize
1474 } else {
1475 0
1476 };
1477 let largest_allocation = allocations.values().map(|a| a.size_bytes).max().unwrap_or(0);
1478
1479 let mut allocation_size_distribution: HashMap<String, usize> = HashMap::new();
1480 for allocation in allocations.values() {
1481 *allocation_size_distribution
1482 .entry(format!("{:?}", allocation.memory_type))
1483 .or_insert(0) += 1;
1484 }
1485
1486 const LEAK_SUSPECT_THRESHOLD: Duration = Duration::from_secs(300);
1492 let memory_leaks_detected = allocations
1493 .values()
1494 .filter(|a| {
1495 !a.freed && a.timestamp.elapsed().unwrap_or_default() > LEAK_SUSPECT_THRESHOLD
1496 })
1497 .count();
1498
1499 let observation_span_secs = {
1508 let timestamps: Vec<SystemTime> = allocations.values().map(|a| a.timestamp).collect();
1509 match (timestamps.iter().min(), timestamps.iter().max()) {
1510 (Some(&min_t), Some(&max_t)) => {
1511 max_t.duration_since(min_t).unwrap_or_default().as_secs_f64()
1512 },
1513 _ => 0.0,
1514 }
1515 };
1516
1517 let mut by_location: HashMap<String, (usize, u64, Duration, usize)> = HashMap::new();
1518 for allocation in allocations.values() {
1519 let location = allocation
1520 .allocation_context
1521 .tensor_name
1522 .clone()
1523 .or_else(|| allocation.allocation_context.layer_name.clone())
1524 .or_else(|| allocation.allocation_context.kernel_name.clone())
1525 .unwrap_or_else(|| {
1526 format!("{:?}", allocation.allocation_context.allocation_source)
1527 });
1528 let entry = by_location.entry(location).or_insert((0, 0, Duration::ZERO, 0));
1529 entry.0 += 1;
1530 entry.1 += allocation.size_bytes as u64;
1531 if let Some(free_time) = allocation.free_timestamp {
1532 if let Ok(lifetime) = free_time.duration_since(allocation.timestamp) {
1533 entry.2 += lifetime;
1534 entry.3 += 1;
1535 }
1536 }
1537 }
1538 let mut allocation_hot_spots: Vec<AllocationHotSpot> = by_location
1539 .into_iter()
1540 .map(
1541 |(location, (count, bytes, total_lifetime, freed_count))| AllocationHotSpot {
1542 location,
1543 allocation_frequency: if observation_span_secs > 0.0 {
1544 count as f64 / observation_span_secs
1545 } else {
1546 count as f64
1547 },
1548 total_memory_allocated: bytes as usize,
1549 avg_allocation_lifetime: if freed_count > 0 {
1550 total_lifetime / freed_count as u32
1551 } else {
1552 Duration::ZERO
1553 },
1554 },
1555 )
1556 .collect();
1557 allocation_hot_spots.sort_by_key(|h| std::cmp::Reverse(h.total_memory_allocated));
1558 allocation_hot_spots.truncate(10);
1559
1560 Self {
1561 total_allocations,
1562 avg_allocation_size,
1563 largest_allocation,
1564 allocation_size_distribution,
1565 memory_leaks_detected,
1566 allocation_hot_spots,
1567 }
1568 }
1569}
1570
1571impl CrossDeviceTransferSummary {
1572 fn new(transfers: &[CrossDeviceTransfer]) -> Self {
1573 let total_transfers = transfers.len();
1574 let total_bytes_transferred: usize = transfers.iter().map(|t| t.bytes_transferred).sum();
1575 let avg_transfer_bandwidth = if total_transfers > 0 {
1576 transfers.iter().map(|t| t.bandwidth_achieved).sum::<f64>() / total_transfers as f64
1577 } else {
1578 0.0
1579 };
1580
1581 let mut by_pair: HashMap<(i32, i32), Vec<f64>> = HashMap::new();
1588 for t in transfers {
1589 by_pair
1590 .entry((t.source_device, t.target_device))
1591 .or_default()
1592 .push(t.bandwidth_achieved);
1593 }
1594 let transfer_bottlenecks: Vec<TransferBottleneck> = if avg_transfer_bandwidth > 0.0 {
1595 by_pair
1596 .into_iter()
1597 .filter_map(|(pair, bandwidths)| {
1598 let pair_avg = bandwidths.iter().sum::<f64>() / bandwidths.len() as f64;
1599 if pair_avg < avg_transfer_bandwidth * 0.5 {
1600 Some(TransferBottleneck {
1601 device_pair: pair,
1602 bottleneck_type: TransferBottleneckType::BandwidthLimited,
1603 impact_severity: (1.0 - pair_avg / avg_transfer_bandwidth)
1604 .clamp(0.0, 1.0),
1605 })
1606 } else {
1607 None
1608 }
1609 })
1610 .collect()
1611 } else {
1612 Vec::new()
1613 };
1614
1615 Self {
1616 total_transfers,
1617 total_bytes_transferred,
1618 avg_transfer_bandwidth,
1619 p2p_efficiency: None,
1622 transfer_bottlenecks,
1623 }
1624 }
1625}
1626
1627#[derive(Debug)]
1628struct GpuMemoryPool {
1629 device_id: i32,
1630 total_memory: usize,
1631 free_memory: usize,
1632}
1633
1634#[derive(Debug, Clone, Serialize, Deserialize)]
1636pub struct AdvancedGpuProfilingConfig {
1637 pub enable_gpu_profiling: bool,
1639 pub device_count: i32,
1641 pub enable_memory_profiling: bool,
1643 pub enable_kernel_profiling: bool,
1645 pub enable_bandwidth_monitoring: bool,
1647 pub max_tracked_allocations: usize,
1649 pub profiling_sampling_rate: f32,
1651 pub enable_fragmentation_analysis: bool,
1653}
1654
1655impl Default for AdvancedGpuProfilingConfig {
1656 fn default() -> Self {
1657 Self {
1658 enable_gpu_profiling: true,
1659 device_count: 1,
1660 enable_memory_profiling: true,
1661 enable_kernel_profiling: true,
1662 enable_bandwidth_monitoring: true,
1663 max_tracked_allocations: 10000,
1664 profiling_sampling_rate: 1.0,
1665 enable_fragmentation_analysis: true,
1666 }
1667 }
1668}
1669
1670#[derive(Debug, Clone, Serialize, Deserialize)]
1672pub struct KernelOptimizationSummaryReport {
1673 pub total_kernels_analyzed: usize,
1674 pub optimization_opportunities_found: usize,
1675 pub high_impact_optimizations: Vec<HighImpactOptimization>,
1676 pub fusion_opportunities: usize,
1677 pub regression_alerts: usize,
1678 pub overall_optimization_score: Option<f64>,
1681 pub top_recommendations: Vec<String>,
1682}
1683
1684#[derive(Debug, Clone, Serialize, Deserialize)]
1685pub struct HighImpactOptimization {
1686 pub kernel_name: String,
1687 pub optimization_type: String,
1688 pub expected_speedup: f64,
1689 pub implementation_difficulty: String,
1690 pub description: String,
1691}
1692
1693#[cfg(test)]
1694#[path = "advanced_gpu_profiler_tests.rs"]
1695mod advanced_gpu_profiler_tests;