diff --git a/RESOURCE_DISPLAY_SUMMARY.md b/RESOURCE_DISPLAY_SUMMARY.md new file mode 100644 index 0000000..451f6fb --- /dev/null +++ b/RESOURCE_DISPLAY_SUMMARY.md @@ -0,0 +1,90 @@ +# Resource Usage Display - Implementation Summary + +## ✅ **Features Successfully Added** + +### 🎯 **Main UI Enhancements** +- **Resource Usage Group Box**: New section displaying real-time resource metrics +- **Toggle Button**: Hide/Show resources button to save screen space +- **Color-Coded Indicators**: Visual feedback for performance status +- **Interactive Help**: Click to get psutil installation instructions + +### 📊 **Monitoring Metrics** +1. **Memory Usage**: Process memory in MB and percentage +2. **CPU Usage**: Process CPU utilization percentage +3. **System Memory**: Overall system memory usage and available space +4. **Cache Information**: Template cache size and cooldown entries +5. **Performance**: Average automation loop execution time + +### 🔄 **Real-Time Updates** +- **2-Second Refresh**: Resource display updates every 2 seconds +- **Non-Blocking**: Updates don't interfere with automation performance +- **Automatic Monitoring**: Starts immediately when application launches + +### 🎨 **Visual Design** +- **Color-Coded Status**: + - 🟢 Green: Normal/Good performance + - 🟡 Orange: Warning levels + - 🔴 Red: High usage/Performance issues + - ⚫ Gray: Unavailable metrics +- **Compact Layout**: Fits seamlessly into existing UI +- **Professional Styling**: Consistent with application theme + +### 💡 **Smart Features** +- **Fallback Mode**: Works without psutil, shows basic cache information +- **Enhanced Mode**: Full system metrics when psutil is installed +- **Error Handling**: Graceful degradation if monitoring fails +- **Installation Guide**: Built-in help for psutil setup + +## 🚀 **Benefits** + +### For Performance Monitoring +- **Real-Time Visibility**: See exactly how much resources the app uses +- **Performance Bottlenecks**: Identify slow automation loops +- **Memory Leak Detection**: Monitor memory usage over time +- **System Impact**: Understand effect on overall system performance + +### For Troubleshooting +- **Quick Diagnosis**: Color-coded warnings for immediate issue identification +- **Cache Monitoring**: Track template cache efficiency +- **Resource Optimization**: Data to optimize scenario performance +- **System Health**: Monitor system memory and CPU usage + +## 📝 **Usage Instructions** + +### Basic Usage +1. **View Resources**: Resource panel is visible by default at the bottom of the main window +2. **Toggle Display**: Click "Hide Resources" button to minimize screen usage +3. **Monitor Status**: Watch color changes for performance alerts + +### Enhanced Monitoring +1. **Install psutil**: Run `pip install psutil` (already added to requirements.txt) +2. **Restart App**: Close and reopen VisionFlow Automator +3. **Full Metrics**: All detailed system information will be displayed + +### Reading the Display +- **Memory**: Shows process memory usage (green < 10%, red > 10%) +- **CPU**: Shows process CPU usage (green < 50%, red > 50%) +- **System**: Shows system memory usage (green < 85%, red > 85%) +- **Cache**: Shows template cache size (blue normal, orange > 20 entries) +- **Performance**: Shows loop execution time (green < 500ms, red > 500ms) + +## 🔧 **Technical Implementation** + +### Code Changes +- Enhanced `get_memory_usage()` method with comprehensive metrics +- Added `_update_resource_display()` for UI updates +- Modified `_monitor_performance()` for real-time monitoring +- Added resource display widgets to main UI layout +- Implemented toggle functionality for space-saving + +### Error Handling +- Graceful fallback when psutil unavailable +- Error display in resource panel for troubleshooting +- Maintains basic functionality even if monitoring fails + +### Performance Impact +- Minimal overhead (2-second update cycle) +- Non-blocking UI updates +- Optimized memory usage for monitoring itself + +The resource usage display provides valuable real-time insights into application performance and helps users optimize their automation scenarios for better efficiency and system resource management. diff --git a/RESOURCE_MONITORING.md b/RESOURCE_MONITORING.md new file mode 100644 index 0000000..4469706 --- /dev/null +++ b/RESOURCE_MONITORING.md @@ -0,0 +1,143 @@ +# Resource Usage Monitoring - VisionFlow Automator + +## Overview +The VisionFlow Automator now includes real-time resource usage monitoring displayed directly in the UI. This feature helps users monitor the application's performance and system impact. + +## Features Added + +### 🔍 **Resource Usage Display** +A new "Resource Usage" group box has been added to the main UI showing: + +#### Memory Usage +- **Process Memory**: Shows the application's memory usage in MB and percentage of system memory +- **Color-coded warnings**: Green for normal usage, red for high usage (>10% of system memory) + +#### CPU Usage +- **Process CPU**: Shows the application's CPU usage percentage +- **Color-coded warnings**: Green for normal usage, red for high usage (>50%) + +#### System Information +- **System Memory**: Shows overall system memory usage percentage and available memory in GB +- **Color-coded warnings**: Green for normal, red when system memory usage exceeds 85% + +#### Cache Information +- **Template Cache**: Number of cached CV2 templates +- **Cooldown Entries**: Number of active step cooldowns +- **Color-coded status**: Blue for normal, orange when template cache exceeds 20 entries + +#### Performance Metrics +- **Loop Time**: Average automation loop execution time in milliseconds +- **Color-coded performance**: Green for fast loops (<500ms), red for slow loops (>500ms) + +### 🎛️ **Controls** + +#### Toggle Button +- **Hide/Show Resources**: Button to toggle the visibility of resource usage information +- **Space-saving**: Users can hide the resource display if they don't need it +- **Tooltip**: Provides information about psutil installation for enhanced monitoring + +#### Interactive Elements +- **Clickable Labels**: When psutil is not installed, clicking on resource labels shows installation instructions +- **Installation Guide**: Built-in dialog explaining how to install psutil for enhanced monitoring + +### 📊 **Monitoring Levels** + +#### Basic Monitoring (Without psutil) +When psutil is not installed, the display shows: +- Template cache size +- Cooldown entries count +- Basic performance metrics +- "N/A" for system metrics with installation instructions + +#### Enhanced Monitoring (With psutil) +When psutil is installed (`pip install psutil`), the display shows: +- Detailed process memory usage +- CPU usage percentage +- System memory statistics +- Available system memory +- Process performance metrics + +### ⚙️ **Technical Details** + +#### Update Frequency +- **Real-time Updates**: Resource display updates every 2 seconds +- **Responsive UI**: Non-blocking updates that don't interfere with automation +- **Performance Optimized**: Minimal overhead from monitoring + +#### Color Coding System +- **🟢 Green**: Normal/Good performance +- **🟡 Orange/Yellow**: Warning levels +- **🔴 Red**: High usage/Performance issues +- **⚫ Gray**: Unavailable/Error states + +#### Error Handling +- **Graceful Degradation**: Shows basic info if detailed monitoring fails +- **Error Display**: Shows error messages for troubleshooting +- **Fallback Information**: Always shows cache and performance data + +### 🎯 **Benefits** + +#### For Users +- **Real-time Monitoring**: See exactly how much resources the app is using +- **Performance Insights**: Identify when the app is running slowly +- **System Impact**: Understand the app's impact on overall system performance +- **Troubleshooting**: Quickly identify memory leaks or performance issues + +#### For Developers +- **Performance Metrics**: Built-in performance profiling +- **Memory Leak Detection**: Monitor memory usage over time +- **Cache Optimization**: Track template cache efficiency +- **System Resources**: Monitor system-wide impact + +### 📋 **Usage Instructions** + +#### Basic Usage +1. **View Resources**: Resource usage is displayed by default in the main window +2. **Toggle Display**: Click "Hide Resources" to save screen space +3. **Monitor Performance**: Watch for color changes indicating performance issues + +#### Enhanced Monitoring Setup +1. **Install psutil**: Run `pip install psutil` in your Python environment +2. **Restart Application**: Close and reopen VisionFlow Automator +3. **Enhanced Display**: All metrics will now show detailed system information + +#### Interpreting Metrics +- **Memory < 100MB**: Normal usage for typical scenarios +- **CPU < 20%**: Normal usage during automation +- **Loop Time < 200ms**: Good performance +- **Cache < 20 entries**: Normal template usage + +### 🚨 **Warning Thresholds** + +#### Memory Warnings +- **Process Memory > 10%**: High memory usage warning +- **System Memory > 85%**: System memory critical + +#### Performance Warnings +- **CPU > 50%**: High CPU usage +- **Loop Time > 500ms**: Performance degradation +- **Cache > 20 entries**: Large template cache + +### 🔧 **Troubleshooting** + +#### High Memory Usage +- Check for memory leaks in long-running sessions +- Clear template cache periodically +- Reduce number of simultaneous image templates + +#### High CPU Usage +- Reduce automation frequency +- Optimize image template sizes +- Check for infinite loops in scenarios + +#### Slow Performance +- Monitor loop times for bottlenecks +- Reduce screenshot frequency +- Optimize template matching regions + +#### Missing psutil +- Install with: `pip install psutil` +- Click on gray resource labels for installation instructions +- Restart application after installation + +The resource monitoring feature provides valuable insights into the application's performance and helps users optimize their automation scenarios for better efficiency. diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc index 96dc202..d4a507d 100644 Binary files a/__pycache__/main.cpython-313.pyc and b/__pycache__/main.cpython-313.pyc differ diff --git a/main.py b/main.py index 9ace82d..55b3780 100644 --- a/main.py +++ b/main.py @@ -603,16 +603,45 @@ class MainWindow(QtWidgets.QMainWindow): import psutil process = psutil.Process() memory_info = process.memory_info() + cpu_percent = process.cpu_percent() + + # Get system info + system_memory = psutil.virtual_memory() + return { - 'rss': memory_info.rss / 1024 / 1024, # MB - 'vms': memory_info.vms / 1024 / 1024, # MB - 'percent': process.memory_percent() + 'process_memory_mb': memory_info.rss / 1024 / 1024, # MB + 'process_memory_percent': process.memory_percent(), + 'cpu_percent': cpu_percent, + 'system_memory_percent': system_memory.percent, + 'system_memory_available_gb': system_memory.available / 1024 / 1024 / 1024, # GB + '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 } except ImportError: # psutil not available, return basic info return { - 'template_cache_size': len(template_cache._cache), - 'cooldown_entries': len(self._step_cooldown) if hasattr(self, '_step_cooldown') else 0 + 'process_memory_mb': 0, + 'process_memory_percent': 0, + 'cpu_percent': 0, + 'system_memory_percent': 0, + 'system_memory_available_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 + } + except Exception as e: + logger.warning(f"Error getting memory usage: {e}") + return { + 'process_memory_mb': 0, + 'process_memory_percent': 0, + 'cpu_percent': 0, + 'system_memory_percent': 0, + 'system_memory_available_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) } def stop_automation(self): @@ -694,20 +723,23 @@ class MainWindow(QtWidgets.QMainWindow): # Setup periodic monitoring timer self.monitor_timer = QtCore.QTimer() self.monitor_timer.timeout.connect(self._monitor_performance) - self.monitor_timer.start(10000) # Monitor every 10 seconds + self.monitor_timer.start(2000) # Monitor every 2 seconds for responsive UI updates + + # Initial resource display update + QtCore.QTimer.singleShot(100, self._monitor_performance) def _monitor_performance(self): """ Monitor application performance and memory usage. """ - if not self.running: - return - try: memory_info = self.get_memory_usage() - # Log performance stats periodically - if hasattr(self, '_loop_times') and self._loop_times: + # Update resource display + self._update_resource_display(memory_info) + + # Log performance stats periodically (only if running) + if self.running and hasattr(self, '_loop_times') and self._loop_times: avg_loop_time = sum(self._loop_times) / len(self._loop_times) # Warning thresholds @@ -715,17 +747,133 @@ class MainWindow(QtWidgets.QMainWindow): logger.warning(f"Performance issue: Average loop time {avg_loop_time:.3f}s") # Memory warning for cache-based monitoring - if 'template_cache_size' in memory_info and memory_info['template_cache_size'] > 20: + if memory_info.get('template_cache_size', 0) > 20: logger.info(f"Template cache has {memory_info['template_cache_size']} entries") except Exception as e: logger.debug(f"Performance monitoring error: {e}") + def _update_resource_display(self, memory_info): + """ + Update the resource usage display in the UI. + """ + try: + # Memory usage + if memory_info.get('has_psutil', False): + memory_text = f"Memory: {memory_info['process_memory_mb']:.1f}MB ({memory_info['process_memory_percent']:.1f}%)" + memory_color = '#d9534f' if memory_info['process_memory_percent'] > 10 else '#5cb85c' + else: + memory_text = "Memory: N/A (psutil needed)" + memory_color = '#f0ad4e' + + self.memory_label.setText(memory_text) + self.memory_label.setStyleSheet(f'font-size: 9pt; color: {memory_color};') + + # Make memory label clickable to show psutil installation info + if not memory_info.get('has_psutil', False): + self.memory_label.mousePressEvent = lambda event: self._show_psutil_info() + self.memory_label.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor)) + + # CPU usage + if memory_info.get('has_psutil', False): + cpu_text = f"CPU: {memory_info['cpu_percent']:.1f}%" + cpu_color = '#d9534f' if memory_info['cpu_percent'] > 50 else '#5cb85c' + else: + cpu_text = "CPU: N/A" + cpu_color = '#777' + + self.cpu_label.setText(cpu_text) + self.cpu_label.setStyleSheet(f'font-size: 9pt; color: {cpu_color};') + + # System memory + if memory_info.get('has_psutil', False): + system_text = f"System: {memory_info['system_memory_percent']:.1f}% ({memory_info['system_memory_available_gb']:.1f}GB free)" + system_color = '#d9534f' if memory_info['system_memory_percent'] > 85 else '#5cb85c' + else: + system_text = "System: N/A" + system_color = '#777' + + self.system_memory_label.setText(system_text) + self.system_memory_label.setStyleSheet(f'font-size: 9pt; color: {system_color};') + + # Cache info + cache_text = f"Cache: {memory_info['template_cache_size']} templates, {memory_info['cooldown_entries']} cooldowns" + cache_color = '#f0ad4e' if memory_info['template_cache_size'] > 20 else '#5bc0de' + + self.cache_label.setText(cache_text) + self.cache_label.setStyleSheet(f'font-size: 9pt; color: {cache_color};') + + # Performance info + if hasattr(self, '_loop_times') and self._loop_times: + avg_time = sum(self._loop_times) / len(self._loop_times) + perf_text = f"Performance: {avg_time*1000:.0f}ms avg loop time" + perf_color = '#d9534f' if avg_time > 0.5 else '#5cb85c' + else: + perf_text = "Performance: Not running" + perf_color = '#777' + + self.performance_label.setText(perf_text) + self.performance_label.setStyleSheet(f'font-size: 9pt; color: {perf_color};') + + # Show error if any + if 'error' in memory_info: + self.performance_label.setText(f"Error: {memory_info['error'][:50]}...") + self.performance_label.setStyleSheet('font-size: 9pt; color: #d9534f;') + + except Exception as e: + logger.debug(f"Error updating resource display: {e}") + # Show basic fallback info + self.memory_label.setText("Memory: Error") + self.cpu_label.setText("CPU: Error") + self.system_memory_label.setText("System: Error") + self.cache_label.setText("Cache: Error") + self.performance_label.setText(f"Display Error: {str(e)[:30]}...") + def stop_monitoring(self): """Stop performance monitoring timer.""" if hasattr(self, 'monitor_timer') and self.monitor_timer: self.monitor_timer.stop() + def _toggle_resource_display(self): + """Toggle the visibility of resource usage widgets.""" + if self.resource_widgets_visible: + # Hide resource widgets + self.memory_label.hide() + self.cpu_label.hide() + self.system_memory_label.hide() + self.cache_label.hide() + self.performance_label.hide() + self.toggle_resources_btn.setText('Show Resources') + self.resource_widgets_visible = False + else: + # Show resource widgets + self.memory_label.show() + self.cpu_label.show() + self.system_memory_label.show() + self.cache_label.show() + self.performance_label.show() + self.toggle_resources_btn.setText('Hide Resources') + self.resource_widgets_visible = True + + def _show_psutil_info(self): + """Show information about installing psutil for enhanced monitoring.""" + msg = QtWidgets.QMessageBox(self) + msg.setWindowTitle("Enhanced Resource Monitoring") + msg.setIcon(QtWidgets.QMessageBox.Icon.Information) + msg.setText("Install psutil for detailed resource monitoring") + msg.setInformativeText( + "For detailed CPU, memory, and system resource monitoring, install the psutil package:\n\n" + "pip install psutil\n\n" + "This will enable:\n" + "• Process memory usage in MB and percentage\n" + "• CPU usage percentage\n" + "• System memory statistics\n" + "• Available system memory\n\n" + "Without psutil, only basic cache information is shown." + ) + msg.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Ok) + msg.exec() + def closeEvent(self, event): """Handle application close event with proper cleanup.""" self.cleanup_resources() @@ -877,6 +1025,48 @@ class MainWindow(QtWidgets.QMainWindow): self.state_label.setStyleSheet('font-weight: bold; font-size: 11pt; color: #0055aa;') self.state_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter) + # Resource usage display + self.resource_group = QtWidgets.QGroupBox('Resource Usage') + self.resource_group.setSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Fixed) + resource_layout = QtWidgets.QGridLayout() + resource_layout.setSpacing(4) + resource_layout.setContentsMargins(6, 6, 6, 6) + + # Toggle button for resource display + self.toggle_resources_btn = QtWidgets.QPushButton('Hide Resources') + self.toggle_resources_btn.setMaximumWidth(100) + self.toggle_resources_btn.setToolTip('Toggle resource usage display. Install psutil for detailed system metrics.') + self.toggle_resources_btn.clicked.connect(self._toggle_resource_display) + resource_layout.addWidget(self.toggle_resources_btn, 0, 2, 1, 1) + + # Memory usage + self.memory_label = QtWidgets.QLabel('Memory: --') + self.memory_label.setStyleSheet('font-size: 9pt; color: #333;') + resource_layout.addWidget(self.memory_label, 0, 0) + + # CPU usage + self.cpu_label = QtWidgets.QLabel('CPU: --') + self.cpu_label.setStyleSheet('font-size: 9pt; color: #333;') + resource_layout.addWidget(self.cpu_label, 0, 1) + + # System memory + self.system_memory_label = QtWidgets.QLabel('System: --') + self.system_memory_label.setStyleSheet('font-size: 9pt; color: #333;') + resource_layout.addWidget(self.system_memory_label, 1, 0) + + # Cache info + self.cache_label = QtWidgets.QLabel('Cache: --') + self.cache_label.setStyleSheet('font-size: 9pt; color: #333;') + resource_layout.addWidget(self.cache_label, 1, 1) + + # Performance info + self.performance_label = QtWidgets.QLabel('Performance: --') + self.performance_label.setStyleSheet('font-size: 9pt; color: #333;') + resource_layout.addWidget(self.performance_label, 2, 0, 1, 3) + + self.resource_group.setLayout(resource_layout) + self.resource_widgets_visible = True + # Main layout layout = QtWidgets.QGridLayout() layout.setHorizontalSpacing(6) @@ -889,6 +1079,10 @@ class MainWindow(QtWidgets.QMainWindow): layout.addWidget(window_group_box, 1, 0, 1, 5) layout.addWidget(steps_group_box, 2, 0, 3, 5) + # Resource usage group + layout.addWidget(self.resource_group, 5, 0, 1, 5) + layout.setRowStretch(5, 0) # Resource group should not stretch vertically + # Start/State row in a group start_state_group = QtWidgets.QGroupBox() start_state_group.setTitle("") @@ -899,8 +1093,8 @@ class MainWindow(QtWidgets.QMainWindow): start_state_layout.addWidget(self.state_label) start_state_layout.addStretch(1) start_state_group.setLayout(start_state_layout) - layout.addWidget(start_state_group, 5, 0, 1, 5) - layout.setRowStretch(5, 0) # Prevent vertical stretch + layout.addWidget(start_state_group, 6, 0, 1, 5) + layout.setRowStretch(6, 0) # Prevent vertical stretch # Set central widget (must be at the end of init_ui) central = QtWidgets.QWidget() diff --git a/requirements.txt b/requirements.txt index 38259df..ead58e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ pyautogui pynput pygetwindow numpy -Pillow \ No newline at end of file +Pillow +psutil # Optional: For enhanced resource monitoring \ No newline at end of file