Skip to main content

trustformers_debug/
kernel_optimizer.rs

1//! Kernel optimization analyzer and recommendation engine
2//!
3//! This module provides comprehensive analysis of GPU kernel performance,
4//! identifies optimization opportunities, and suggests specific improvements.
5// reason: debug/profiling scaffolding — structs are constructed and their fields/methods
6// are retained for the data model, serialization completeness, and future consumers that
7// do not yet read every member. Consolidated from many item-level #[allow(dead_code)].
8#![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
23/// CPU-side analytical computations backing the analyzers in this module
24/// (occupancy estimation, roofline classification, fusion detection).
25mod analysis;
26
27/// Performance-regression detection (baseline establishment + Welch's
28/// t-test comparison) backing [`PerformanceRegressionDetector`]. Types are
29/// re-exported here so existing `crate::kernel_optimizer::{Foo, ...}`
30/// paths keep working after the split.
31mod regression;
32pub use regression::*;
33
34/// Comprehensive kernel optimization analyzer
35#[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/// Launch configuration optimization engine
47#[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/// Memory access pattern analysis engine
97#[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,  // Stride = 1 element
126    Good,     // Small stride, good cache utilization
127    Moderate, // Medium stride, some cache misses
128    Poor,     // Large stride, many cache misses
129    Critical, // Very large stride, severe performance impact
130}
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/// Bank conflict analysis for shared memory
160#[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>, // Utilization per bank
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub enum ConflictSeverity {
177    None,
178    Low,    // 2-way conflicts
179    Medium, // 4-way conflicts
180    High,   // 8-way conflicts
181    Severe, // 16+ way conflicts
182}
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/// Compute utilization analysis engine
210#[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>, // Per device
222}
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,  // < 1 op/byte
238    Balanced,     // 1-10 ops/byte
239    ComputeBound, // > 10 ops/byte
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct RooflinePosition {
244    pub current_performance: f64,    // GFLOPS
245    pub theoretical_peak: f64,       // GFLOPS
246    pub memory_bandwidth_limit: f64, // GB/s
247    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, // GFLOPS
262    pub peak_memory_bandwidth: f64,    // GB/s
263    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/// Resource balancing engine
286#[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/// Kernel fusion analysis engine
336#[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,      // Simple element-wise operations
359    ProducerConsumerFusion, // Producer directly feeds consumer
360    LoopFusion,             // Fuse similar loop structures
361    ReductionFusion,        // Combine multiple reductions
362    ConvolutionFusion,      // Fuse convolution with activation/bias
363    AttentionFusion,        // Fuse attention mechanism components
364}
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, // Strength of dependency
431}
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/// Fusion cost-benefit analyzer
467#[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
509// Implementation of the main analyzer
510
511impl 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    /// Create an analyzer with empty state, for the fallback path when
525    /// [`Self::new`] fails.
526    ///
527    /// Every sub-analyzer starts from the same empty maps [`Self::new`] builds;
528    /// the only difference is that this constructor cannot fail. It is named
529    /// `new_empty` rather than the previous `new_stub` because nothing here is
530    /// stubbed out: analysis on this instance is fully functional, it simply
531    /// starts with no recorded history.
532    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    /// Names of every kernel this analyzer holds a real execution profile for.
545    pub fn analyzed_kernel_names(&self) -> Vec<&str> {
546        self.kernel_profiles.keys().map(String::as_str).collect()
547    }
548
549    /// Optimization suggestions recorded so far, keyed by kernel name.
550    pub fn optimization_suggestions(&self) -> &HashMap<String, Vec<KernelOptimization>> {
551        &self.optimization_suggestions
552    }
553
554    /// Analyze a kernel execution and generate optimization suggestions
555    pub fn analyze_kernel(
556        &mut self,
557        kernel_name: &str,
558        profile_data: KernelProfileData,
559    ) -> Result<Vec<KernelOptimization>> {
560        // Update kernel profile
561        self.update_kernel_profile(kernel_name, profile_data.clone())?;
562
563        // Analyze different aspects
564        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        // Combine all optimizations
572        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        // Rank optimizations by expected impact
578        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        // Store suggestions
586        self.optimization_suggestions
587            .insert(kernel_name.to_string(), all_optimizations.clone());
588
589        // Check for performance regressions
590        self.performance_regression_detector
591            .check_regression(kernel_name, &profile_data)?;
592
593        Ok(all_optimizations)
594    }
595
596    /// Analyze kernel fusion opportunities
597    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    /// Get comprehensive optimization report for a kernel
605    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        // Update profile with new data
661        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        // Higher score = higher priority
727        // Balance performance gain against implementation difficulty
728        performance_gain / (difficulty * difficulty)
729    }
730}
731
732// Helper structures and implementations
733
734#[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    /// Real regression status computed from this kernel's execution-time
758    /// history, or `None` when there is not yet enough real data to
759    /// establish and compare against a baseline -- see
760    /// [`PerformanceRegressionDetector::get_status`]. Never a fabricated
761    /// "stable" placeholder.
762    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), // grid + block
778    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
857// Sub-analyzer constructors. `new()` is the fallible form used on the normal
858// path; `new_empty()` is the infallible form used by
859// `KernelOptimizationAnalyzer::new_empty`. Both start from empty state.
860
861impl 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        // Real CPU-side launch-configuration analysis: estimate occupancy from
886        // the launch descriptor + documented sm_86 device limits and emit
887        // block-size / register / shared-memory recommendations.
888        Ok(analysis::analyze_launch_config(profile_data))
889    }
890
891    fn get_analysis(&self, kernel_name: &str) -> Result<LaunchConfigAnalysisResult> {
892        // Simplified implementation
893        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        // Real CPU-side memory-access analysis: classify coalescing / warp
936        // divergence from the measured efficiency metrics and emit fixes.
937        Ok(analysis::analyze_memory_access(profile_data))
938    }
939
940    fn get_analysis(&self, kernel_name: &str) -> Result<MemoryAnalysisResult> {
941        // Simplified implementation
942        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        // Real CPU-side compute-utilization analysis: place the kernel on the
1003        // roofline (arithmetic intensity vs ridge point) and classify the
1004        // bottleneck (memory-bound / compute-bound / latency-bound).
1005        Ok(analysis::analyze_compute_utilization(profile_data))
1006    }
1007
1008    fn get_analysis(&self, kernel_name: &str) -> Result<ComputeAnalysisResult> {
1009        // Simplified implementation
1010        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        // Real CPU-side fusion detection: examine each adjacent producer→consumer
1084        // pair, classify the kernels, and model the memory-traffic speedup.
1085        let opportunities = analysis::find_fusion_opportunities(kernel_sequence);
1086
1087        // Index opportunities by participating kernel so per-kernel reports can
1088        // surface them later.
1089        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
1106// Constructors for the remaining sub-analyzers; same `new`/`new_empty` pairing
1107// as above.
1108
1109impl 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/// Configuration for kernel optimization analysis
1184#[derive(Debug, Clone, Serialize, Deserialize)]
1185pub struct KernelOptimizationConfig {
1186    /// Enable launch configuration optimization
1187    pub enable_launch_config_optimization: bool,
1188    /// Enable memory access optimization
1189    pub enable_memory_access_optimization: bool,
1190    /// Enable kernel fusion analysis
1191    pub enable_kernel_fusion: bool,
1192    /// Enable performance regression detection
1193    pub enable_regression_detection: bool,
1194    /// Maximum number of optimization suggestions per kernel
1195    pub max_optimization_suggestions: usize,
1196    /// Minimum performance improvement threshold (percentage)
1197    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    // StatisticalAnalyzer now lives in (and is private to) the `regression`
1438    // submodule -- see kernel_optimizer/regression.rs's own test module for
1439    // its `new`/`new_empty` coverage.
1440
1441    #[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, // register-limited → low occupancy
1613            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        // Results are ranked by performance gain (descending) and within range.
1633        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        // Opportunities are indexed per participating kernel.
1698        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}