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

1""" 

2System Monitor with Plotext Visualization 

3Real-time system monitoring with plotext visualization for Textual TUI. 

4 

5This module extends SystemMonitorCore with plotext-specific visualization. 

6""" 

7 

8import plotext as plt 

9import platform 

10import psutil 

11import time 

12from datetime import datetime 

13import io 

14import sys 

15 

16from openhcs.ui.shared.system_monitor_core import SystemMonitorCore, GPU_AVAILABLE, get_cpu_freq_mhz 

17 

18 

19class SystemMonitor(SystemMonitorCore): 

20 """System monitoring with plotext visualization (TUI-specific).""" 

21 

22 def __init__(self, history_length=60): 

23 """Initialize with plotext visualization support.""" 

24 super().__init__(history_length) 

25 

26 def get_ascii_title(self): 

27 """Return the OpenHCS ASCII art title""" 

28 return """ 

29╔═══════════════════════════════════════════════════════════════════════╗ 

30║ ██████╗ ██████╗ ███████╗███╗ ██╗██╗ ██╗ ██████╗███████╗ ║ 

31║ ██╔═══██╗██╔══██╗██╔════╝████╗ ██║██║ ██║██╔════╝██╔════╝ ║ 

32║ ██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║██║ ███████╗ ║ 

33║ ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║██║ ╚════██║ ║ 

34║ ╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║╚██████╗███████║ ║ 

35║ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝╚══════╝ ║ 

36╚═══════════════════════════════════════════════════════════════════════╝""" 

37 

38 def create_monitor_view(self, width=80, height=30): 

39 """Create the system monitor visualization""" 

40 plt.clear_figure() 

41 

42 # Create subplots 

43 plt.subplots(2, 2) 

44 plt.plot_size(width=width, height=height) 

45 

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 

51 

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) 

56 

57 x_range = list(range(len(self.cpu_history))) 

58 

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 %") 

67 

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 %") 

76 

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 %") 

89 

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 %") 

102 

103 # Capture the plot output 

104 old_stdout = sys.stdout 

105 sys.stdout = buffer = io.StringIO() 

106 

107 try: 

108 # Print title 

109 print(self.get_ascii_title()) 

110 

111 # Show plots 

112 plt.show() 

113 

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") 

120 

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 

130 

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}%)") 

134 

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) 

139 

140 output = buffer.getvalue() 

141 finally: 

142 sys.stdout = old_stdout 

143 

144 return output 

145 

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 } 

159 

160 return self._current_metrics.copy() 

161 

162 

163# Standalone CLI usage 

164def main(): 

165 """Run system monitor in standalone mode""" 

166 monitor = SystemMonitor() 

167 

168 print("Starting System Monitor...") 

169 print("Press Ctrl+C to exit") 

170 

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...") 

179 

180 

181if __name__ == "__main__": 

182 main()