mirror of https://github.com/jetkvm/kvm.git
330 lines
12 KiB
Go
330 lines
12 KiB
Go
package audio
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
// AdaptiveOptimizer automatically adjusts audio parameters based on latency metrics
|
|
type AdaptiveOptimizer struct {
|
|
// Atomic fields MUST be first for ARM32 alignment (int64 fields need 8-byte alignment)
|
|
optimizationCount int64 // Number of optimizations performed (atomic)
|
|
lastOptimization int64 // Timestamp of last optimization (atomic)
|
|
optimizationLevel int64 // Current optimization level (0-10) (atomic)
|
|
stabilityScore int64 // Current stability score (0-100) (atomic)
|
|
optimizationInterval int64 // Current optimization interval in nanoseconds (atomic)
|
|
|
|
latencyMonitor *LatencyMonitor
|
|
bufferManager *AdaptiveBufferManager
|
|
logger zerolog.Logger
|
|
|
|
// Control channels
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
wg sync.WaitGroup
|
|
|
|
// Configuration
|
|
config OptimizerConfig
|
|
|
|
// Stability tracking
|
|
stabilityHistory []StabilityMetric
|
|
stabilityMutex sync.RWMutex
|
|
}
|
|
|
|
// StabilityMetric tracks system stability over time
|
|
type StabilityMetric struct {
|
|
Timestamp time.Time
|
|
LatencyStdev float64
|
|
CPUVariance float64
|
|
MemoryStable bool
|
|
ErrorRate float64
|
|
StabilityScore int
|
|
}
|
|
|
|
// OptimizerConfig holds configuration for the adaptive optimizer
|
|
type OptimizerConfig struct {
|
|
MaxOptimizationLevel int // Maximum optimization level (0-10)
|
|
CooldownPeriod time.Duration // Minimum time between optimizations
|
|
Aggressiveness float64 // How aggressively to optimize (0.0-1.0)
|
|
RollbackThreshold time.Duration // Latency threshold to rollback optimizations
|
|
StabilityPeriod time.Duration // Time to wait for stability after optimization
|
|
|
|
// Adaptive interval configuration
|
|
MinOptimizationInterval time.Duration // Minimum optimization interval (high stability)
|
|
MaxOptimizationInterval time.Duration // Maximum optimization interval (low stability)
|
|
StabilityThreshold int // Stability score threshold for interval adjustment
|
|
StabilityHistorySize int // Number of stability metrics to track
|
|
}
|
|
|
|
// DefaultOptimizerConfig returns a sensible default configuration
|
|
func DefaultOptimizerConfig() OptimizerConfig {
|
|
return OptimizerConfig{
|
|
MaxOptimizationLevel: 8,
|
|
CooldownPeriod: Config.CooldownPeriod,
|
|
Aggressiveness: Config.OptimizerAggressiveness,
|
|
RollbackThreshold: Config.RollbackThreshold,
|
|
StabilityPeriod: Config.AdaptiveOptimizerStability,
|
|
|
|
// Adaptive interval defaults
|
|
MinOptimizationInterval: 100 * time.Millisecond, // High stability: check every 100ms
|
|
MaxOptimizationInterval: 2 * time.Second, // Low stability: check every 2s
|
|
StabilityThreshold: 70, // Stability score threshold
|
|
StabilityHistorySize: 20, // Track last 20 stability metrics
|
|
}
|
|
}
|
|
|
|
// NewAdaptiveOptimizer creates a new adaptive optimizer
|
|
func NewAdaptiveOptimizer(latencyMonitor *LatencyMonitor, bufferManager *AdaptiveBufferManager, config OptimizerConfig, logger zerolog.Logger) *AdaptiveOptimizer {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
optimizer := &AdaptiveOptimizer{
|
|
latencyMonitor: latencyMonitor,
|
|
bufferManager: bufferManager,
|
|
config: config,
|
|
logger: logger.With().Str("component", "adaptive-optimizer").Logger(),
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
stabilityHistory: make([]StabilityMetric, 0, config.StabilityHistorySize),
|
|
}
|
|
|
|
// Initialize stability score and optimization interval
|
|
atomic.StoreInt64(&optimizer.stabilityScore, 50) // Start with medium stability
|
|
atomic.StoreInt64(&optimizer.optimizationInterval, int64(config.MaxOptimizationInterval))
|
|
|
|
// Register as latency monitor callback
|
|
latencyMonitor.AddOptimizationCallback(optimizer.handleLatencyOptimization)
|
|
|
|
return optimizer
|
|
}
|
|
|
|
// Start begins the adaptive optimization process
|
|
func (ao *AdaptiveOptimizer) Start() {
|
|
ao.wg.Add(1)
|
|
go ao.optimizationLoop()
|
|
ao.logger.Debug().Msg("adaptive optimizer started")
|
|
}
|
|
|
|
// Stop stops the adaptive optimizer
|
|
func (ao *AdaptiveOptimizer) Stop() {
|
|
ao.cancel()
|
|
ao.wg.Wait()
|
|
ao.logger.Debug().Msg("adaptive optimizer stopped")
|
|
}
|
|
|
|
// initializeStrategies sets up the available optimization strategies
|
|
|
|
// handleLatencyOptimization is called when latency optimization is needed
|
|
func (ao *AdaptiveOptimizer) handleLatencyOptimization(metrics LatencyMetrics) error {
|
|
currentLevel := atomic.LoadInt64(&ao.optimizationLevel)
|
|
lastOpt := atomic.LoadInt64(&ao.lastOptimization)
|
|
|
|
// Check cooldown period
|
|
if time.Since(time.Unix(0, lastOpt)) < ao.config.CooldownPeriod {
|
|
return nil
|
|
}
|
|
|
|
// Determine if we need to increase or decrease optimization level
|
|
targetLevel := ao.calculateTargetOptimizationLevel(metrics)
|
|
|
|
if targetLevel > currentLevel {
|
|
return ao.increaseOptimization(int(targetLevel))
|
|
} else if targetLevel < currentLevel {
|
|
return ao.decreaseOptimization(int(targetLevel))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// calculateTargetOptimizationLevel determines the appropriate optimization level
|
|
func (ao *AdaptiveOptimizer) calculateTargetOptimizationLevel(metrics LatencyMetrics) int64 {
|
|
// Base calculation on current latency vs target
|
|
latencyRatio := float64(metrics.Current) / float64(Config.AdaptiveOptimizerLatencyTarget) // 50ms target
|
|
|
|
// Adjust based on trend
|
|
switch metrics.Trend {
|
|
case LatencyTrendIncreasing:
|
|
latencyRatio *= 1.2 // Be more aggressive
|
|
case LatencyTrendDecreasing:
|
|
latencyRatio *= 0.8 // Be less aggressive
|
|
case LatencyTrendVolatile:
|
|
latencyRatio *= 1.1 // Slightly more aggressive
|
|
}
|
|
|
|
// Apply aggressiveness factor
|
|
latencyRatio *= ao.config.Aggressiveness
|
|
|
|
// Convert to optimization level
|
|
targetLevel := int64(latencyRatio * Config.LatencyScalingFactor) // Scale to 0-10 range
|
|
if targetLevel > int64(ao.config.MaxOptimizationLevel) {
|
|
targetLevel = int64(ao.config.MaxOptimizationLevel)
|
|
}
|
|
if targetLevel < 0 {
|
|
targetLevel = 0
|
|
}
|
|
|
|
return targetLevel
|
|
}
|
|
|
|
// increaseOptimization applies optimization strategies up to the target level
|
|
func (ao *AdaptiveOptimizer) increaseOptimization(targetLevel int) error {
|
|
atomic.StoreInt64(&ao.optimizationLevel, int64(targetLevel))
|
|
atomic.StoreInt64(&ao.lastOptimization, time.Now().UnixNano())
|
|
atomic.AddInt64(&ao.optimizationCount, 1)
|
|
|
|
return nil
|
|
}
|
|
|
|
// decreaseOptimization rolls back optimization strategies to the target level
|
|
func (ao *AdaptiveOptimizer) decreaseOptimization(targetLevel int) error {
|
|
atomic.StoreInt64(&ao.optimizationLevel, int64(targetLevel))
|
|
atomic.StoreInt64(&ao.lastOptimization, time.Now().UnixNano())
|
|
|
|
return nil
|
|
}
|
|
|
|
// optimizationLoop runs the main optimization monitoring loop
|
|
func (ao *AdaptiveOptimizer) optimizationLoop() {
|
|
defer ao.wg.Done()
|
|
|
|
// Start with initial interval
|
|
currentInterval := time.Duration(atomic.LoadInt64(&ao.optimizationInterval))
|
|
ticker := time.NewTicker(currentInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ao.ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
// Update stability metrics and check for optimization needs
|
|
ao.updateStabilityMetrics()
|
|
ao.checkStability()
|
|
|
|
// Adjust optimization interval based on current stability
|
|
newInterval := ao.calculateOptimizationInterval()
|
|
if newInterval != currentInterval {
|
|
currentInterval = newInterval
|
|
ticker.Reset(currentInterval)
|
|
ao.logger.Debug().Dur("new_interval", currentInterval).Int64("stability_score", atomic.LoadInt64(&ao.stabilityScore)).Msg("adjusted optimization interval")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// checkStability monitors system stability and rolls back if needed
|
|
func (ao *AdaptiveOptimizer) checkStability() {
|
|
metrics := ao.latencyMonitor.GetMetrics()
|
|
|
|
// Check if we need to rollback due to excessive latency
|
|
if metrics.Current > ao.config.RollbackThreshold {
|
|
currentLevel := int(atomic.LoadInt64(&ao.optimizationLevel))
|
|
if currentLevel > 0 {
|
|
ao.logger.Warn().Dur("current_latency", metrics.Current).Dur("threshold", ao.config.RollbackThreshold).Msg("rolling back optimizations due to excessive latency")
|
|
if err := ao.decreaseOptimization(currentLevel - 1); err != nil {
|
|
ao.logger.Error().Err(err).Msg("failed to decrease optimization level")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// updateStabilityMetrics calculates and stores current system stability metrics
|
|
func (ao *AdaptiveOptimizer) updateStabilityMetrics() {
|
|
metrics := ao.latencyMonitor.GetMetrics()
|
|
|
|
// Calculate stability score based on multiple factors
|
|
stabilityScore := ao.calculateStabilityScore(metrics)
|
|
atomic.StoreInt64(&ao.stabilityScore, int64(stabilityScore))
|
|
|
|
// Store stability metric in history
|
|
stabilityMetric := StabilityMetric{
|
|
Timestamp: time.Now(),
|
|
LatencyStdev: float64(metrics.Jitter), // Use Jitter as variance indicator
|
|
CPUVariance: 0.0, // TODO: Get from system metrics
|
|
MemoryStable: true, // TODO: Get from system metrics
|
|
ErrorRate: 0.0, // TODO: Get from error tracking
|
|
StabilityScore: stabilityScore,
|
|
}
|
|
|
|
ao.stabilityMutex.Lock()
|
|
ao.stabilityHistory = append(ao.stabilityHistory, stabilityMetric)
|
|
if len(ao.stabilityHistory) > ao.config.StabilityHistorySize {
|
|
ao.stabilityHistory = ao.stabilityHistory[1:]
|
|
}
|
|
ao.stabilityMutex.Unlock()
|
|
}
|
|
|
|
// calculateStabilityScore computes a stability score (0-100) based on system metrics
|
|
func (ao *AdaptiveOptimizer) calculateStabilityScore(metrics LatencyMetrics) int {
|
|
// Base score starts at 100 (perfect stability)
|
|
score := 100.0
|
|
|
|
// Penalize high jitter (latency variance)
|
|
if metrics.Jitter > 0 && metrics.Average > 0 {
|
|
jitterRatio := float64(metrics.Jitter) / float64(metrics.Average)
|
|
variancePenalty := jitterRatio * 50 // Scale jitter impact
|
|
score -= variancePenalty
|
|
}
|
|
|
|
// Penalize latency trend volatility
|
|
switch metrics.Trend {
|
|
case LatencyTrendVolatile:
|
|
score -= 20
|
|
case LatencyTrendIncreasing:
|
|
score -= 10
|
|
case LatencyTrendDecreasing:
|
|
score += 5 // Slight bonus for improving latency
|
|
}
|
|
|
|
// Ensure score is within bounds
|
|
if score < 0 {
|
|
score = 0
|
|
}
|
|
if score > 100 {
|
|
score = 100
|
|
}
|
|
|
|
return int(score)
|
|
}
|
|
|
|
// calculateOptimizationInterval determines the optimization interval based on stability
|
|
func (ao *AdaptiveOptimizer) calculateOptimizationInterval() time.Duration {
|
|
stabilityScore := atomic.LoadInt64(&ao.stabilityScore)
|
|
|
|
// High stability = shorter intervals (more frequent optimization)
|
|
// Low stability = longer intervals (less frequent optimization)
|
|
if stabilityScore >= int64(ao.config.StabilityThreshold) {
|
|
// High stability: use minimum interval
|
|
interval := ao.config.MinOptimizationInterval
|
|
atomic.StoreInt64(&ao.optimizationInterval, int64(interval))
|
|
return interval
|
|
} else {
|
|
// Low stability: scale interval based on stability score
|
|
// Lower stability = longer intervals
|
|
stabilityRatio := float64(stabilityScore) / float64(ao.config.StabilityThreshold)
|
|
minInterval := float64(ao.config.MinOptimizationInterval)
|
|
maxInterval := float64(ao.config.MaxOptimizationInterval)
|
|
|
|
// Linear interpolation between min and max intervals
|
|
interval := time.Duration(minInterval + (maxInterval-minInterval)*(1.0-stabilityRatio))
|
|
atomic.StoreInt64(&ao.optimizationInterval, int64(interval))
|
|
return interval
|
|
}
|
|
}
|
|
|
|
// GetOptimizationStats returns current optimization statistics
|
|
func (ao *AdaptiveOptimizer) GetOptimizationStats() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"optimization_level": atomic.LoadInt64(&ao.optimizationLevel),
|
|
"optimization_count": atomic.LoadInt64(&ao.optimizationCount),
|
|
"last_optimization": time.Unix(0, atomic.LoadInt64(&ao.lastOptimization)),
|
|
"stability_score": atomic.LoadInt64(&ao.stabilityScore),
|
|
"optimization_interval": time.Duration(atomic.LoadInt64(&ao.optimizationInterval)),
|
|
}
|
|
}
|
|
|
|
// Strategy implementation methods (stubs for now)
|