Enhance memory usage tracking with improved CPU calculation and error handling

This commit is contained in:
2025-08-18 09:49:28 +02:00
parent 2f8b3ba872
commit b6662d81da
+74 -60
View File
@@ -1617,50 +1617,71 @@ class MainWindow(QtWidgets.QMainWindow):
logger.info('Automation started successfully.')
def get_memory_usage(self):
"""
Get current memory usage information for monitoring, including GPU memory.
Uses timeout protection to prevent UI hanging.
"""
"""Return dict of process/system resource usage with improved CPU calculation."""
try:
import psutil
process = psutil.Process()
memory_info = process.memory_info()
cpu_percent = process.cpu_percent()
proc = psutil.Process()
mem_info = proc.memory_info()
# Get system info
system_memory = psutil.virtual_memory()
system_cpu = psutil.cpu_percent(interval=0.1) # System-wide CPU usage
# Get GPU information with error handling (non-blocking)
# Improved per-process CPU percent (delta since last call)
cpu_percent = 0.0
try:
gpu_info = get_gpu_memory_info()
now = time.time()
times = proc.cpu_times()
if self._last_proc_cpu_times is not None and self._last_cpu_timestamp is not None:
prev_total = (self._last_proc_cpu_times.user + getattr(self._last_proc_cpu_times, 'system', 0))
curr_total = (times.user + getattr(times, 'system', 0))
delta_proc = curr_total - prev_total
delta_time = max(1e-6, now - self._last_cpu_timestamp)
cpu_percent = (delta_proc / delta_time) * 100.0 / max(1, self._num_cpus)
if cpu_percent < 0:
cpu_percent = 0.0
elif cpu_percent > 100:
cpu_percent = min(cpu_percent, 100.0)
self._last_proc_cpu_times = times
self._last_cpu_timestamp = now
except Exception as e:
logger.debug(f"GPU detection failed: {e}")
gpu_info = {'has_gpu': False, 'total_mb': 0, 'used_mb': 0, 'free_mb': 0, 'utilization_percent': 0, 'gpu_name': 'Error', 'method': 'error'}
logger.debug(f"CPU calc delta failed, fallback: {e}")
try:
cpu_percent = proc.cpu_percent(interval=0.0)
except Exception:
cpu_percent = 0.0
# System metrics (non-blocking)
virt = psutil.virtual_memory()
try:
system_cpu = psutil.cpu_percent(interval=0.0)
except Exception:
system_cpu = psutil.cpu_percent(interval=0.05)
# GPU metrics
try:
gpu = get_gpu_memory_info()
except Exception as ge:
logger.debug(f"GPU info failed: {ge}")
gpu = {'has_gpu': False, 'total_mb': 0, 'used_mb': 0, 'free_mb': 0, 'utilization_percent': 0, 'gpu_name': 'Error', 'method': 'error'}
return {
'process_memory_mb': memory_info.rss / 1024 / 1024, # MB
'process_memory_percent': process.memory_percent(),
'cpu_percent': cpu_percent, # Process CPU
'system_cpu_percent': system_cpu, # System-wide CPU
'system_memory_percent': system_memory.percent,
'system_memory_available_gb': system_memory.available / 1024 / 1024 / 1024, # GB
'system_memory_total_gb': system_memory.total / 1024 / 1024 / 1024, # GB
'system_memory_used_gb': system_memory.used / 1024 / 1024 / 1024, # GB
'process_memory_mb': mem_info.rss / 1024 / 1024,
'process_memory_percent': proc.memory_percent(),
'cpu_percent': cpu_percent,
'system_cpu_percent': system_cpu,
'system_memory_percent': virt.percent,
'system_memory_available_gb': virt.available / 1024 / 1024 / 1024,
'system_memory_total_gb': virt.total / 1024 / 1024 / 1024,
'system_memory_used_gb': virt.used / 1024 / 1024 / 1024,
'template_cache_size': len(template_cache._cache) if hasattr(template_cache, '_cache') else 0,
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
'has_psutil': True,
# GPU information
'gpu_has_gpu': gpu_info['has_gpu'],
'gpu_total_mb': gpu_info['total_mb'],
'gpu_used_mb': gpu_info['used_mb'],
'gpu_free_mb': gpu_info['free_mb'],
'gpu_utilization_percent': gpu_info['utilization_percent'],
'gpu_name': gpu_info['gpu_name'],
'gpu_method': gpu_info.get('method', 'none')
'gpu_has_gpu': gpu['has_gpu'],
'gpu_total_mb': gpu['total_mb'],
'gpu_used_mb': gpu['used_mb'],
'gpu_free_mb': gpu['free_mb'],
'gpu_utilization_percent': gpu['utilization_percent'],
'gpu_name': gpu['gpu_name'],
'gpu_method': gpu.get('method', 'none')
}
except ImportError:
# psutil not available, minimal info without GPU detection to prevent hanging
return {
'process_memory_mb': 0,
'process_memory_percent': 0,
@@ -1673,7 +1694,6 @@ class MainWindow(QtWidgets.QMainWindow):
'template_cache_size': len(template_cache._cache) if hasattr(template_cache, '_cache') else 0,
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
'has_psutil': False,
# Minimal GPU info to prevent hanging
'gpu_has_gpu': False,
'gpu_total_mb': 0,
'gpu_used_mb': 0,
@@ -1683,19 +1703,19 @@ class MainWindow(QtWidgets.QMainWindow):
'gpu_method': 'disabled'
}
except Exception as e:
logger.warning(f"Error getting memory usage (non-critical): {e}")
# Fallback minimal info to prevent hanging
logger.warning(f"get_memory_usage fallback: {e}")
return {
'process_memory_mb': 0,
'process_memory_percent': 0,
'cpu_percent': 0,
'system_cpu_percent': 0,
'system_memory_percent': 0,
'system_memory_available_gb': 0,
'system_memory_total_gb': 0,
'system_memory_used_gb': 0,
'template_cache_size': len(template_cache._cache) if hasattr(template_cache, '_cache') else 0,
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
'has_psutil': False,
'error': str(e),
# Minimal GPU info to prevent hanging
'gpu_has_gpu': False,
'gpu_total_mb': 0,
'gpu_used_mb': 0,
@@ -1786,6 +1806,15 @@ class MainWindow(QtWidgets.QMainWindow):
self._memory_cleanup_timer.start(300000) # Cleanup every 5 minutes
self._last_memory_cleanup = time.time()
# Improved CPU usage tracking (store previous CPU times for delta calculation)
self._last_proc_cpu_times = None
self._last_cpu_timestamp = None
try:
import psutil # Local import guarded; may fail if psutil missing
self._num_cpus = psutil.cpu_count(logical=True) or 1
except Exception:
self._num_cpus = 1
# Resource usage tracking for max/average values
self._resource_history = {
'memory_mb': [],
@@ -1829,29 +1858,20 @@ class MainWindow(QtWidgets.QMainWindow):
QtCore.QTimer.singleShot(1000, self._save_window_geometry)
def _check_system_theme_change(self):
"""
Check if the system theme has changed and update accordingly.
Only runs when theme_mode is 'system'.
"""
"""Detect system theme change when in 'system' mode and re-apply theme."""
if self.theme_mode != 'system':
self.theme_monitor_timer.stop()
return
try:
current_system_theme = self.is_system_dark_theme()
if self._last_system_theme is None:
self._last_system_theme = current_system_theme
return
if current_system_theme != self._last_system_theme:
logger.info(f'System theme changed to: {"Dark" if current_system_theme else "Light"}')
self._last_system_theme = current_system_theme
self.apply_theme()
self._update_theme_combo_text()
except Exception as e:
logger.debug(f"Error checking system theme change: {e}")
logger.debug(f"System theme check failed: {e}")
def _update_resource_history(self, memory_info):
"""
@@ -1937,7 +1957,6 @@ class MainWindow(QtWidgets.QMainWindow):
return
try:
# Add timeout protection for memory info gathering
memory_info = self.get_memory_usage()
# Update resource display (this should be fast)
@@ -1967,9 +1986,9 @@ class MainWindow(QtWidgets.QMainWindow):
cpu_msg = f"High CPU usage: {memory_info['cpu_percent']:.1f}%"
self._log_warning_once("cpu_high", cpu_msg)
# GPU memory usage warning
# GPU utilization warning
if memory_info.get('gpu_has_gpu', False) and memory_info.get('gpu_utilization_percent', 0) > 90:
gpu_msg = f"High GPU memory usage: {memory_info['gpu_utilization_percent']:.1f}%"
gpu_msg = f"High GPU usage: {memory_info['gpu_utilization_percent']:.1f}%"
self._log_warning_once("gpu_high", gpu_msg)
except Exception as e:
@@ -2984,17 +3003,12 @@ class MainWindow(QtWidgets.QMainWindow):
subcontrol-position: center right;
}}
QComboBox::down-arrow {{
image: none;
width: 0px;
height: 0px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 6px solid {colors['foreground']};
margin: 0px;
padding: 0px;
/* Use native arrow; prior triangle via borders rendered as rectangles on some systems */
width: 12px;
height: 12px;
}}
QComboBox::down-arrow:hover {{
border-top-color: {colors['accent']};
/* Keep default hover */
}}
QComboBox QAbstractItemView {{
background-color: {colors['input_bg']};