feat(webkit): add performance-optimized memory configuration system
- commit
- 390c2f0a167fe9da9d8bfc275f6746fecefc631d
- author
- bamen · · 2025-09-11 18:47 UTC
- committer
- bamen · · 2025-09-11 16:25 UTC
- parent
- 0b7f97e
- signature
- unsigned
2 files · +74 -0
M internal/config/config.go +62 -0
| @@ -33,6 +33,7 @@ type Config struct { | |||
| 33 | 33 | Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"` | |
| 34 | 34 | VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"` | |
| 35 | 35 | CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"` | |
| 36 | + | WebkitMemory WebkitMemoryConfig `mapstructure:"webkit_memory" yaml:"webkit_memory"` | |
| 36 | 37 | // RenderingMode controls GPU/CPU rendering selection for WebKit | |
| 37 | 38 | RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"` | |
| 38 | 39 | } | |
| @@ -152,6 +153,35 @@ type CodecConfig struct { | |||
| 152 | 153 | DisableTwitchCodecControl bool `mapstructure:"disable_twitch_codec_control" yaml:"disable_twitch_codec_control"` | |
| 153 | 154 | } | |
| 154 | 155 | ||
| 156 | + | // WebkitMemoryConfig holds WebKit memory optimization settings | |
| 157 | + | type WebkitMemoryConfig struct { | |
| 158 | + | // Cache model (document_viewer | web_browser | primary_web_browser) | |
| 159 | + | CacheModel string `mapstructure:"cache_model" yaml:"cache_model"` | |
| 160 | + | ||
| 161 | + | // Enable page cache for back/forward navigation | |
| 162 | + | EnablePageCache bool `mapstructure:"enable_page_cache" yaml:"enable_page_cache"` | |
| 163 | + | ||
| 164 | + | // Memory limit in MB (0 = system default) | |
| 165 | + | MemoryLimitMB int `mapstructure:"memory_limit_mb" yaml:"memory_limit_mb"` | |
| 166 | + | ||
| 167 | + | // Memory pressure thresholds (0.0-1.0) | |
| 168 | + | ConservativeThreshold float64 `mapstructure:"conservative_threshold" yaml:"conservative_threshold"` | |
| 169 | + | StrictThreshold float64 `mapstructure:"strict_threshold" yaml:"strict_threshold"` | |
| 170 | + | KillThreshold float64 `mapstructure:"kill_threshold" yaml:"kill_threshold"` | |
| 171 | + | ||
| 172 | + | // Memory monitoring interval in seconds | |
| 173 | + | PollIntervalSeconds float64 `mapstructure:"poll_interval_seconds" yaml:"poll_interval_seconds"` | |
| 174 | + | ||
| 175 | + | // Garbage collection interval in seconds (0 = disabled) | |
| 176 | + | EnableGCInterval int `mapstructure:"enable_gc_interval" yaml:"enable_gc_interval"` | |
| 177 | + | ||
| 178 | + | // Process recycling threshold (number of page loads) | |
| 179 | + | ProcessRecycleThreshold int `mapstructure:"process_recycle_threshold" yaml:"process_recycle_threshold"` | |
| 180 | + | ||
| 181 | + | // Enable memory monitoring logs | |
| 182 | + | EnableMemoryMonitoring bool `mapstructure:"enable_memory_monitoring" yaml:"enable_memory_monitoring"` | |
| 183 | + | } | |
| 184 | + | ||
| 155 | 185 | // Manager handles configuration loading, watching, and reloading. | |
| 156 | 186 | type Manager struct { | |
| 157 | 187 | config *Config | |
| @@ -257,6 +287,26 @@ func NewManager() (*Manager, error) { | |||
| 257 | 287 | } | |
| 258 | 288 | } | |
| 259 | 289 | ||
| 290 | + | // WebKit memory environment variable bindings | |
| 291 | + | memoryEnvBindings := map[string]string{ | |
| 292 | + | "webkit_memory.cache_model": "DUMBER_CACHE_MODEL", | |
| 293 | + | "webkit_memory.enable_page_cache": "DUMBER_ENABLE_PAGE_CACHE", | |
| 294 | + | "webkit_memory.memory_limit_mb": "DUMBER_MEMORY_LIMIT_MB", | |
| 295 | + | "webkit_memory.conservative_threshold": "DUMBER_MEMORY_CONSERVATIVE", | |
| 296 | + | "webkit_memory.strict_threshold": "DUMBER_MEMORY_STRICT", | |
| 297 | + | "webkit_memory.kill_threshold": "DUMBER_MEMORY_KILL", | |
| 298 | + | "webkit_memory.poll_interval_seconds": "DUMBER_MEMORY_POLL_INTERVAL", | |
| 299 | + | "webkit_memory.enable_gc_interval": "DUMBER_GC_INTERVAL", | |
| 300 | + | "webkit_memory.process_recycle_threshold": "DUMBER_RECYCLE_THRESHOLD", | |
| 301 | + | "webkit_memory.enable_memory_monitoring": "DUMBER_ENABLE_MEMORY_MONITORING", | |
| 302 | + | } | |
| 303 | + | ||
| 304 | + | for key, env := range memoryEnvBindings { | |
| 305 | + | if err := v.BindEnv(key, env); err != nil { | |
| 306 | + | return nil, fmt.Errorf("failed to bind environment variable %s: %w", env, err) | |
| 307 | + | } | |
| 308 | + | } | |
| 309 | + | ||
| 260 | 310 | return &Manager{ | |
| 261 | 311 | viper: v, | |
| 262 | 312 | callbacks: make([]func(*Config), 0), | |
| @@ -500,6 +550,18 @@ func (m *Manager) setDefaults() { | |||
| 500 | 550 | m.viper.SetDefault("codec_preferences.av1_max_resolution", defaults.CodecPreferences.AV1MaxResolution) | |
| 501 | 551 | m.viper.SetDefault("codec_preferences.disable_twitch_codec_control", defaults.CodecPreferences.DisableTwitchCodecControl) | |
| 502 | 552 | ||
| 553 | + | // WebKit memory defaults | |
| 554 | + | m.viper.SetDefault("webkit_memory.cache_model", defaults.WebkitMemory.CacheModel) | |
| 555 | + | m.viper.SetDefault("webkit_memory.enable_page_cache", defaults.WebkitMemory.EnablePageCache) | |
| 556 | + | m.viper.SetDefault("webkit_memory.memory_limit_mb", defaults.WebkitMemory.MemoryLimitMB) | |
| 557 | + | m.viper.SetDefault("webkit_memory.conservative_threshold", defaults.WebkitMemory.ConservativeThreshold) | |
| 558 | + | m.viper.SetDefault("webkit_memory.strict_threshold", defaults.WebkitMemory.StrictThreshold) | |
| 559 | + | m.viper.SetDefault("webkit_memory.kill_threshold", defaults.WebkitMemory.KillThreshold) | |
| 560 | + | m.viper.SetDefault("webkit_memory.poll_interval_seconds", defaults.WebkitMemory.PollIntervalSeconds) | |
| 561 | + | m.viper.SetDefault("webkit_memory.enable_gc_interval", defaults.WebkitMemory.EnableGCInterval) | |
| 562 | + | m.viper.SetDefault("webkit_memory.process_recycle_threshold", defaults.WebkitMemory.ProcessRecycleThreshold) | |
| 563 | + | m.viper.SetDefault("webkit_memory.enable_memory_monitoring", defaults.WebkitMemory.EnableMemoryMonitoring) | |
| 564 | + | ||
| 503 | 565 | // Rendering defaults | |
| 504 | 566 | m.viper.SetDefault("rendering_mode", string(RenderingModeAuto)) | |
| 505 | 567 | } | |
| @@ -33,6 +33,7 @@ type Config struct { | |||||
| 33 | Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"` | 33 | Appearance AppearanceConfig `mapstructure:"appearance" yaml:"appearance"` | ||
| 34 | VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"` | 34 | VideoAcceleration VideoAccelerationConfig `mapstructure:"video_acceleration" yaml:"video_acceleration"` | ||
| 35 | CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"` | 35 | CodecPreferences CodecConfig `mapstructure:"codec_preferences" yaml:"codec_preferences"` | ||
| 36 | + | WebkitMemory WebkitMemoryConfig `mapstructure:"webkit_memory" yaml:"webkit_memory"` | |||
| 36 | // RenderingMode controls GPU/CPU rendering selection for WebKit | 37 | // RenderingMode controls GPU/CPU rendering selection for WebKit | ||
| 37 | RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"` | 38 | RenderingMode RenderingMode `mapstructure:"rendering_mode" yaml:"rendering_mode"` | ||
| 38 | } | 39 | } | ||
| @@ -152,6 +153,35 @@ type CodecConfig struct { | |||||
| 152 | DisableTwitchCodecControl bool `mapstructure:"disable_twitch_codec_control" yaml:"disable_twitch_codec_control"` | 153 | DisableTwitchCodecControl bool `mapstructure:"disable_twitch_codec_control" yaml:"disable_twitch_codec_control"` | ||
| 153 | } | 154 | } | ||
| 154 | 155 | ||||
| 156 | + | // WebkitMemoryConfig holds WebKit memory optimization settings | |||
| 157 | + | type WebkitMemoryConfig struct { | |||
| 158 | + | // Cache model (document_viewer | web_browser | primary_web_browser) | |||
| 159 | + | CacheModel string `mapstructure:"cache_model" yaml:"cache_model"` | |||
| 160 | + | ||||
| 161 | + | // Enable page cache for back/forward navigation | |||
| 162 | + | EnablePageCache bool `mapstructure:"enable_page_cache" yaml:"enable_page_cache"` | |||
| 163 | + | ||||
| 164 | + | // Memory limit in MB (0 = system default) | |||
| 165 | + | MemoryLimitMB int `mapstructure:"memory_limit_mb" yaml:"memory_limit_mb"` | |||
| 166 | + | ||||
| 167 | + | // Memory pressure thresholds (0.0-1.0) | |||
| 168 | + | ConservativeThreshold float64 `mapstructure:"conservative_threshold" yaml:"conservative_threshold"` | |||
| 169 | + | StrictThreshold float64 `mapstructure:"strict_threshold" yaml:"strict_threshold"` | |||
| 170 | + | KillThreshold float64 `mapstructure:"kill_threshold" yaml:"kill_threshold"` | |||
| 171 | + | ||||
| 172 | + | // Memory monitoring interval in seconds | |||
| 173 | + | PollIntervalSeconds float64 `mapstructure:"poll_interval_seconds" yaml:"poll_interval_seconds"` | |||
| 174 | + | ||||
| 175 | + | // Garbage collection interval in seconds (0 = disabled) | |||
| 176 | + | EnableGCInterval int `mapstructure:"enable_gc_interval" yaml:"enable_gc_interval"` | |||
| 177 | + | ||||
| 178 | + | // Process recycling threshold (number of page loads) | |||
| 179 | + | ProcessRecycleThreshold int `mapstructure:"process_recycle_threshold" yaml:"process_recycle_threshold"` | |||
| 180 | + | ||||
| 181 | + | // Enable memory monitoring logs | |||
| 182 | + | EnableMemoryMonitoring bool `mapstructure:"enable_memory_monitoring" yaml:"enable_memory_monitoring"` | |||
| 183 | + | } | |||
| 184 | + | ||||
| 155 | // Manager handles configuration loading, watching, and reloading. | 185 | // Manager handles configuration loading, watching, and reloading. | ||
| 156 | type Manager struct { | 186 | type Manager struct { | ||
| 157 | config *Config | 187 | config *Config | ||
| @@ -257,6 +287,26 @@ func NewManager() (*Manager, error) { | |||||
| 257 | } | 287 | } | ||
| 258 | } | 288 | } | ||
| 259 | 289 | ||||
| 290 | + | // WebKit memory environment variable bindings | |||
| 291 | + | memoryEnvBindings := map[string]string{ | |||
| 292 | + | "webkit_memory.cache_model": "DUMBER_CACHE_MODEL", | |||
| 293 | + | "webkit_memory.enable_page_cache": "DUMBER_ENABLE_PAGE_CACHE", | |||
| 294 | + | "webkit_memory.memory_limit_mb": "DUMBER_MEMORY_LIMIT_MB", | |||
| 295 | + | "webkit_memory.conservative_threshold": "DUMBER_MEMORY_CONSERVATIVE", | |||
| 296 | + | "webkit_memory.strict_threshold": "DUMBER_MEMORY_STRICT", | |||
| 297 | + | "webkit_memory.kill_threshold": "DUMBER_MEMORY_KILL", | |||
| 298 | + | "webkit_memory.poll_interval_seconds": "DUMBER_MEMORY_POLL_INTERVAL", | |||
| 299 | + | "webkit_memory.enable_gc_interval": "DUMBER_GC_INTERVAL", | |||
| 300 | + | "webkit_memory.process_recycle_threshold": "DUMBER_RECYCLE_THRESHOLD", | |||
| 301 | + | "webkit_memory.enable_memory_monitoring": "DUMBER_ENABLE_MEMORY_MONITORING", | |||
| 302 | + | } | |||
| 303 | + | ||||
| 304 | + | for key, env := range memoryEnvBindings { | |||
| 305 | + | if err := v.BindEnv(key, env); err != nil { | |||
| 306 | + | return nil, fmt.Errorf("failed to bind environment variable %s: %w", env, err) | |||
| 307 | + | } | |||
| 308 | + | } | |||
| 309 | + | ||||
| 260 | return &Manager{ | 310 | return &Manager{ | ||
| 261 | viper: v, | 311 | viper: v, | ||
| 262 | callbacks: make([]func(*Config), 0), | 312 | callbacks: make([]func(*Config), 0), | ||
| @@ -500,6 +550,18 @@ func (m *Manager) setDefaults() { | |||||
| 500 | m.viper.SetDefault("codec_preferences.av1_max_resolution", defaults.CodecPreferences.AV1MaxResolution) | 550 | m.viper.SetDefault("codec_preferences.av1_max_resolution", defaults.CodecPreferences.AV1MaxResolution) | ||
| 501 | m.viper.SetDefault("codec_preferences.disable_twitch_codec_control", defaults.CodecPreferences.DisableTwitchCodecControl) | 551 | m.viper.SetDefault("codec_preferences.disable_twitch_codec_control", defaults.CodecPreferences.DisableTwitchCodecControl) | ||
| 502 | 552 | ||||
| 553 | + | // WebKit memory defaults | |||
| 554 | + | m.viper.SetDefault("webkit_memory.cache_model", defaults.WebkitMemory.CacheModel) | |||
| 555 | + | m.viper.SetDefault("webkit_memory.enable_page_cache", defaults.WebkitMemory.EnablePageCache) | |||
| 556 | + | m.viper.SetDefault("webkit_memory.memory_limit_mb", defaults.WebkitMemory.MemoryLimitMB) | |||
| 557 | + | m.viper.SetDefault("webkit_memory.conservative_threshold", defaults.WebkitMemory.ConservativeThreshold) | |||
| 558 | + | m.viper.SetDefault("webkit_memory.strict_threshold", defaults.WebkitMemory.StrictThreshold) | |||
| 559 | + | m.viper.SetDefault("webkit_memory.kill_threshold", defaults.WebkitMemory.KillThreshold) | |||
| 560 | + | m.viper.SetDefault("webkit_memory.poll_interval_seconds", defaults.WebkitMemory.PollIntervalSeconds) | |||
| 561 | + | m.viper.SetDefault("webkit_memory.enable_gc_interval", defaults.WebkitMemory.EnableGCInterval) | |||
| 562 | + | m.viper.SetDefault("webkit_memory.process_recycle_threshold", defaults.WebkitMemory.ProcessRecycleThreshold) | |||
| 563 | + | m.viper.SetDefault("webkit_memory.enable_memory_monitoring", defaults.WebkitMemory.EnableMemoryMonitoring) | |||
| 564 | + | ||||
| 503 | // Rendering defaults | 565 | // Rendering defaults | ||
| 504 | m.viper.SetDefault("rendering_mode", string(RenderingModeAuto)) | 566 | m.viper.SetDefault("rendering_mode", string(RenderingModeAuto)) | ||
| 505 | } | 567 | } | ||
M internal/config/defaults.go +12 -0
| @@ -119,6 +119,18 @@ func DefaultConfig() *Config { | |||
| 119 | 119 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | |
| 120 | 120 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | |
| 121 | 121 | }, | |
| 122 | + | WebkitMemory: WebkitMemoryConfig{ | |
| 123 | + | CacheModel: "web_browser", // Aggressive caching for fast page loads | |
| 124 | + | EnablePageCache: true, // Instant back/forward navigation | |
| 125 | + | MemoryLimitMB: 0, // Use system default | |
| 126 | + | ConservativeThreshold: 0.4, // Start cleanup at 40% | |
| 127 | + | StrictThreshold: 0.6, // Strict cleanup at 60% | |
| 128 | + | KillThreshold: 0.8, // Kill processes at 80% | |
| 129 | + | PollIntervalSeconds: 45.0, // Check every 45 seconds | |
| 130 | + | EnableGCInterval: 120, // GC every 2 minutes | |
| 131 | + | ProcessRecycleThreshold: 50, // Recycle after 50 page loads | |
| 132 | + | EnableMemoryMonitoring: true, // Monitor for production tuning | |
| 133 | + | }, | |
| 122 | 134 | RenderingMode: RenderingModeAuto, | |
| 123 | 135 | } | |
| 124 | 136 | } | |
| @@ -119,6 +119,18 @@ func DefaultConfig() *Config { | |||||
| 119 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | 119 | AV1MaxResolution: "1080p", // Optimal AV1 up to 1080p, fallback to VP9 for higher res | ||
| 120 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | 120 | DisableTwitchCodecControl: true, // Disable codec control on Twitch by default (prevents theater/fullscreen freezing) | ||
| 121 | }, | 121 | }, | ||
| 122 | + | WebkitMemory: WebkitMemoryConfig{ | |||
| 123 | + | CacheModel: "web_browser", // Aggressive caching for fast page loads | |||
| 124 | + | EnablePageCache: true, // Instant back/forward navigation | |||
| 125 | + | MemoryLimitMB: 0, // Use system default | |||
| 126 | + | ConservativeThreshold: 0.4, // Start cleanup at 40% | |||
| 127 | + | StrictThreshold: 0.6, // Strict cleanup at 60% | |||
| 128 | + | KillThreshold: 0.8, // Kill processes at 80% | |||
| 129 | + | PollIntervalSeconds: 45.0, // Check every 45 seconds | |||
| 130 | + | EnableGCInterval: 120, // GC every 2 minutes | |||
| 131 | + | ProcessRecycleThreshold: 50, // Recycle after 50 page loads | |||
| 132 | + | EnableMemoryMonitoring: true, // Monitor for production tuning | |||
| 133 | + | }, | |||
| 122 | RenderingMode: RenderingModeAuto, | 134 | RenderingMode: RenderingModeAuto, | ||
| 123 | } | 135 | } | ||
| 124 | } | 136 | } | ||