diff --git a/main.py b/main.py index 62d50d7..b0dad1b 100644 --- a/main.py +++ b/main.py @@ -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() - - # 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) + proc = psutil.Process() + mem_info = proc.memory_info() + + # 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']};