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.')
|
logger.info('Automation started successfully.')
|
||||||
|
|
||||||
def get_memory_usage(self):
|
def get_memory_usage(self):
|
||||||
"""
|
"""Return dict of process/system resource usage with improved CPU calculation."""
|
||||||
Get current memory usage information for monitoring, including GPU memory.
|
|
||||||
Uses timeout protection to prevent UI hanging.
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
import psutil
|
import psutil
|
||||||
process = psutil.Process()
|
proc = psutil.Process()
|
||||||
memory_info = process.memory_info()
|
mem_info = proc.memory_info()
|
||||||
cpu_percent = process.cpu_percent()
|
|
||||||
|
# Improved per-process CPU percent (delta since last call)
|
||||||
# Get system info
|
cpu_percent = 0.0
|
||||||
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)
|
|
||||||
try:
|
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:
|
except Exception as e:
|
||||||
logger.debug(f"GPU detection failed: {e}")
|
logger.debug(f"CPU calc delta failed, fallback: {e}")
|
||||||
gpu_info = {'has_gpu': False, 'total_mb': 0, 'used_mb': 0, 'free_mb': 0, 'utilization_percent': 0, 'gpu_name': 'Error', 'method': 'error'}
|
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 {
|
return {
|
||||||
'process_memory_mb': memory_info.rss / 1024 / 1024, # MB
|
'process_memory_mb': mem_info.rss / 1024 / 1024,
|
||||||
'process_memory_percent': process.memory_percent(),
|
'process_memory_percent': proc.memory_percent(),
|
||||||
'cpu_percent': cpu_percent, # Process CPU
|
'cpu_percent': cpu_percent,
|
||||||
'system_cpu_percent': system_cpu, # System-wide CPU
|
'system_cpu_percent': system_cpu,
|
||||||
'system_memory_percent': system_memory.percent,
|
'system_memory_percent': virt.percent,
|
||||||
'system_memory_available_gb': system_memory.available / 1024 / 1024 / 1024, # GB
|
'system_memory_available_gb': virt.available / 1024 / 1024 / 1024,
|
||||||
'system_memory_total_gb': system_memory.total / 1024 / 1024 / 1024, # GB
|
'system_memory_total_gb': virt.total / 1024 / 1024 / 1024,
|
||||||
'system_memory_used_gb': system_memory.used / 1024 / 1024 / 1024, # GB
|
'system_memory_used_gb': virt.used / 1024 / 1024 / 1024,
|
||||||
'template_cache_size': len(template_cache._cache) if hasattr(template_cache, '_cache') else 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,
|
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
|
||||||
'has_psutil': True,
|
'has_psutil': True,
|
||||||
# GPU information
|
'gpu_has_gpu': gpu['has_gpu'],
|
||||||
'gpu_has_gpu': gpu_info['has_gpu'],
|
'gpu_total_mb': gpu['total_mb'],
|
||||||
'gpu_total_mb': gpu_info['total_mb'],
|
'gpu_used_mb': gpu['used_mb'],
|
||||||
'gpu_used_mb': gpu_info['used_mb'],
|
'gpu_free_mb': gpu['free_mb'],
|
||||||
'gpu_free_mb': gpu_info['free_mb'],
|
'gpu_utilization_percent': gpu['utilization_percent'],
|
||||||
'gpu_utilization_percent': gpu_info['utilization_percent'],
|
'gpu_name': gpu['gpu_name'],
|
||||||
'gpu_name': gpu_info['gpu_name'],
|
'gpu_method': gpu.get('method', 'none')
|
||||||
'gpu_method': gpu_info.get('method', 'none')
|
|
||||||
}
|
}
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# psutil not available, minimal info without GPU detection to prevent hanging
|
|
||||||
return {
|
return {
|
||||||
'process_memory_mb': 0,
|
'process_memory_mb': 0,
|
||||||
'process_memory_percent': 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,
|
'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,
|
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
|
||||||
'has_psutil': False,
|
'has_psutil': False,
|
||||||
# Minimal GPU info to prevent hanging
|
|
||||||
'gpu_has_gpu': False,
|
'gpu_has_gpu': False,
|
||||||
'gpu_total_mb': 0,
|
'gpu_total_mb': 0,
|
||||||
'gpu_used_mb': 0,
|
'gpu_used_mb': 0,
|
||||||
@@ -1683,19 +1703,19 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
'gpu_method': 'disabled'
|
'gpu_method': 'disabled'
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error getting memory usage (non-critical): {e}")
|
logger.warning(f"get_memory_usage fallback: {e}")
|
||||||
# Fallback minimal info to prevent hanging
|
|
||||||
return {
|
return {
|
||||||
'process_memory_mb': 0,
|
'process_memory_mb': 0,
|
||||||
'process_memory_percent': 0,
|
'process_memory_percent': 0,
|
||||||
'cpu_percent': 0,
|
'cpu_percent': 0,
|
||||||
|
'system_cpu_percent': 0,
|
||||||
'system_memory_percent': 0,
|
'system_memory_percent': 0,
|
||||||
'system_memory_available_gb': 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,
|
'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,
|
'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0,
|
||||||
'has_psutil': False,
|
'has_psutil': False,
|
||||||
'error': str(e),
|
|
||||||
# Minimal GPU info to prevent hanging
|
|
||||||
'gpu_has_gpu': False,
|
'gpu_has_gpu': False,
|
||||||
'gpu_total_mb': 0,
|
'gpu_total_mb': 0,
|
||||||
'gpu_used_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._memory_cleanup_timer.start(300000) # Cleanup every 5 minutes
|
||||||
self._last_memory_cleanup = time.time()
|
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
|
# Resource usage tracking for max/average values
|
||||||
self._resource_history = {
|
self._resource_history = {
|
||||||
'memory_mb': [],
|
'memory_mb': [],
|
||||||
@@ -1829,29 +1858,20 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
QtCore.QTimer.singleShot(1000, self._save_window_geometry)
|
QtCore.QTimer.singleShot(1000, self._save_window_geometry)
|
||||||
|
|
||||||
def _check_system_theme_change(self):
|
def _check_system_theme_change(self):
|
||||||
"""
|
"""Detect system theme change when in 'system' mode and re-apply theme."""
|
||||||
Check if the system theme has changed and update accordingly.
|
|
||||||
Only runs when theme_mode is 'system'.
|
|
||||||
"""
|
|
||||||
if self.theme_mode != 'system':
|
if self.theme_mode != 'system':
|
||||||
self.theme_monitor_timer.stop()
|
self.theme_monitor_timer.stop()
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_system_theme = self.is_system_dark_theme()
|
current_system_theme = self.is_system_dark_theme()
|
||||||
|
|
||||||
if self._last_system_theme is None:
|
if self._last_system_theme is None:
|
||||||
self._last_system_theme = current_system_theme
|
self._last_system_theme = current_system_theme
|
||||||
return
|
return
|
||||||
|
|
||||||
if current_system_theme != self._last_system_theme:
|
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._last_system_theme = current_system_theme
|
||||||
self.apply_theme()
|
self.apply_theme()
|
||||||
self._update_theme_combo_text()
|
|
||||||
|
|
||||||
except Exception as e:
|
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):
|
def _update_resource_history(self, memory_info):
|
||||||
"""
|
"""
|
||||||
@@ -1937,7 +1957,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Add timeout protection for memory info gathering
|
|
||||||
memory_info = self.get_memory_usage()
|
memory_info = self.get_memory_usage()
|
||||||
|
|
||||||
# Update resource display (this should be fast)
|
# 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}%"
|
cpu_msg = f"High CPU usage: {memory_info['cpu_percent']:.1f}%"
|
||||||
self._log_warning_once("cpu_high", cpu_msg)
|
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:
|
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)
|
self._log_warning_once("gpu_high", gpu_msg)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2984,17 +3003,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
subcontrol-position: center right;
|
subcontrol-position: center right;
|
||||||
}}
|
}}
|
||||||
QComboBox::down-arrow {{
|
QComboBox::down-arrow {{
|
||||||
image: none;
|
/* Use native arrow; prior triangle via borders rendered as rectangles on some systems */
|
||||||
width: 0px;
|
width: 12px;
|
||||||
height: 0px;
|
height: 12px;
|
||||||
border-left: 5px solid transparent;
|
|
||||||
border-right: 5px solid transparent;
|
|
||||||
border-top: 6px solid {colors['foreground']};
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}}
|
}}
|
||||||
QComboBox::down-arrow:hover {{
|
QComboBox::down-arrow:hover {{
|
||||||
border-top-color: {colors['accent']};
|
/* Keep default hover */
|
||||||
}}
|
}}
|
||||||
QComboBox QAbstractItemView {{
|
QComboBox QAbstractItemView {{
|
||||||
background-color: {colors['input_bg']};
|
background-color: {colors['input_bg']};
|
||||||
|
|||||||
Reference in New Issue
Block a user