mirror of
https://github.com/jetkvm/kvm.git
synced 2025-09-16 08:38:14 +00:00
This change replaces all instances of GetConfig() function calls with direct access to the Config variable throughout the audio package. The modification improves performance by eliminating function call overhead and simplifies the codebase by removing unnecessary indirection. The commit also includes minor optimizations in validation logic and connection handling, while maintaining all existing functionality. Error handling remains robust with appropriate fallbacks when config values are not available. Additional improvements include: - Enhanced connection health monitoring in UnifiedAudioClient - Optimized validation functions using cached config values - Reduced memory allocations in hot paths - Improved error recovery during quality changes
145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
package audio
|
|
|
|
import (
|
|
"runtime"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/jetkvm/kvm/internal/logging"
|
|
)
|
|
|
|
// GoroutineMonitor tracks goroutine count and provides cleanup mechanisms
|
|
type GoroutineMonitor struct {
|
|
baselineCount int
|
|
peakCount int
|
|
lastCount int
|
|
monitorInterval time.Duration
|
|
lastCheck time.Time
|
|
enabled int32
|
|
}
|
|
|
|
// Global goroutine monitor instance
|
|
var globalGoroutineMonitor *GoroutineMonitor
|
|
|
|
// NewGoroutineMonitor creates a new goroutine monitor
|
|
func NewGoroutineMonitor(monitorInterval time.Duration) *GoroutineMonitor {
|
|
if monitorInterval <= 0 {
|
|
monitorInterval = 30 * time.Second
|
|
}
|
|
|
|
// Get current goroutine count as baseline
|
|
baselineCount := runtime.NumGoroutine()
|
|
|
|
return &GoroutineMonitor{
|
|
baselineCount: baselineCount,
|
|
peakCount: baselineCount,
|
|
lastCount: baselineCount,
|
|
monitorInterval: monitorInterval,
|
|
lastCheck: time.Now(),
|
|
}
|
|
}
|
|
|
|
// Start begins goroutine monitoring
|
|
func (gm *GoroutineMonitor) Start() {
|
|
if !atomic.CompareAndSwapInt32(&gm.enabled, 0, 1) {
|
|
return // Already running
|
|
}
|
|
|
|
go gm.monitorLoop()
|
|
}
|
|
|
|
// Stop stops goroutine monitoring
|
|
func (gm *GoroutineMonitor) Stop() {
|
|
atomic.StoreInt32(&gm.enabled, 0)
|
|
}
|
|
|
|
// monitorLoop periodically checks goroutine count
|
|
func (gm *GoroutineMonitor) monitorLoop() {
|
|
logger := logging.GetDefaultLogger().With().Str("component", "goroutine-monitor").Logger()
|
|
logger.Info().Int("baseline", gm.baselineCount).Msg("goroutine monitor started")
|
|
|
|
for atomic.LoadInt32(&gm.enabled) == 1 {
|
|
time.Sleep(gm.monitorInterval)
|
|
gm.checkGoroutineCount()
|
|
}
|
|
|
|
logger.Info().Msg("goroutine monitor stopped")
|
|
}
|
|
|
|
// checkGoroutineCount checks current goroutine count and logs if it exceeds thresholds
|
|
func (gm *GoroutineMonitor) checkGoroutineCount() {
|
|
currentCount := runtime.NumGoroutine()
|
|
gm.lastCount = currentCount
|
|
|
|
// Update peak count if needed
|
|
if currentCount > gm.peakCount {
|
|
gm.peakCount = currentCount
|
|
}
|
|
|
|
// Calculate growth since baseline
|
|
growth := currentCount - gm.baselineCount
|
|
growthPercent := float64(growth) / float64(gm.baselineCount) * 100
|
|
|
|
// Log warning if growth exceeds thresholds
|
|
logger := logging.GetDefaultLogger().With().Str("component", "goroutine-monitor").Logger()
|
|
|
|
// Different log levels based on growth severity
|
|
if growthPercent > 30 {
|
|
// Severe growth - trigger cleanup
|
|
logger.Warn().Int("current", currentCount).Int("baseline", gm.baselineCount).
|
|
Int("growth", growth).Float64("growth_percent", growthPercent).
|
|
Msg("excessive goroutine growth detected - triggering cleanup")
|
|
|
|
// Force garbage collection to clean up unused resources
|
|
runtime.GC()
|
|
|
|
// Force cleanup of goroutine buffer cache
|
|
cleanupGoroutineCache()
|
|
} else if growthPercent > 20 {
|
|
// Moderate growth - just log warning
|
|
logger.Warn().Int("current", currentCount).Int("baseline", gm.baselineCount).
|
|
Int("growth", growth).Float64("growth_percent", growthPercent).
|
|
Msg("significant goroutine growth detected")
|
|
} else if growthPercent > 10 {
|
|
// Minor growth - log info
|
|
logger.Info().Int("current", currentCount).Int("baseline", gm.baselineCount).
|
|
Int("growth", growth).Float64("growth_percent", growthPercent).
|
|
Msg("goroutine growth detected")
|
|
}
|
|
|
|
// Update last check time
|
|
gm.lastCheck = time.Now()
|
|
}
|
|
|
|
// GetGoroutineStats returns current goroutine statistics
|
|
func (gm *GoroutineMonitor) GetGoroutineStats() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"current_count": gm.lastCount,
|
|
"baseline_count": gm.baselineCount,
|
|
"peak_count": gm.peakCount,
|
|
"growth": gm.lastCount - gm.baselineCount,
|
|
"growth_percent": float64(gm.lastCount-gm.baselineCount) / float64(gm.baselineCount) * 100,
|
|
"last_check": gm.lastCheck,
|
|
}
|
|
}
|
|
|
|
// GetGoroutineMonitor returns the global goroutine monitor instance
|
|
func GetGoroutineMonitor() *GoroutineMonitor {
|
|
if globalGoroutineMonitor == nil {
|
|
globalGoroutineMonitor = NewGoroutineMonitor(Config.GoroutineMonitorInterval)
|
|
}
|
|
return globalGoroutineMonitor
|
|
}
|
|
|
|
// StartGoroutineMonitoring starts the global goroutine monitor
|
|
func StartGoroutineMonitoring() {
|
|
// Goroutine monitoring disabled
|
|
}
|
|
|
|
// StopGoroutineMonitoring stops the global goroutine monitor
|
|
func StopGoroutineMonitoring() {
|
|
if globalGoroutineMonitor != nil {
|
|
globalGoroutineMonitor.Stop()
|
|
}
|
|
}
|