Enhance memory usage tracking with improved CPU calculation and error handling
This commit is contained in:
@@ -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']};
|
||||
|
||||
Reference in New Issue
Block a user