Coverage for openhcs/textual_tui/services/system_monitor.py: 0.0%
102 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 02:09 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-04 02:09 +0000
1"""
2System Monitor with Plotext Visualization
3Real-time system monitoring with plotext visualization for Textual TUI.
5This module extends SystemMonitorCore with plotext-specific visualization.
6"""
8import plotext as plt
9import platform
10import psutil
11import time
12from datetime import datetime
13import io
14import sys
16from openhcs.ui.shared.system_monitor_core import SystemMonitorCore, GPU_AVAILABLE, get_cpu_freq_mhz
19class SystemMonitor(SystemMonitorCore):
20 """System monitoring with plotext visualization (TUI-specific)."""
22 def __init__(self, history_length=60):
23 """Initialize with plotext visualization support."""
24 super().__init__(history_length)
26 def get_ascii_title(self):
27 """Return the OpenHCS ASCII art title"""
28 return """
29╔═══════════════════════════════════════════════════════════════════════╗
30║ ██████╗ ██████╗ ███████╗███╗ ██╗██╗ ██╗ ██████╗███████╗ ║
31║ ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██║ ██║██╔════╝██╔════╝ ║
32║ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║██║ ███████╗ ║
33║ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║██║ ╚════██║ ║
34║ ╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║╚██████╗███████║ ║
35║ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝╚══════╝ ║
36╚═══════════════════════════════════════════════════════════════════════╝"""
38 def create_monitor_view(self, width=80, height=30):
39 """Create the system monitor visualization"""
40 plt.clear_figure()
42 # Create subplots
43 plt.subplots(2, 2)
44 plt.plot_size(width=width, height=height)
46 # Get current metrics for display
47 current_cpu = self.cpu_history[-1] if self.cpu_history else 0
48 current_ram = self.ram_history[-1] if self.ram_history else 0
49 current_gpu = self.gpu_history[-1] if self.gpu_history else 0
50 current_vram = self.vram_history[-1] if self.vram_history else 0
52 # Get system info
53 ram_info = psutil.virtual_memory()
54 ram_used_gb = ram_info.used / (1024**3)
55 ram_total_gb = ram_info.total / (1024**3)
57 x_range = list(range(len(self.cpu_history)))
59 # CPU Usage Plot (Top Left)
60 plt.subplot(1, 1)
61 plt.theme('dark')
62 plt.plot(x_range, list(self.cpu_history), color='cyan')
63 plt.ylim(0, 100)
64 plt.title(f"CPU Usage: {current_cpu:.1f}%")
65 plt.xlabel("Time (seconds)")
66 plt.ylabel("Usage %")
68 # RAM Usage Plot (Top Right)
69 plt.subplot(1, 2)
70 plt.theme('dark')
71 plt.plot(x_range, list(self.ram_history), color='green')
72 plt.ylim(0, 100)
73 plt.title(f"RAM: {ram_used_gb:.1f}/{ram_total_gb:.1f} GB ({current_ram:.1f}%)")
74 plt.xlabel("Time (seconds)")
75 plt.ylabel("Usage %")
77 # GPU Usage Plot (Bottom Left)
78 plt.subplot(2, 1)
79 plt.theme('dark')
80 if GPU_AVAILABLE and any(self.gpu_history):
81 plt.plot(x_range, list(self.gpu_history), color='yellow')
82 plt.ylim(0, 100)
83 plt.title(f"GPU Usage: {current_gpu:.1f}%")
84 else:
85 plt.plot([0, 1], [0, 0], color='red')
86 plt.title("GPU: Not Available")
87 plt.xlabel("Time (seconds)")
88 plt.ylabel("Usage %")
90 # VRAM Usage Plot (Bottom Right)
91 plt.subplot(2, 2)
92 plt.theme('dark')
93 if GPU_AVAILABLE and any(self.vram_history):
94 plt.plot(x_range, list(self.vram_history), color='magenta')
95 plt.ylim(0, 100)
96 plt.title(f"VRAM Usage: {current_vram:.1f}%")
97 else:
98 plt.plot([0, 1], [0, 0], color='red')
99 plt.title("VRAM: Not Available")
100 plt.xlabel("Time (seconds)")
101 plt.ylabel("Usage %")
103 # Capture the plot output
104 old_stdout = sys.stdout
105 sys.stdout = buffer = io.StringIO()
107 try:
108 # Print title
109 print(self.get_ascii_title())
111 # Show plots
112 plt.show()
114 # Additional system info
115 print("\n" + "═" * 75)
116 print(f"System Information | Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
117 print("═" * 75)
118 print(f"CPU Cores: {psutil.cpu_count()} | CPU Frequency: {get_cpu_freq_mhz()} MHz")
119 print(f"Total RAM: {ram_total_gb:.1f} GB | Available RAM: {ram_info.available/(1024**3):.1f} GB")
121 if GPU_AVAILABLE:
122 try:
123 gpus = GPUtil.getGPUs()
124 if gpus:
125 gpu = gpus[0]
126 print(f"GPU: {gpu.name} | VRAM: {gpu.memoryUsed:.0f}/{gpu.memoryTotal:.0f} MB")
127 print(f"GPU Temperature: {gpu.temperature}°C")
128 except:
129 pass
131 # Disk usage
132 disk = psutil.disk_usage('/')
133 print(f"Disk Usage: {disk.used/(1024**3):.1f}/{disk.total/(1024**3):.1f} GB ({disk.percent}%)")
135 # Network info
136 net = psutil.net_io_counters()
137 print(f"Network - Sent: {net.bytes_sent/(1024**2):.1f} MB | Recv: {net.bytes_recv/(1024**2):.1f} MB")
138 print("═" * 75)
140 output = buffer.getvalue()
141 finally:
142 sys.stdout = old_stdout
144 return output
146 def get_metrics_dict(self):
147 """Get current metrics as a dictionary - uses cached data from update_metrics()"""
148 # Return cached metrics to avoid duplicate system calls
149 # If no cached data exists (first call), return defaults
150 if not self._current_metrics:
151 return {
152 'cpu_percent': 0,
153 'ram_percent': 0,
154 'ram_used_gb': 0,
155 'ram_total_gb': 0,
156 'cpu_cores': 0,
157 'cpu_freq_mhz': 0,
158 }
160 return self._current_metrics.copy()
163# Standalone CLI usage
164def main():
165 """Run system monitor in standalone mode"""
166 monitor = SystemMonitor()
168 print("Starting System Monitor...")
169 print("Press Ctrl+C to exit")
171 try:
172 while True:
173 monitor.update_metrics()
174 print("\033[2J\033[H") # Clear screen
175 print(monitor.create_monitor_view())
176 time.sleep(1)
177 except KeyboardInterrupt:
178 print("\nExiting System Monitor...")
181if __name__ == "__main__":
182 main()