1#![allow(dead_code)]
9
10use anyhow::Result;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13use std::time::Duration;
14use uuid::Uuid;
15
16use crate::advanced_gpu_profiler::{
17 AccessLocalityMetrics, CachePerformanceAnalysis, CoalescingAnalysis, ComputeBottleneckAnalysis,
18 ComputeBottleneckType, ComputeUtilizationProfile, ConfigPerformanceMeasurement,
19 ImplementationDifficulty, InstructionMixAnalysis, KernelExecutionProfile, KernelOptimization,
20 MemoryAccessAnalysis, OptimalLaunchConfig, ResourceUtilizationMetrics,
21};
22
23mod analysis;
26
27mod regression;
32pub use regression::*;
33
34#[derive(Debug)]
36pub struct KernelOptimizationAnalyzer {
37 kernel_profiles: HashMap<String, KernelExecutionProfile>,
38 optimization_suggestions: HashMap<String, Vec<KernelOptimization>>,
39 launch_config_analyzer: LaunchConfigAnalyzer,
40 memory_access_analyzer: MemoryAccessAnalyzer,
41 compute_utilization_analyzer: ComputeUtilizationAnalyzer,
42 fusion_analyzer: KernelFusionAnalyzer,
43 performance_regression_detector: PerformanceRegressionDetector,
44}
45
46#[derive(Debug)]
48pub struct LaunchConfigAnalyzer {
49 optimal_configs: HashMap<String, OptimalLaunchConfig>,
50 config_performance_history: HashMap<String, Vec<ConfigPerformanceMeasurement>>,
51 autotuning_enabled: bool,
52 search_space_cache: HashMap<String, LaunchConfigSearchSpace>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct LaunchConfigSearchSpace {
57 pub kernel_name: String,
58 pub min_block_size: (u32, u32, u32),
59 pub max_block_size: (u32, u32, u32),
60 pub block_size_constraints: Vec<BlockSizeConstraint>,
61 pub shared_memory_constraints: MemoryConstraints,
62 pub register_constraints: RegisterConstraints,
63 pub occupancy_targets: OccupancyTargets,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub enum BlockSizeConstraint {
68 MultipleOf(u32),
69 PowerOfTwo,
70 MaxThreadsPerBlock(u32),
71 SharedMemoryLimit(usize),
72 RegisterLimit(u32),
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct MemoryConstraints {
77 pub max_shared_memory_per_block: usize,
78 pub bank_conflict_aware: bool,
79 pub coalescing_optimization: bool,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct RegisterConstraints {
84 pub max_registers_per_thread: u32,
85 pub spill_threshold: u32,
86 pub occupancy_impact_threshold: f64,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct OccupancyTargets {
91 pub minimum_occupancy: f64,
92 pub target_occupancy: f64,
93 pub theoretical_occupancy: f64,
94}
95
96#[derive(Debug)]
98pub struct MemoryAccessAnalyzer {
99 access_patterns: HashMap<String, MemoryAccessAnalysis>,
100 coalescing_analysis: HashMap<String, CoalescingAnalysis>,
101 cache_performance: HashMap<String, CachePerformanceAnalysis>,
102 stride_analysis: HashMap<String, StrideAnalysisResult>,
103 bank_conflict_analyzer: BankConflictAnalyzer,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct StrideAnalysisResult {
108 pub kernel_name: String,
109 pub detected_strides: Vec<DetectedStride>,
110 pub access_pattern_classification: AccessPatternType,
111 pub optimization_potential: f64,
112 pub recommended_optimizations: Vec<StrideOptimization>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct DetectedStride {
117 pub stride_bytes: usize,
118 pub frequency: u64,
119 pub memory_region: String,
120 pub performance_impact: StrideImpact,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub enum StrideImpact {
125 Optimal, Good, Moderate, Poor, Critical, }
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub enum AccessPatternType {
134 Sequential,
135 Strided,
136 Random,
137 Blocked,
138 Sparse,
139 Irregular,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct StrideOptimization {
144 pub optimization_type: StrideOptimizationType,
145 pub description: String,
146 pub expected_improvement: f64,
147 pub implementation_complexity: ImplementationDifficulty,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub enum StrideOptimizationType {
152 DataLayoutReorganization,
153 AccessReordering,
154 TilingStrategy,
155 PrefetchingStrategy,
156 VectorizedAccess,
157}
158
159#[derive(Debug)]
161pub struct BankConflictAnalyzer {
162 conflict_patterns: HashMap<String, BankConflictPattern>,
163 resolution_strategies: HashMap<String, Vec<ConflictResolutionStrategy>>,
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct BankConflictPattern {
168 pub kernel_name: String,
169 pub conflict_count: u64,
170 pub conflict_severity: ConflictSeverity,
171 pub conflicting_addresses: Vec<ConflictingAccess>,
172 pub bank_utilization: Vec<f64>, }
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub enum ConflictSeverity {
177 None,
178 Low, Medium, High, Severe, }
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct ConflictingAccess {
186 pub address_pattern: String,
187 pub conflict_degree: u32,
188 pub access_frequency: u64,
189 pub performance_penalty: f64,
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct ConflictResolutionStrategy {
194 pub strategy_type: ConflictResolutionType,
195 pub description: String,
196 pub expected_speedup: f64,
197 pub implementation_steps: Vec<String>,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
201pub enum ConflictResolutionType {
202 ArrayPadding,
203 AccessReordering,
204 DataStructureReorganization,
205 BroadcastOptimization,
206 MemoryLayoutChange,
207}
208
209#[derive(Debug)]
211pub struct ComputeUtilizationAnalyzer {
212 utilization_profiles: HashMap<String, ComputeUtilizationProfile>,
213 bottleneck_analysis: HashMap<String, ComputeBottleneckAnalysis>,
214 arithmetic_intensity_analyzer: ArithmeticIntensityAnalyzer,
215 resource_balancer: ResourceBalancer,
216}
217
218#[derive(Debug)]
219pub struct ArithmeticIntensityAnalyzer {
220 intensity_profiles: HashMap<String, ArithmeticIntensityProfile>,
221 roofline_models: HashMap<i32, RooflineModel>, }
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct ArithmeticIntensityProfile {
226 pub kernel_name: String,
227 pub operations_per_byte: f64,
228 pub compute_intensity: ComputeIntensityCategory,
229 pub memory_bound_ratio: f64,
230 pub compute_bound_ratio: f64,
231 pub roofline_position: RooflinePosition,
232 pub optimization_direction: OptimizationDirection,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub enum ComputeIntensityCategory {
237 MemoryBound, Balanced, ComputeBound, }
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct RooflinePosition {
244 pub current_performance: f64, pub theoretical_peak: f64, pub memory_bandwidth_limit: f64, pub efficiency_percentage: f64,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub enum OptimizationDirection {
252 IncreaseComputeIntensity,
253 ImproveMemoryEfficiency,
254 BalanceComputeMemory,
255 OptimizeForLatency,
256}
257
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct RooflineModel {
260 pub device_id: i32,
261 pub peak_compute_performance: f64, pub peak_memory_bandwidth: f64, pub cache_hierarchy: CacheHierarchy,
264 pub compute_capabilities: ComputeCapabilities,
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
268pub struct CacheHierarchy {
269 pub l1_cache_bandwidth: f64,
270 pub l2_cache_bandwidth: f64,
271 pub shared_memory_bandwidth: f64,
272 pub texture_cache_bandwidth: f64,
273 pub constant_cache_bandwidth: f64,
274}
275
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct ComputeCapabilities {
278 pub fp32_performance: f64,
279 pub fp16_performance: f64,
280 pub int32_performance: f64,
281 pub tensor_performance: f64,
282 pub special_function_performance: f64,
283}
284
285#[derive(Debug)]
287pub struct ResourceBalancer {
288 resource_profiles: HashMap<String, ResourceProfile>,
289 balancing_strategies: HashMap<String, Vec<BalancingStrategy>>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
293pub struct ResourceProfile {
294 pub kernel_name: String,
295 pub register_pressure: ResourcePressure,
296 pub shared_memory_pressure: ResourcePressure,
297 pub occupancy_limiting_factor: OccupancyLimitingFactor,
298 pub resource_utilization_efficiency: f64,
299}
300
301#[derive(Debug, Clone, Serialize, Deserialize)]
302pub enum ResourcePressure {
303 Low,
304 Medium,
305 High,
306 Critical,
307}
308
309#[derive(Debug, Clone, Serialize, Deserialize)]
310pub enum OccupancyLimitingFactor {
311 RegisterCount,
312 SharedMemoryUsage,
313 BlockSize,
314 WarpCount,
315 None,
316}
317
318#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct BalancingStrategy {
320 pub strategy_type: BalancingStrategyType,
321 pub description: String,
322 pub expected_occupancy_improvement: f64,
323 pub performance_impact: f64,
324}
325
326#[derive(Debug, Clone, Serialize, Deserialize)]
327pub enum BalancingStrategyType {
328 RegisterOptimization,
329 SharedMemoryOptimization,
330 BlockSizeAdjustment,
331 WorkDistributionOptimization,
332 ResourcePartitioning,
333}
334
335#[derive(Debug)]
337pub struct KernelFusionAnalyzer {
338 fusion_opportunities: HashMap<String, Vec<FusionOpportunity>>,
339 dependency_graph: KernelDependencyGraph,
340 fusion_templates: Vec<FusionTemplate>,
341 cost_benefit_analyzer: FusionCostBenefitAnalyzer,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct FusionOpportunity {
346 pub opportunity_id: Uuid,
347 pub kernel_group: Vec<String>,
348 pub fusion_type: FusionType,
349 pub data_dependencies: Vec<DataDependency>,
350 pub expected_speedup: f64,
351 pub memory_savings: usize,
352 pub implementation_complexity: ImplementationDifficulty,
353 pub fusion_feasibility: FusionFeasibility,
354}
355
356#[derive(Debug, Clone, Serialize, Deserialize)]
357pub enum FusionType {
358 ElementwiseFusion, ProducerConsumerFusion, LoopFusion, ReductionFusion, ConvolutionFusion, AttentionFusion, }
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct DataDependency {
368 pub source_kernel: String,
369 pub target_kernel: String,
370 pub dependency_type: DependencyType,
371 pub data_size: usize,
372 pub access_pattern: String,
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
376pub enum DependencyType {
377 ReadAfterWrite,
378 WriteAfterRead,
379 WriteAfterWrite,
380 Reduction,
381 Broadcast,
382}
383
384#[derive(Debug, Clone, Serialize, Deserialize)]
385pub struct FusionFeasibility {
386 pub resource_constraints_satisfied: bool,
387 pub register_usage_feasible: bool,
388 pub shared_memory_feasible: bool,
389 pub synchronization_complexity: SynchronizationComplexity,
390 pub fusion_confidence: f64,
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
394pub enum SynchronizationComplexity {
395 None,
396 Minimal,
397 Moderate,
398 Complex,
399 Prohibitive,
400}
401
402#[derive(Debug)]
403pub struct KernelDependencyGraph {
404 nodes: HashMap<String, KernelNode>,
405 edges: Vec<DependencyEdge>,
406 fusion_clusters: Vec<FusionCluster>,
407}
408
409#[derive(Debug, Clone)]
410pub struct KernelNode {
411 pub kernel_name: String,
412 pub execution_time: Duration,
413 pub memory_footprint: usize,
414 pub resource_requirements: ResourceRequirements,
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
418pub struct ResourceRequirements {
419 pub registers_per_thread: u32,
420 pub shared_memory_per_block: usize,
421 pub max_threads_per_block: u32,
422 pub memory_bandwidth_required: f64,
423}
424
425#[derive(Debug, Clone)]
426pub struct DependencyEdge {
427 pub source: String,
428 pub target: String,
429 pub dependency: DataDependency,
430 pub weight: f64, }
432
433#[derive(Debug, Clone)]
434pub struct FusionCluster {
435 pub cluster_id: Uuid,
436 pub kernels: Vec<String>,
437 pub fusion_potential: f64,
438 pub estimated_speedup: f64,
439}
440
441#[derive(Debug, Clone, Serialize, Deserialize)]
442pub struct FusionTemplate {
443 pub template_name: String,
444 pub pattern_signature: String,
445 pub applicable_kernels: Vec<String>,
446 pub fusion_strategy: FusionStrategy,
447 pub expected_benefits: FusionBenefits,
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct FusionStrategy {
452 pub strategy_name: String,
453 pub implementation_approach: String,
454 pub resource_management: String,
455 pub synchronization_strategy: String,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize)]
459pub struct FusionBenefits {
460 pub memory_bandwidth_reduction: f64,
461 pub kernel_launch_overhead_reduction: f64,
462 pub cache_locality_improvement: f64,
463 pub register_pressure_impact: f64,
464}
465
466#[derive(Debug)]
468pub struct FusionCostBenefitAnalyzer {
469 cost_models: HashMap<FusionType, CostModel>,
470 benefit_predictors: HashMap<FusionType, BenefitPredictor>,
471}
472
473#[derive(Debug, Clone, Serialize, Deserialize)]
474pub struct CostModel {
475 pub fusion_type: FusionType,
476 pub development_cost: f64,
477 pub validation_cost: f64,
478 pub maintenance_cost: f64,
479 pub risk_factor: f64,
480}
481
482#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct BenefitPredictor {
484 pub fusion_type: FusionType,
485 pub performance_model: PerformanceModel,
486 pub memory_model: MemoryModel,
487 pub energy_model: EnergyModel,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct PerformanceModel {
492 pub base_speedup_factor: f64,
493 pub scaling_factors: HashMap<String, f64>,
494 pub confidence_interval: (f64, f64),
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
498pub struct MemoryModel {
499 pub memory_reduction_factor: f64,
500 pub bandwidth_savings: f64,
501 pub cache_improvement: f64,
502}
503#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct EnergyModel {
505 pub energy_reduction_factor: f64,
506 pub power_efficiency_improvement: f64,
507}
508
509impl KernelOptimizationAnalyzer {
512 pub fn new() -> Result<Self> {
513 Ok(Self {
514 kernel_profiles: HashMap::new(),
515 optimization_suggestions: HashMap::new(),
516 launch_config_analyzer: LaunchConfigAnalyzer::new()?,
517 memory_access_analyzer: MemoryAccessAnalyzer::new()?,
518 compute_utilization_analyzer: ComputeUtilizationAnalyzer::new()?,
519 fusion_analyzer: KernelFusionAnalyzer::new()?,
520 performance_regression_detector: PerformanceRegressionDetector::new()?,
521 })
522 }
523
524 pub fn new_empty() -> Self {
533 Self {
534 kernel_profiles: HashMap::new(),
535 optimization_suggestions: HashMap::new(),
536 launch_config_analyzer: LaunchConfigAnalyzer::new_empty(),
537 memory_access_analyzer: MemoryAccessAnalyzer::new_empty(),
538 compute_utilization_analyzer: ComputeUtilizationAnalyzer::new_empty(),
539 fusion_analyzer: KernelFusionAnalyzer::new_empty(),
540 performance_regression_detector: PerformanceRegressionDetector::new_empty(),
541 }
542 }
543
544 pub fn analyzed_kernel_names(&self) -> Vec<&str> {
546 self.kernel_profiles.keys().map(String::as_str).collect()
547 }
548
549 pub fn optimization_suggestions(&self) -> &HashMap<String, Vec<KernelOptimization>> {
551 &self.optimization_suggestions
552 }
553
554 pub fn analyze_kernel(
556 &mut self,
557 kernel_name: &str,
558 profile_data: KernelProfileData,
559 ) -> Result<Vec<KernelOptimization>> {
560 self.update_kernel_profile(kernel_name, profile_data.clone())?;
562
563 let launch_config_optimizations =
565 self.launch_config_analyzer.analyze(kernel_name, &profile_data)?;
566 let memory_optimizations =
567 self.memory_access_analyzer.analyze(kernel_name, &profile_data)?;
568 let compute_optimizations =
569 self.compute_utilization_analyzer.analyze(kernel_name, &profile_data)?;
570
571 let mut all_optimizations = Vec::new();
573 all_optimizations.extend(launch_config_optimizations);
574 all_optimizations.extend(memory_optimizations);
575 all_optimizations.extend(compute_optimizations);
576
577 all_optimizations.sort_by(|a, b| {
579 b.expected_improvement
580 .performance_gain_percentage
581 .partial_cmp(&a.expected_improvement.performance_gain_percentage)
582 .unwrap_or(std::cmp::Ordering::Equal)
583 });
584
585 self.optimization_suggestions
587 .insert(kernel_name.to_string(), all_optimizations.clone());
588
589 self.performance_regression_detector
591 .check_regression(kernel_name, &profile_data)?;
592
593 Ok(all_optimizations)
594 }
595
596 pub fn analyze_fusion_opportunities(
598 &mut self,
599 kernel_sequence: &[String],
600 ) -> Result<Vec<FusionOpportunity>> {
601 self.fusion_analyzer.find_fusion_opportunities(kernel_sequence)
602 }
603
604 pub fn get_optimization_report(&self, kernel_name: &str) -> Result<KernelOptimizationReport> {
606 let profile = self
607 .kernel_profiles
608 .get(kernel_name)
609 .ok_or_else(|| anyhow::anyhow!("Kernel profile not found: {}", kernel_name))?;
610
611 let optimizations =
612 self.optimization_suggestions.get(kernel_name).cloned().unwrap_or_default();
613
614 let launch_config_analysis = self.launch_config_analyzer.get_analysis(kernel_name)?;
615 let memory_analysis = self.memory_access_analyzer.get_analysis(kernel_name)?;
616 let compute_analysis = self.compute_utilization_analyzer.get_analysis(kernel_name)?;
617
618 let fusion_opportunities =
619 self.fusion_analyzer.get_opportunities_for_kernel(kernel_name)?;
620 let regression_status = self.performance_regression_detector.get_status(kernel_name)?;
621
622 Ok(KernelOptimizationReport {
623 kernel_name: kernel_name.to_string(),
624 current_performance: profile.clone(),
625 optimization_suggestions: optimizations,
626 launch_config_analysis,
627 memory_analysis,
628 compute_analysis,
629 fusion_opportunities,
630 regression_status,
631 overall_optimization_potential: self.calculate_optimization_potential(kernel_name)?,
632 })
633 }
634
635 fn update_kernel_profile(
636 &mut self,
637 kernel_name: &str,
638 profile_data: KernelProfileData,
639 ) -> Result<()> {
640 let profile = self.kernel_profiles.entry(kernel_name.to_string()).or_insert_with(|| {
641 KernelExecutionProfile {
642 kernel_name: kernel_name.to_string(),
643 execution_count: 0,
644 total_execution_time: Duration::ZERO,
645 avg_execution_time: Duration::ZERO,
646 min_execution_time: Duration::MAX,
647 max_execution_time: Duration::ZERO,
648 grid_sizes: Vec::new(),
649 block_sizes: Vec::new(),
650 shared_memory_usage: Vec::new(),
651 register_usage: Vec::new(),
652 occupancy_measurements: Vec::new(),
653 compute_utilization: Vec::new(),
654 memory_bandwidth_utilization: Vec::new(),
655 warp_efficiency: Vec::new(),
656 memory_efficiency: Vec::new(),
657 }
658 });
659
660 profile.execution_count += 1;
662 profile.total_execution_time += profile_data.execution_time;
663 profile.avg_execution_time = profile.total_execution_time / profile.execution_count as u32;
664
665 if profile_data.execution_time < profile.min_execution_time {
666 profile.min_execution_time = profile_data.execution_time;
667 }
668 if profile_data.execution_time > profile.max_execution_time {
669 profile.max_execution_time = profile_data.execution_time;
670 }
671
672 profile.grid_sizes.push(profile_data.grid_size);
673 profile.block_sizes.push(profile_data.block_size);
674 profile.shared_memory_usage.push(profile_data.shared_memory_bytes);
675 profile.register_usage.push(profile_data.registers_per_thread);
676 profile.occupancy_measurements.push(profile_data.occupancy);
677 profile.compute_utilization.push(profile_data.compute_utilization);
678 profile
679 .memory_bandwidth_utilization
680 .push(profile_data.memory_bandwidth_utilization);
681 profile.warp_efficiency.push(profile_data.warp_efficiency);
682 profile.memory_efficiency.push(profile_data.memory_efficiency);
683
684 Ok(())
685 }
686
687 fn calculate_optimization_potential(&self, kernel_name: &str) -> Result<OptimizationPotential> {
688 let optimizations = self
689 .optimization_suggestions
690 .get(kernel_name)
691 .ok_or_else(|| anyhow::anyhow!("No optimizations found for kernel: {}", kernel_name))?;
692
693 let max_performance_gain = optimizations
694 .iter()
695 .map(|opt| opt.expected_improvement.performance_gain_percentage)
696 .fold(0.0, f64::max);
697
698 let total_memory_savings = optimizations
699 .iter()
700 .map(|opt| opt.expected_improvement.memory_usage_reduction_percentage)
701 .sum::<f64>();
702
703 let avg_implementation_difficulty = optimizations
704 .iter()
705 .map(|opt| match opt.implementation_difficulty {
706 ImplementationDifficulty::Trivial => 1.0,
707 ImplementationDifficulty::Easy => 2.0,
708 ImplementationDifficulty::Moderate => 3.0,
709 ImplementationDifficulty::Difficult => 4.0,
710 ImplementationDifficulty::Expert => 5.0,
711 })
712 .sum::<f64>()
713 / optimizations.len() as f64;
714
715 Ok(OptimizationPotential {
716 max_performance_gain,
717 total_memory_savings,
718 avg_implementation_difficulty,
719 optimization_count: optimizations.len(),
720 priority_score: self
721 .calculate_priority_score(max_performance_gain, avg_implementation_difficulty),
722 })
723 }
724
725 fn calculate_priority_score(&self, performance_gain: f64, difficulty: f64) -> f64 {
726 performance_gain / (difficulty * difficulty)
729 }
730}
731
732#[derive(Debug, Clone, Serialize, Deserialize)]
735pub struct KernelProfileData {
736 pub execution_time: Duration,
737 pub grid_size: (u32, u32, u32),
738 pub block_size: (u32, u32, u32),
739 pub shared_memory_bytes: usize,
740 pub registers_per_thread: u32,
741 pub occupancy: f64,
742 pub compute_utilization: f64,
743 pub memory_bandwidth_utilization: f64,
744 pub warp_efficiency: f64,
745 pub memory_efficiency: f64,
746}
747
748#[derive(Debug, Clone, Serialize, Deserialize)]
749pub struct KernelOptimizationReport {
750 pub kernel_name: String,
751 pub current_performance: KernelExecutionProfile,
752 pub optimization_suggestions: Vec<KernelOptimization>,
753 pub launch_config_analysis: LaunchConfigAnalysisResult,
754 pub memory_analysis: MemoryAnalysisResult,
755 pub compute_analysis: ComputeAnalysisResult,
756 pub fusion_opportunities: Vec<FusionOpportunity>,
757 pub regression_status: Option<RegressionStatus>,
763 pub overall_optimization_potential: OptimizationPotential,
764}
765
766#[derive(Debug, Clone, Serialize, Deserialize)]
767pub struct OptimizationPotential {
768 pub max_performance_gain: f64,
769 pub total_memory_savings: f64,
770 pub avg_implementation_difficulty: f64,
771 pub optimization_count: usize,
772 pub priority_score: f64,
773}
774
775#[derive(Debug, Clone, Serialize, Deserialize)]
776pub struct LaunchConfigAnalysisResult {
777 pub current_config: (u32, u32, u32, u32, u32, u32), pub optimal_config: OptimalLaunchConfig,
779 pub configuration_recommendations: Vec<ConfigurationRecommendation>,
780}
781
782#[derive(Debug, Clone, Serialize, Deserialize)]
783pub struct ConfigurationRecommendation {
784 pub recommendation_type: ConfigurationRecommendationType,
785 pub current_value: String,
786 pub recommended_value: String,
787 pub expected_improvement: f64,
788 pub rationale: String,
789}
790
791#[derive(Debug, Clone, Serialize, Deserialize)]
792pub enum ConfigurationRecommendationType {
793 BlockSizeOptimization,
794 GridSizeOptimization,
795 SharedMemoryOptimization,
796 OccupancyImprovement,
797}
798
799#[derive(Debug, Clone, Serialize, Deserialize)]
800pub struct MemoryAnalysisResult {
801 pub access_pattern_analysis: MemoryAccessAnalysis,
802 pub coalescing_analysis: CoalescingAnalysis,
803 pub cache_performance: CachePerformanceAnalysis,
804 pub memory_optimization_recommendations: Vec<MemoryOptimizationRecommendation>,
805}
806
807#[derive(Debug, Clone, Serialize, Deserialize)]
808pub struct MemoryOptimizationRecommendation {
809 pub recommendation_type: MemoryOptimizationRecommendationType,
810 pub description: String,
811 pub expected_improvement: f64,
812 pub implementation_steps: Vec<String>,
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
816pub enum MemoryOptimizationRecommendationType {
817 CoalescingImprovement,
818 CacheOptimization,
819 StrideOptimization,
820 BankConflictResolution,
821 PrefetchingStrategy,
822}
823
824#[derive(Debug, Clone, Serialize, Deserialize)]
825pub struct ComputeAnalysisResult {
826 pub utilization_profile: ComputeUtilizationProfile,
827 pub bottleneck_analysis: ComputeBottleneckAnalysis,
828 pub arithmetic_intensity_analysis: ArithmeticIntensityProfile,
829 pub resource_utilization_recommendations: Vec<ResourceOptimizationRecommendation>,
830}
831
832#[derive(Debug, Clone, Serialize, Deserialize)]
833pub struct ResourceOptimizationRecommendation {
834 pub recommendation_type: ResourceOptimizationRecommendationType,
835 pub description: String,
836 pub expected_benefit: f64,
837 pub resource_impact: ResourceImpact,
838}
839
840#[derive(Debug, Clone, Serialize, Deserialize)]
841pub enum ResourceOptimizationRecommendationType {
842 RegisterOptimization,
843 SharedMemoryOptimization,
844 OccupancyImprovement,
845 ComputeIntensityBalance,
846 ResourceLoadBalancing,
847}
848
849#[derive(Debug, Clone, Serialize, Deserialize)]
850pub struct ResourceImpact {
851 pub register_usage_change: i32,
852 pub shared_memory_change: i32,
853 pub occupancy_change: f64,
854 pub performance_change: f64,
855}
856
857impl LaunchConfigAnalyzer {
862 fn new() -> Result<Self> {
863 Ok(Self {
864 optimal_configs: HashMap::new(),
865 config_performance_history: HashMap::new(),
866 autotuning_enabled: true,
867 search_space_cache: HashMap::new(),
868 })
869 }
870
871 fn new_empty() -> Self {
872 Self {
873 optimal_configs: HashMap::new(),
874 config_performance_history: HashMap::new(),
875 autotuning_enabled: false,
876 search_space_cache: HashMap::new(),
877 }
878 }
879
880 fn analyze(
881 &mut self,
882 _kernel_name: &str,
883 profile_data: &KernelProfileData,
884 ) -> Result<Vec<KernelOptimization>> {
885 Ok(analysis::analyze_launch_config(profile_data))
889 }
890
891 fn get_analysis(&self, kernel_name: &str) -> Result<LaunchConfigAnalysisResult> {
892 Ok(LaunchConfigAnalysisResult {
894 current_config: (1, 1, 1, 256, 1, 1),
895 optimal_config: OptimalLaunchConfig {
896 kernel_name: kernel_name.to_string(),
897 optimal_block_size: (256, 1, 1),
898 optimal_grid_size: (1024, 1, 1),
899 optimal_shared_memory: 0,
900 expected_occupancy: 1.0,
901 expected_performance: 1.0,
902 constraints: vec![],
903 },
904 configuration_recommendations: vec![],
905 })
906 }
907}
908
909impl MemoryAccessAnalyzer {
910 fn new() -> Result<Self> {
911 Ok(Self {
912 access_patterns: HashMap::new(),
913 coalescing_analysis: HashMap::new(),
914 cache_performance: HashMap::new(),
915 stride_analysis: HashMap::new(),
916 bank_conflict_analyzer: BankConflictAnalyzer::new()?,
917 })
918 }
919
920 fn new_empty() -> Self {
921 Self {
922 access_patterns: HashMap::new(),
923 coalescing_analysis: HashMap::new(),
924 cache_performance: HashMap::new(),
925 stride_analysis: HashMap::new(),
926 bank_conflict_analyzer: BankConflictAnalyzer::new_empty(),
927 }
928 }
929
930 fn analyze(
931 &mut self,
932 _kernel_name: &str,
933 profile_data: &KernelProfileData,
934 ) -> Result<Vec<KernelOptimization>> {
935 Ok(analysis::analyze_memory_access(profile_data))
938 }
939
940 fn get_analysis(&self, kernel_name: &str) -> Result<MemoryAnalysisResult> {
941 Ok(MemoryAnalysisResult {
943 access_pattern_analysis: MemoryAccessAnalysis {
944 kernel_name: kernel_name.to_string(),
945 total_memory_transactions: 0,
946 coalesced_transactions: 0,
947 uncoalesced_transactions: 0,
948 stride_patterns: vec![],
949 access_locality: AccessLocalityMetrics {
950 temporal_locality_score: 0.8,
951 spatial_locality_score: 0.9,
952 working_set_size: 1024,
953 reuse_distance_avg: 10.0,
954 },
955 bank_conflicts: 0,
956 cache_line_utilization: 0.85,
957 },
958 coalescing_analysis: CoalescingAnalysis {
959 kernel_name: kernel_name.to_string(),
960 coalescing_efficiency: 0.9,
961 uncoalesced_regions: vec![],
962 suggested_improvements: vec![],
963 },
964 cache_performance: CachePerformanceAnalysis {
965 kernel_name: kernel_name.to_string(),
966 l1_cache_hit_rate: 0.85,
967 l2_cache_hit_rate: 0.70,
968 texture_cache_hit_rate: 0.95,
969 shared_memory_bank_conflicts: 0,
970 cache_thrashing_detected: false,
971 recommended_cache_optimizations: vec![],
972 },
973 memory_optimization_recommendations: vec![],
974 })
975 }
976}
977
978impl ComputeUtilizationAnalyzer {
979 fn new() -> Result<Self> {
980 Ok(Self {
981 utilization_profiles: HashMap::new(),
982 bottleneck_analysis: HashMap::new(),
983 arithmetic_intensity_analyzer: ArithmeticIntensityAnalyzer::new()?,
984 resource_balancer: ResourceBalancer::new()?,
985 })
986 }
987
988 fn new_empty() -> Self {
989 Self {
990 utilization_profiles: HashMap::new(),
991 bottleneck_analysis: HashMap::new(),
992 arithmetic_intensity_analyzer: ArithmeticIntensityAnalyzer::new_empty(),
993 resource_balancer: ResourceBalancer::new_empty(),
994 }
995 }
996
997 fn analyze(
998 &mut self,
999 _kernel_name: &str,
1000 profile_data: &KernelProfileData,
1001 ) -> Result<Vec<KernelOptimization>> {
1002 Ok(analysis::analyze_compute_utilization(profile_data))
1006 }
1007
1008 fn get_analysis(&self, kernel_name: &str) -> Result<ComputeAnalysisResult> {
1009 Ok(ComputeAnalysisResult {
1011 utilization_profile: ComputeUtilizationProfile {
1012 kernel_name: kernel_name.to_string(),
1013 arithmetic_intensity: 2.5,
1014 compute_throughput: 1000.0,
1015 memory_throughput: 800.0,
1016 compute_to_memory_ratio: 1.25,
1017 warp_execution_efficiency: 0.95,
1018 instruction_mix: InstructionMixAnalysis {
1019 integer_ops_percentage: 20.0,
1020 float_ops_percentage: 70.0,
1021 double_ops_percentage: 5.0,
1022 special_function_ops_percentage: 2.0,
1023 memory_ops_percentage: 25.0,
1024 control_flow_ops_percentage: 3.0,
1025 },
1026 resource_utilization: ResourceUtilizationMetrics {
1027 register_utilization: 0.75,
1028 shared_memory_utilization: 0.60,
1029 constant_memory_utilization: 0.30,
1030 texture_cache_utilization: 0.80,
1031 compute_unit_utilization: 0.85,
1032 },
1033 },
1034 bottleneck_analysis: ComputeBottleneckAnalysis {
1035 kernel_name: kernel_name.to_string(),
1036 primary_bottleneck: ComputeBottleneckType::MemoryBandwidth,
1037 bottleneck_severity: 0.6,
1038 contributing_factors: vec![],
1039 optimization_opportunities: vec![],
1040 },
1041 arithmetic_intensity_analysis: ArithmeticIntensityProfile {
1042 kernel_name: kernel_name.to_string(),
1043 operations_per_byte: 2.5,
1044 compute_intensity: ComputeIntensityCategory::Balanced,
1045 memory_bound_ratio: 0.6,
1046 compute_bound_ratio: 0.4,
1047 roofline_position: RooflinePosition {
1048 current_performance: 800.0,
1049 theoretical_peak: 1000.0,
1050 memory_bandwidth_limit: 900.0,
1051 efficiency_percentage: 80.0,
1052 },
1053 optimization_direction: OptimizationDirection::IncreaseComputeIntensity,
1054 },
1055 resource_utilization_recommendations: vec![],
1056 })
1057 }
1058}
1059
1060impl KernelFusionAnalyzer {
1061 fn new() -> Result<Self> {
1062 Ok(Self {
1063 fusion_opportunities: HashMap::new(),
1064 dependency_graph: KernelDependencyGraph::new(),
1065 fusion_templates: vec![],
1066 cost_benefit_analyzer: FusionCostBenefitAnalyzer::new()?,
1067 })
1068 }
1069
1070 fn new_empty() -> Self {
1071 Self {
1072 fusion_opportunities: HashMap::new(),
1073 dependency_graph: KernelDependencyGraph::new(),
1074 fusion_templates: vec![],
1075 cost_benefit_analyzer: FusionCostBenefitAnalyzer::new_empty(),
1076 }
1077 }
1078
1079 fn find_fusion_opportunities(
1080 &mut self,
1081 kernel_sequence: &[String],
1082 ) -> Result<Vec<FusionOpportunity>> {
1083 let opportunities = analysis::find_fusion_opportunities(kernel_sequence);
1086
1087 for opportunity in &opportunities {
1090 for kernel in &opportunity.kernel_group {
1091 self.fusion_opportunities
1092 .entry(kernel.clone())
1093 .or_default()
1094 .push(opportunity.clone());
1095 }
1096 }
1097
1098 Ok(opportunities)
1099 }
1100
1101 fn get_opportunities_for_kernel(&self, kernel_name: &str) -> Result<Vec<FusionOpportunity>> {
1102 Ok(self.fusion_opportunities.get(kernel_name).cloned().unwrap_or_default())
1103 }
1104}
1105
1106impl BankConflictAnalyzer {
1110 fn new() -> Result<Self> {
1111 Ok(Self {
1112 conflict_patterns: HashMap::new(),
1113 resolution_strategies: HashMap::new(),
1114 })
1115 }
1116
1117 fn new_empty() -> Self {
1118 Self {
1119 conflict_patterns: HashMap::new(),
1120 resolution_strategies: HashMap::new(),
1121 }
1122 }
1123}
1124
1125impl ArithmeticIntensityAnalyzer {
1126 fn new() -> Result<Self> {
1127 Ok(Self {
1128 intensity_profiles: HashMap::new(),
1129 roofline_models: HashMap::new(),
1130 })
1131 }
1132
1133 fn new_empty() -> Self {
1134 Self {
1135 intensity_profiles: HashMap::new(),
1136 roofline_models: HashMap::new(),
1137 }
1138 }
1139}
1140
1141impl ResourceBalancer {
1142 fn new() -> Result<Self> {
1143 Ok(Self {
1144 resource_profiles: HashMap::new(),
1145 balancing_strategies: HashMap::new(),
1146 })
1147 }
1148
1149 fn new_empty() -> Self {
1150 Self {
1151 resource_profiles: HashMap::new(),
1152 balancing_strategies: HashMap::new(),
1153 }
1154 }
1155}
1156
1157impl KernelDependencyGraph {
1158 fn new() -> Self {
1159 Self {
1160 nodes: HashMap::new(),
1161 edges: vec![],
1162 fusion_clusters: vec![],
1163 }
1164 }
1165}
1166
1167impl FusionCostBenefitAnalyzer {
1168 fn new() -> Result<Self> {
1169 Ok(Self {
1170 cost_models: HashMap::new(),
1171 benefit_predictors: HashMap::new(),
1172 })
1173 }
1174
1175 fn new_empty() -> Self {
1176 Self {
1177 cost_models: HashMap::new(),
1178 benefit_predictors: HashMap::new(),
1179 }
1180 }
1181}
1182
1183#[derive(Debug, Clone, Serialize, Deserialize)]
1185pub struct KernelOptimizationConfig {
1186 pub enable_launch_config_optimization: bool,
1188 pub enable_memory_access_optimization: bool,
1190 pub enable_kernel_fusion: bool,
1192 pub enable_regression_detection: bool,
1194 pub max_optimization_suggestions: usize,
1196 pub min_improvement_threshold: f64,
1198}
1199
1200impl Default for KernelOptimizationConfig {
1201 fn default() -> Self {
1202 Self {
1203 enable_launch_config_optimization: true,
1204 enable_memory_access_optimization: true,
1205 enable_kernel_fusion: true,
1206 enable_regression_detection: true,
1207 max_optimization_suggestions: 10,
1208 min_improvement_threshold: 5.0,
1209 }
1210 }
1211}
1212
1213#[cfg(test)]
1214#[path = "kernel_optimizer_tests.rs"]
1215mod kernel_optimizer_tests;
1216
1217#[cfg(test)]
1218mod tests {
1219 use super::*;
1220
1221 #[test]
1222 fn test_kernel_optimization_config_default() {
1223 let config = KernelOptimizationConfig::default();
1224 assert!(config.enable_launch_config_optimization);
1225 assert!(config.enable_memory_access_optimization);
1226 assert!(config.enable_kernel_fusion);
1227 assert!(config.enable_regression_detection);
1228 assert_eq!(config.max_optimization_suggestions, 10);
1229 assert!((config.min_improvement_threshold - 5.0).abs() < f64::EPSILON);
1230 }
1231
1232 #[test]
1233 fn test_launch_config_search_space_creation() {
1234 let space = LaunchConfigSearchSpace {
1235 kernel_name: "matmul_kernel".to_string(),
1236 min_block_size: (1, 1, 1),
1237 max_block_size: (1024, 1024, 64),
1238 block_size_constraints: vec![
1239 BlockSizeConstraint::MultipleOf(32),
1240 BlockSizeConstraint::PowerOfTwo,
1241 ],
1242 shared_memory_constraints: MemoryConstraints {
1243 max_shared_memory_per_block: 49152,
1244 bank_conflict_aware: true,
1245 coalescing_optimization: true,
1246 },
1247 register_constraints: RegisterConstraints {
1248 max_registers_per_thread: 255,
1249 spill_threshold: 64,
1250 occupancy_impact_threshold: 0.5,
1251 },
1252 occupancy_targets: OccupancyTargets {
1253 minimum_occupancy: 0.25,
1254 target_occupancy: 0.75,
1255 theoretical_occupancy: 1.0,
1256 },
1257 };
1258 assert_eq!(space.kernel_name, "matmul_kernel");
1259 assert_eq!(space.block_size_constraints.len(), 2);
1260 }
1261
1262 #[test]
1263 fn test_stride_analysis_result_creation() {
1264 let result = StrideAnalysisResult {
1265 kernel_name: "conv_kernel".to_string(),
1266 detected_strides: vec![DetectedStride {
1267 stride_bytes: 4,
1268 frequency: 1000,
1269 memory_region: "global".to_string(),
1270 performance_impact: StrideImpact::Optimal,
1271 }],
1272 access_pattern_classification: AccessPatternType::Sequential,
1273 optimization_potential: 0.3,
1274 recommended_optimizations: vec![],
1275 };
1276 assert_eq!(result.detected_strides.len(), 1);
1277 assert!(matches!(
1278 result.access_pattern_classification,
1279 AccessPatternType::Sequential
1280 ));
1281 }
1282
1283 #[test]
1284 fn test_bank_conflict_pattern_creation() {
1285 let pattern = BankConflictPattern {
1286 kernel_name: "shared_mem_kernel".to_string(),
1287 conflict_count: 50,
1288 conflict_severity: ConflictSeverity::Medium,
1289 conflicting_addresses: vec![ConflictingAccess {
1290 address_pattern: "stride_4".to_string(),
1291 conflict_degree: 4,
1292 access_frequency: 100,
1293 performance_penalty: 0.15,
1294 }],
1295 bank_utilization: vec![0.8, 0.7, 0.9, 0.6],
1296 };
1297 assert_eq!(pattern.conflict_count, 50);
1298 assert!(matches!(
1299 pattern.conflict_severity,
1300 ConflictSeverity::Medium
1301 ));
1302 }
1303
1304 #[test]
1305 fn test_conflict_resolution_strategy_creation() {
1306 let strategy = ConflictResolutionStrategy {
1307 strategy_type: ConflictResolutionType::ArrayPadding,
1308 description: "Add padding to shared memory arrays".to_string(),
1309 expected_speedup: 1.3,
1310 implementation_steps: vec![
1311 "Identify conflicting arrays".to_string(),
1312 "Add padding to array declarations".to_string(),
1313 ],
1314 };
1315 assert!(matches!(
1316 strategy.strategy_type,
1317 ConflictResolutionType::ArrayPadding
1318 ));
1319 assert!(strategy.expected_speedup > 1.0);
1320 }
1321
1322 #[test]
1323 fn test_arithmetic_intensity_profile() {
1324 let profile = ArithmeticIntensityProfile {
1325 kernel_name: "gemm".to_string(),
1326 operations_per_byte: 50.0,
1327 compute_intensity: ComputeIntensityCategory::ComputeBound,
1328 memory_bound_ratio: 0.2,
1329 compute_bound_ratio: 0.8,
1330 roofline_position: RooflinePosition {
1331 current_performance: 500.0,
1332 theoretical_peak: 1000.0,
1333 memory_bandwidth_limit: 900.0,
1334 efficiency_percentage: 50.0,
1335 },
1336 optimization_direction: OptimizationDirection::IncreaseComputeIntensity,
1337 };
1338 assert!(matches!(
1339 profile.compute_intensity,
1340 ComputeIntensityCategory::ComputeBound
1341 ));
1342 assert!((profile.roofline_position.efficiency_percentage - 50.0).abs() < f64::EPSILON);
1343 }
1344
1345 #[test]
1346 fn test_roofline_model() {
1347 let model = RooflineModel {
1348 device_id: 0,
1349 peak_compute_performance: 10000.0,
1350 peak_memory_bandwidth: 900.0,
1351 cache_hierarchy: CacheHierarchy {
1352 l1_cache_bandwidth: 12000.0,
1353 l2_cache_bandwidth: 3000.0,
1354 shared_memory_bandwidth: 6000.0,
1355 texture_cache_bandwidth: 2000.0,
1356 constant_cache_bandwidth: 8000.0,
1357 },
1358 compute_capabilities: ComputeCapabilities {
1359 fp32_performance: 10000.0,
1360 fp16_performance: 20000.0,
1361 int32_performance: 5000.0,
1362 tensor_performance: 100000.0,
1363 special_function_performance: 2500.0,
1364 },
1365 };
1366 assert!(model.peak_compute_performance > 0.0);
1367 assert!(
1368 model.cache_hierarchy.l1_cache_bandwidth > model.cache_hierarchy.l2_cache_bandwidth
1369 );
1370 }
1371
1372 #[test]
1373 fn test_resource_profile() {
1374 let profile = ResourceProfile {
1375 kernel_name: "attention_kernel".to_string(),
1376 register_pressure: ResourcePressure::High,
1377 shared_memory_pressure: ResourcePressure::Medium,
1378 occupancy_limiting_factor: OccupancyLimitingFactor::RegisterCount,
1379 resource_utilization_efficiency: 0.65,
1380 };
1381 assert!(matches!(profile.register_pressure, ResourcePressure::High));
1382 assert!(matches!(
1383 profile.occupancy_limiting_factor,
1384 OccupancyLimitingFactor::RegisterCount
1385 ));
1386 }
1387
1388 #[test]
1389 fn test_balancing_strategy() {
1390 let strategy = BalancingStrategy {
1391 strategy_type: BalancingStrategyType::RegisterOptimization,
1392 description: "Reduce register usage per thread".to_string(),
1393 expected_occupancy_improvement: 0.15,
1394 performance_impact: 0.10,
1395 };
1396 assert!(strategy.expected_occupancy_improvement > 0.0);
1397 }
1398
1399 #[test]
1400 fn test_fusion_opportunity() {
1401 let opportunity = FusionOpportunity {
1402 opportunity_id: Uuid::new_v4(),
1403 kernel_group: vec!["bias_add".to_string(), "relu".to_string()],
1404 fusion_type: FusionType::ElementwiseFusion,
1405 data_dependencies: vec![DataDependency {
1406 source_kernel: "bias_add".to_string(),
1407 target_kernel: "relu".to_string(),
1408 dependency_type: DependencyType::ReadAfterWrite,
1409 data_size: 4096,
1410 access_pattern: "sequential".to_string(),
1411 }],
1412 expected_speedup: 1.5,
1413 memory_savings: 4096,
1414 implementation_complexity: ImplementationDifficulty::Easy,
1415 fusion_feasibility: FusionFeasibility {
1416 resource_constraints_satisfied: true,
1417 register_usage_feasible: true,
1418 shared_memory_feasible: true,
1419 synchronization_complexity: SynchronizationComplexity::None,
1420 fusion_confidence: 0.95,
1421 },
1422 };
1423 assert_eq!(opportunity.kernel_group.len(), 2);
1424 assert!(matches!(
1425 opportunity.fusion_type,
1426 FusionType::ElementwiseFusion
1427 ));
1428 assert!(opportunity.fusion_feasibility.resource_constraints_satisfied);
1429 }
1430
1431 #[test]
1432 fn test_fusion_cost_benefit_analyzer_new_empty() {
1433 let analyzer = FusionCostBenefitAnalyzer::new_empty();
1434 assert!(analyzer.cost_models.is_empty());
1435 }
1436
1437 #[test]
1442 fn test_stride_impact_variants() {
1443 let impacts = [
1444 StrideImpact::Optimal,
1445 StrideImpact::Good,
1446 StrideImpact::Moderate,
1447 StrideImpact::Poor,
1448 StrideImpact::Critical,
1449 ];
1450 assert_eq!(impacts.len(), 5);
1451 }
1452
1453 #[test]
1454 fn test_access_pattern_type_variants() {
1455 let patterns = [
1456 AccessPatternType::Sequential,
1457 AccessPatternType::Strided,
1458 AccessPatternType::Random,
1459 AccessPatternType::Blocked,
1460 AccessPatternType::Sparse,
1461 AccessPatternType::Irregular,
1462 ];
1463 assert_eq!(patterns.len(), 6);
1464 }
1465
1466 #[test]
1467 fn test_stride_optimization() {
1468 let opt = StrideOptimization {
1469 optimization_type: StrideOptimizationType::TilingStrategy,
1470 description: "Apply loop tiling for better cache utilization".to_string(),
1471 expected_improvement: 0.25,
1472 implementation_complexity: ImplementationDifficulty::Moderate,
1473 };
1474 assert!(matches!(
1475 opt.optimization_type,
1476 StrideOptimizationType::TilingStrategy
1477 ));
1478 }
1479
1480 #[test]
1481 fn test_occupancy_targets() {
1482 let targets = OccupancyTargets {
1483 minimum_occupancy: 0.25,
1484 target_occupancy: 0.75,
1485 theoretical_occupancy: 1.0,
1486 };
1487 assert!(targets.minimum_occupancy < targets.target_occupancy);
1488 assert!(targets.target_occupancy <= targets.theoretical_occupancy);
1489 }
1490
1491 #[test]
1492 fn test_memory_constraints() {
1493 let constraints = MemoryConstraints {
1494 max_shared_memory_per_block: 49152,
1495 bank_conflict_aware: true,
1496 coalescing_optimization: true,
1497 };
1498 assert!(constraints.bank_conflict_aware);
1499 assert_eq!(constraints.max_shared_memory_per_block, 49152);
1500 }
1501
1502 #[test]
1503 fn test_compute_capabilities() {
1504 let caps = ComputeCapabilities {
1505 fp32_performance: 10000.0,
1506 fp16_performance: 20000.0,
1507 int32_performance: 5000.0,
1508 tensor_performance: 100000.0,
1509 special_function_performance: 2500.0,
1510 };
1511 assert!(caps.fp16_performance > caps.fp32_performance);
1512 assert!(caps.tensor_performance > caps.fp16_performance);
1513 }
1514
1515 #[test]
1516 fn test_fusion_cost_benefit_analyzer_new() {
1517 let result = FusionCostBenefitAnalyzer::new();
1518 assert!(result.is_ok());
1519 }
1520
1521 #[test]
1522 fn test_fusion_type_variants() {
1523 let types = [
1524 FusionType::ElementwiseFusion,
1525 FusionType::ProducerConsumerFusion,
1526 FusionType::LoopFusion,
1527 FusionType::ReductionFusion,
1528 FusionType::ConvolutionFusion,
1529 FusionType::AttentionFusion,
1530 ];
1531 assert_eq!(types.len(), 6);
1532 }
1533
1534 #[test]
1535 fn test_dependency_type_variants() {
1536 let types = [
1537 DependencyType::ReadAfterWrite,
1538 DependencyType::WriteAfterRead,
1539 DependencyType::WriteAfterWrite,
1540 DependencyType::Reduction,
1541 DependencyType::Broadcast,
1542 ];
1543 assert_eq!(types.len(), 5);
1544 }
1545
1546 #[test]
1547 fn test_data_dependency_creation() {
1548 let dep = DataDependency {
1549 source_kernel: "conv1".to_string(),
1550 target_kernel: "relu1".to_string(),
1551 dependency_type: DependencyType::ReadAfterWrite,
1552 data_size: 8192,
1553 access_pattern: "contiguous".to_string(),
1554 };
1555 assert_eq!(dep.source_kernel, "conv1");
1556 assert_eq!(dep.data_size, 8192);
1557 }
1558
1559 #[test]
1560 fn test_fusion_feasibility_creation() {
1561 let feasibility = FusionFeasibility {
1562 resource_constraints_satisfied: true,
1563 register_usage_feasible: true,
1564 shared_memory_feasible: false,
1565 synchronization_complexity: SynchronizationComplexity::None,
1566 fusion_confidence: 0.7,
1567 };
1568 assert!(feasibility.resource_constraints_satisfied);
1569 assert!(!feasibility.shared_memory_feasible);
1570 }
1571
1572 #[test]
1573 fn test_optimization_direction_variants() {
1574 let dirs = [
1575 OptimizationDirection::IncreaseComputeIntensity,
1576 OptimizationDirection::ImproveMemoryEfficiency,
1577 OptimizationDirection::BalanceComputeMemory,
1578 OptimizationDirection::OptimizeForLatency,
1579 ];
1580 assert_eq!(dirs.len(), 4);
1581 }
1582
1583 #[test]
1584 fn test_block_size_constraint_variants() {
1585 let constraints = [
1586 BlockSizeConstraint::MultipleOf(32),
1587 BlockSizeConstraint::PowerOfTwo,
1588 BlockSizeConstraint::MaxThreadsPerBlock(1024),
1589 BlockSizeConstraint::SharedMemoryLimit(49152),
1590 BlockSizeConstraint::RegisterLimit(255),
1591 ];
1592 assert_eq!(constraints.len(), 5);
1593 }
1594
1595 #[test]
1596 fn test_register_constraints_creation() {
1597 let constraints = RegisterConstraints {
1598 max_registers_per_thread: 255,
1599 spill_threshold: 64,
1600 occupancy_impact_threshold: 0.5,
1601 };
1602 assert_eq!(constraints.max_registers_per_thread, 255);
1603 assert!((constraints.occupancy_impact_threshold - 0.5).abs() < f64::EPSILON);
1604 }
1605
1606 fn low_occupancy_matmul_profile() -> KernelProfileData {
1607 KernelProfileData {
1608 execution_time: Duration::from_micros(250),
1609 grid_size: (4096, 1, 1),
1610 block_size: (256, 1, 1),
1611 shared_memory_bytes: 0,
1612 registers_per_thread: 128, occupancy: 0.33,
1614 compute_utilization: 0.65,
1615 memory_bandwidth_utilization: 0.45,
1616 warp_efficiency: 0.92,
1617 memory_efficiency: 0.88,
1618 }
1619 }
1620
1621 #[test]
1622 fn test_analyze_kernel_returns_real_optimizations() {
1623 let mut analyzer =
1624 KernelOptimizationAnalyzer::new().expect("analyzer construction should succeed");
1625 let opts = analyzer
1626 .analyze_kernel("matmul_tile", low_occupancy_matmul_profile())
1627 .expect("analysis should succeed");
1628 assert!(
1629 !opts.is_empty(),
1630 "low-occupancy register-limited kernel must yield optimizations"
1631 );
1632 for window in opts.windows(2) {
1634 assert!(
1635 window[0].expected_improvement.performance_gain_percentage
1636 >= window[1].expected_improvement.performance_gain_percentage
1637 );
1638 }
1639 for opt in &opts {
1640 assert!((0.0..=1.0).contains(&opt.confidence));
1641 assert!((0.0..=95.0).contains(&opt.expected_improvement.performance_gain_percentage));
1642 }
1643 }
1644
1645 #[test]
1646 fn test_analyze_memory_bound_kernel() {
1647 let mut analyzer =
1648 KernelOptimizationAnalyzer::new().expect("analyzer construction should succeed");
1649 let profile = KernelProfileData {
1650 execution_time: Duration::from_micros(80),
1651 grid_size: (8192, 1, 1),
1652 block_size: (256, 1, 1),
1653 shared_memory_bytes: 0,
1654 registers_per_thread: 32,
1655 occupancy: 0.55,
1656 compute_utilization: 0.15,
1657 memory_bandwidth_utilization: 0.9,
1658 warp_efficiency: 0.6,
1659 memory_efficiency: 0.4,
1660 };
1661 let opts = analyzer.analyze_kernel("gemv", profile).expect("analysis should succeed");
1662 assert!(
1663 !opts.is_empty(),
1664 "memory-bound kernel must yield optimizations"
1665 );
1666 assert!(opts.iter().any(|o| matches!(
1667 o.optimization_type,
1668 crate::advanced_gpu_profiler::OptimizationType::MemoryCoalescing
1669 | crate::advanced_gpu_profiler::OptimizationType::ComputeIntensityBalance
1670 )));
1671 }
1672
1673 #[test]
1674 fn test_analyze_fusion_opportunities_public_api() {
1675 let mut analyzer =
1676 KernelOptimizationAnalyzer::new().expect("analyzer construction should succeed");
1677 let sequence = vec![
1678 "matmul_qk".to_string(),
1679 "softmax".to_string(),
1680 "matmul_v".to_string(),
1681 "bias_add".to_string(),
1682 "gelu".to_string(),
1683 ];
1684 let opportunities = analyzer
1685 .analyze_fusion_opportunities(&sequence)
1686 .expect("fusion analysis should succeed");
1687 assert!(
1688 !opportunities.is_empty(),
1689 "an attention-style kernel chain must expose fusion opportunities"
1690 );
1691 for opp in &opportunities {
1692 assert!(opp.expected_speedup > 1.0);
1693 assert_eq!(opp.kernel_group.len(), 2);
1694 assert!(opp.memory_savings > 0);
1695 assert!((0.0..=1.0).contains(&opp.fusion_feasibility.fusion_confidence));
1696 }
1697 let report = analyzer.fusion_analyzer.get_opportunities_for_kernel("softmax");
1699 assert!(report.is_ok());
1700 assert!(!report.expect("indexed opportunities").is_empty());
1701 }
1702}