Add real-time resource monitoring and UI enhancements

- Implemented a new resource usage display in the main UI, showing memory, CPU, and system metrics.
- Added toggle functionality to hide/show resource information.
- Enhanced performance monitoring with real-time updates every 2 seconds.
- Included error handling and fallback modes for when psutil is not installed.
- Updated requirements.txt to include psutil for enhanced monitoring capabilities.
This commit is contained in:
2025-07-31 13:45:00 +02:00
parent 2d2389436d
commit abb21792d6
5 changed files with 443 additions and 15 deletions
+90
View File
@@ -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.
+143
View File
@@ -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.
Binary file not shown.
+208 -14
View File
@@ -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()
+2 -1
View File
@@ -4,4 +4,5 @@ pyautogui
pynput
pygetwindow
numpy
Pillow
Pillow
psutil # Optional: For enhanced resource monitoring