guro 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
guro/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ # guro/__init__.py
2
+ __version__ = "1.0.0"
guro/cli/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # guro/cli/__init__.py
2
+ from .main import cli
3
+
4
+ __all__ = ['cli']
guro/cli/main.py ADDED
@@ -0,0 +1,161 @@
1
+ import click
2
+ from rich.console import Console
3
+ from rich.panel import Panel
4
+ from rich.table import Table
5
+ from rich.prompt import Prompt, Confirm
6
+ from rich import print as rprint
7
+ from typing import Optional
8
+ from ..core.monitor import SystemMonitor
9
+ from ..core.benchmark import SafeSystemBenchmark
10
+ from ..core.heatmap import SystemHeatmap
11
+
12
+ console = Console()
13
+
14
+ def print_banner():
15
+ """Display the Guro banner"""
16
+ banner = """
17
+ [bold cyan]
18
+ ██████╗ ██╗ ██╗██████╗ ██████╗
19
+ ██╔════╝ ██║ ██║██╔══██╗██╔═══██╗
20
+ ██║ ███╗██║ ██║██████╔╝██║ ██║
21
+ ██║ ██║██║ ██║██╔══██╗██║ ██║
22
+ ╚██████╔╝╚██████╔╝██║ ██║╚██████╔╝
23
+ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝
24
+ [/bold cyan]
25
+ [yellow]A Simple System Monitoring & Benchmarking Toolkit[/yellow]
26
+ """
27
+ console.print(banner)
28
+
29
+ @click.group()
30
+ @click.version_option(version='1.0.0')
31
+ def cli():
32
+ """🚀 Guro - A Simple System Monitoring & Benchmarking Toolkit"""
33
+ print_banner()
34
+
35
+ @cli.command()
36
+ @click.option('--interval', '-i', default=1.0, help='Monitoring interval in seconds')
37
+ @click.option('--duration', '-d', default=None, type=int, help='Monitoring duration in seconds')
38
+ @click.option('--export', '-e', is_flag=True, help='Export monitoring data to CSV')
39
+ def monitor(interval: float, duration: Optional[int], export: bool):
40
+ """📊 Monitor system resources and performance in real-time"""
41
+ try:
42
+ monitor = SystemMonitor()
43
+ if export:
44
+ click.echo("📝 Monitoring data will be exported to 'monitoring_data.csv'")
45
+
46
+ with console.status("[bold green]Initializing system monitor..."):
47
+ monitor.run_performance_test(
48
+ interval=interval,
49
+ duration=duration,
50
+ export_data=export
51
+ )
52
+ except KeyboardInterrupt:
53
+ console.print("\n[yellow]Monitoring stopped by user[/yellow]")
54
+ except Exception as e:
55
+ console.print(f"\n[red]Error during monitoring: {str(e)}[/red]")
56
+
57
+ @cli.command()
58
+ @click.option('--type', '-t', 'test_type',
59
+ type=click.Choice(['mini', 'god'], case_sensitive=False),
60
+ help='Type of benchmark test to run')
61
+ @click.option('--gpu-only', is_flag=True, help='Run only GPU benchmark')
62
+ @click.option('--cpu-only', is_flag=True, help='Run only CPU benchmark')
63
+ def benchmark(test_type: str, gpu_only: bool, cpu_only: bool):
64
+ """🔥 Run system benchmarks"""
65
+ try:
66
+ benchmark = SafeSystemBenchmark()
67
+
68
+ if not test_type:
69
+ test_type = Prompt.ask(
70
+ "Select benchmark type",
71
+ choices=["mini", "god"],
72
+ default="mini"
73
+ )
74
+
75
+ with console.status("[bold green]Preparing benchmark..."):
76
+ if test_type == "mini":
77
+ benchmark.mini_test(gpu_only=gpu_only, cpu_only=cpu_only)
78
+ else:
79
+ benchmark.god_test(gpu_only=gpu_only, cpu_only=cpu_only)
80
+
81
+ except KeyboardInterrupt:
82
+ console.print("\n[yellow]Benchmark stopped by user[/yellow]")
83
+ except Exception as e:
84
+ console.print(Panel(
85
+ f"[red]Error during benchmark: {str(e)}[/red]",
86
+ title="⚠️ Benchmark Error",
87
+ border_style="red"
88
+ ))
89
+
90
+ @cli.command() # Added the cli decorator here
91
+ @click.option('--interval', '-i',
92
+ type=click.FloatRange(min=0.1, min_open=False),
93
+ default=1.0,
94
+ help='Update interval in seconds (must be greater than 0.1)')
95
+ @click.option('--duration', '-d',
96
+ type=click.IntRange(min=1, min_open=False),
97
+ default=10,
98
+ help='Duration to run in seconds (default: 10)')
99
+ def heatmap(interval: float, duration: int):
100
+ """🌡️ Display unified system temperature heatmap"""
101
+ try:
102
+ heatmap = SystemHeatmap()
103
+
104
+ with console.status("[bold green]Initializing system heatmap..."):
105
+ updates = heatmap.run(
106
+ interval=interval,
107
+ duration=duration
108
+ )
109
+
110
+ console.print(f"\n[green]Heatmap completed after {updates} updates[/green]")
111
+
112
+ except KeyboardInterrupt:
113
+ console.print("\n[yellow]Heatmap visualization stopped by user[/yellow]")
114
+ except Exception as e:
115
+ console.print(f"[red]Error during heatmap visualization: {str(e)}[/red]")
116
+
117
+ @cli.command(name='list')
118
+ def list_features():
119
+ """📋 List all available features and commands"""
120
+ table = Table(title="Guro Commands and Features")
121
+ table.add_column("Command", style="cyan")
122
+ table.add_column("Description", style="green")
123
+ table.add_column("Options", style="yellow")
124
+
125
+ commands = {
126
+ "monitor": ("📊 Real-time system monitoring", "-i/--interval, -d/--duration, -e/--export"),
127
+ "benchmark": ("🔥 System benchmarking", "-t/--type [mini/god], --gpu-only, --cpu-only"),
128
+ "heatmap": ("🌡️ Hardware Heatmap Analysis", "-i/--interval, -d/--duration"),
129
+ "about": ("ℹ️ About Guro", "None"),
130
+ "list": ("📋 List all commands", "None")
131
+ }
132
+
133
+ for cmd, (desc, opts) in commands.items():
134
+ table.add_row(cmd, desc, opts)
135
+
136
+ console.print(table)
137
+
138
+ @cli.command(name='about')
139
+ def about():
140
+ """ℹ️ Display information about Guro"""
141
+ about_text = """[bold cyan]Guro - A Simple System Monitoring & Benchmarking Toolkit[/bold cyan]
142
+
143
+ [green]Version:[/green] 1.0.0
144
+ [green]Author:[/green] Dhanush Kandhan
145
+ [green]License:[/green] MIT
146
+
147
+ 🛠️ A Simple powerful toolkit for system monitoring and benchmarking.
148
+
149
+ [yellow]Key Features:[/yellow]
150
+ • 📊 Real-time system monitoring
151
+ • 💾 Memory management
152
+ • 🔥 Performance benchmarking
153
+ • 🌡️ Hardware Heatmap Analysis
154
+
155
+ [blue]GitHub:[/blue] https://github.com/dhanushk-offl/guro
156
+ [blue]Documentation:[/blue] https://github.com/dhanushk-offl/guro/wiki"""
157
+
158
+ console.print(Panel(about_text, title="About Guro", border_style="blue"))
159
+
160
+ if __name__ == '__main__':
161
+ cli()
guro/core/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ # guro/core/__init__.py
2
+ from .monitor import SystemMonitor
3
+ __all__ = ['SystemMonitor']
guro/core/benchmark.py ADDED
@@ -0,0 +1,317 @@
1
+ import psutil
2
+ import time
3
+ import numpy as np
4
+ import multiprocessing
5
+ from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn, BarColumn
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.live import Live
9
+ from rich.table import Table
10
+ import subprocess
11
+ import platform
12
+ from threading import Thread
13
+ import signal
14
+ import sys
15
+
16
+ try:
17
+ import GPUtil
18
+ HAS_GPU_STATS = True
19
+ except ImportError:
20
+ HAS_GPU_STATS = False
21
+
22
+ class SafeSystemBenchmark:
23
+ def __init__(self):
24
+ self.console = Console()
25
+ self.results = {}
26
+ self.running = False
27
+ self.baseline_scores = {
28
+ 'cpu_single': 2.5,
29
+ 'cpu_multi': 1.0,
30
+ 'gpu_compute': 1.5
31
+ }
32
+ # Safety thresholds
33
+ self.MAX_CPU_USAGE = 80 # Maximum CPU usage percentage
34
+ self.MAX_MEMORY_USAGE = 80 # Maximum memory usage percentage
35
+ self.has_gpu = self._check_gpu()
36
+
37
+ def _check_gpu(self):
38
+ """Check if GPU is available and get GPU information"""
39
+ gpu_info = {'available': False, 'info': None}
40
+
41
+ if HAS_GPU_STATS:
42
+ try:
43
+ gpus = GPUtil.getGPUs()
44
+ if gpus and len(gpus) > 0:
45
+ gpu = gpus[0] # Get first GPU info
46
+ gpu_info['available'] = True
47
+ gpu_info['info'] = {
48
+ 'name': gpu.name,
49
+ 'count': len(gpus),
50
+ 'memory_total': gpu.memoryTotal,
51
+ 'driver_version': gpu.driver
52
+ }
53
+ except Exception:
54
+ pass
55
+ return gpu_info
56
+
57
+ def get_system_info(self):
58
+ """Get basic system information safely"""
59
+ info = {
60
+ 'system': platform.system(),
61
+ 'processor': platform.processor(),
62
+ 'memory_total': psutil.virtual_memory().total,
63
+ 'cpu_cores': psutil.cpu_count(logical=False),
64
+ 'cpu_threads': psutil.cpu_count(logical=True),
65
+ 'gpu': self.has_gpu
66
+ }
67
+ return info
68
+
69
+ def safe_gpu_test(self, duration):
70
+ """Safe GPU benchmark with controlled load"""
71
+ if not self.has_gpu['available']:
72
+ return {'times': [], 'loads': [], 'error': 'No GPU available'}
73
+
74
+ result = {'times': [], 'loads': [], 'memory_usage': []}
75
+ start_time = time.time()
76
+
77
+ try:
78
+ while time.time() - start_time < duration and self.running:
79
+ if HAS_GPU_STATS:
80
+ gpus = GPUtil.getGPUs()
81
+ if gpus and len(gpus) > 0:
82
+ gpu = gpus[0]
83
+ gpu_load = gpu.load * 100
84
+ gpu_memory = gpu.memoryUsed
85
+
86
+ result['times'].append(time.time() - start_time)
87
+ result['loads'].append(gpu_load)
88
+ result['memory_usage'].append(gpu_memory)
89
+
90
+ time.sleep(0.1)
91
+
92
+ except Exception as e:
93
+ result['error'] = str(e)
94
+
95
+ return result
96
+
97
+ def monitor_resources(self):
98
+ """Monitor system resources in real-time"""
99
+ while self.running:
100
+ cpu_percent = psutil.cpu_percent()
101
+ memory_percent = psutil.virtual_memory().percent
102
+
103
+ # Safety check
104
+ if cpu_percent > self.MAX_CPU_USAGE or memory_percent > self.MAX_MEMORY_USAGE:
105
+ self.running = False
106
+ self.console.print("[red]Warning: System resource usage too high. Stopping benchmark.[/red]")
107
+ break
108
+
109
+ time.sleep(0.5)
110
+
111
+ def safe_cpu_test(self, duration):
112
+ """Safe CPU benchmark with controlled load"""
113
+ start_time = time.time()
114
+ result = {'times': [], 'loads': []}
115
+
116
+ while time.time() - start_time < duration and self.running:
117
+ # Matrix operations with controlled size
118
+ size = 100
119
+ matrix = np.random.rand(size, size)
120
+ np.dot(matrix, matrix.T)
121
+
122
+ result['times'].append(time.time() - start_time)
123
+ result['loads'].append(psutil.cpu_percent())
124
+ time.sleep(0.1)
125
+
126
+ return result
127
+
128
+ def safe_memory_test(self, duration):
129
+ """Safe memory benchmark"""
130
+ start_time = time.time()
131
+ result = {'times': [], 'usage': []}
132
+
133
+ while time.time() - start_time < duration and self.running:
134
+ memory = psutil.virtual_memory()
135
+ result['times'].append(time.time() - start_time)
136
+ result['usage'].append(memory.percent)
137
+ time.sleep(0.1)
138
+
139
+ return result
140
+
141
+ def mini_test(self, gpu_only=False, cpu_only=False):
142
+ """Run 30-second mini benchmark"""
143
+ self.running = True
144
+ duration = 30
145
+
146
+ # Start resource monitoring
147
+ monitor_thread = Thread(target=self.monitor_resources)
148
+ monitor_thread.start()
149
+
150
+ with Live(self.generate_status_table(), refresh_per_second=4) as live:
151
+ self.results = {
152
+ 'system_info': self.get_system_info(),
153
+ 'duration': duration
154
+ }
155
+
156
+ if not gpu_only:
157
+ # CPU Test
158
+ self.results['cpu'] = self.safe_cpu_test(duration/2)
159
+ # Memory Test
160
+ self.results['memory'] = self.safe_memory_test(duration/2)
161
+
162
+ if not cpu_only and self.has_gpu['available']:
163
+ # GPU Test
164
+ self.results['gpu'] = self.safe_gpu_test(duration/2)
165
+
166
+ live.update(self.generate_status_table())
167
+
168
+ self.running = False
169
+ monitor_thread.join()
170
+ self.display_results("Mini-Test")
171
+
172
+ def god_test(self, gpu_only=False, cpu_only=False):
173
+ """Running GOD - LEVEL comprehensive benchmark"""
174
+ self.running = True
175
+ duration = 60
176
+
177
+ # Start resource monitoring
178
+ monitor_thread = Thread(target=self.monitor_resources)
179
+ monitor_thread.start()
180
+
181
+ with Live(self.generate_status_table(), refresh_per_second=4) as live:
182
+ self.results = {
183
+ 'system_info': self.get_system_info(),
184
+ 'duration': duration
185
+ }
186
+
187
+ if not gpu_only:
188
+ # Extended CPU Test
189
+ self.results['cpu'] = self.safe_cpu_test(duration/2)
190
+ # Extended Memory Test
191
+ self.results['memory'] = self.safe_memory_test(duration/2)
192
+
193
+ if not cpu_only and self.has_gpu['available']:
194
+ # Extended GPU Test
195
+ self.results['gpu'] = self.safe_gpu_test(duration/2)
196
+
197
+ live.update(self.generate_status_table())
198
+
199
+ self.running = False
200
+ monitor_thread.join()
201
+ self.display_results("God-Test")
202
+
203
+ def generate_status_table(self):
204
+ """Generate real-time status table"""
205
+ table = Table(title="Benchmark Status")
206
+ table.add_column("Metric")
207
+ table.add_column("Value")
208
+
209
+ cpu_percent = psutil.cpu_percent()
210
+ memory_percent = psutil.virtual_memory().percent
211
+
212
+ table.add_row("CPU Usage", f"{cpu_percent}%")
213
+ table.add_row("Memory Usage", f"{memory_percent}%")
214
+
215
+ if self.has_gpu['available'] and HAS_GPU_STATS:
216
+ gpus = GPUtil.getGPUs()
217
+ if gpus and len(gpus) > 0:
218
+ gpu = gpus[0]
219
+ table.add_row("GPU", f"[green]{gpu.name}[/green]")
220
+ table.add_row("GPU Usage", f"{gpu.load * 100}%")
221
+ table.add_row("GPU Memory", f"{gpu.memoryUsed} MB / {gpu.memoryTotal} MB")
222
+
223
+ table.add_row("Status", "[green]Running[/green]" if self.running else "[red]Stopped[/red]")
224
+
225
+ return table
226
+
227
+ def display_results(self, test_type):
228
+ """Display benchmark results"""
229
+ if not self.results:
230
+ return
231
+
232
+ result_text = f"[bold cyan]{test_type} Results[/bold cyan]\n\n"
233
+
234
+ # System Information
235
+ result_text += "[green]System Information:[/green]\n"
236
+ sys_info = self.results.get('system_info', {})
237
+ result_text += f"• System: {sys_info.get('system', 'N/A')}\n"
238
+ result_text += f"• Processor: {sys_info.get('processor', 'N/A')}\n"
239
+ result_text += f"• CPU Cores: {sys_info.get('cpu_cores', 'N/A')}\n"
240
+ result_text += f"• CPU Threads: {sys_info.get('cpu_threads', 'N/A')}\n"
241
+
242
+ # GPU Information
243
+ gpu_info = sys_info.get('gpu', {})
244
+ if gpu_info.get('available', False):
245
+ gpu_details = gpu_info.get('info', {})
246
+ result_text += f"• GPU: {gpu_details.get('name', 'N/A')}\n"
247
+ result_text += f"• GPU Count: {gpu_details.get('count', 'N/A')}\n"
248
+ result_text += f"• GPU Memory: {gpu_details.get('memory_total', 'N/A')} MB\n"
249
+ result_text += f"• Driver Version: {gpu_details.get('driver_version', 'N/A')}\n"
250
+ else:
251
+ result_text += "• GPU: Not Available\n"
252
+
253
+ result_text += "\n[green]Performance Results:[/green]\n"
254
+
255
+ # CPU Results
256
+ if 'cpu' in self.results:
257
+ cpu_loads = self.results['cpu'].get('loads', [])
258
+ if cpu_loads:
259
+ result_text += f"• Average CPU Load: {np.mean(cpu_loads):.2f}%\n"
260
+ result_text += f"• Peak CPU Load: {max(cpu_loads):.2f}%\n"
261
+
262
+ # Memory Results
263
+ if 'memory' in self.results:
264
+ memory_usage = self.results['memory'].get('usage', [])
265
+ if memory_usage:
266
+ result_text += f"• Average Memory Usage: {np.mean(memory_usage):.2f}%\n"
267
+ result_text += f"• Peak Memory Usage: {max(memory_usage):.2f}%\n"
268
+
269
+ # GPU Results
270
+ if 'gpu' in self.results and 'error' not in self.results['gpu']:
271
+ gpu_loads = self.results['gpu'].get('loads', [])
272
+ if gpu_loads:
273
+ result_text += f"• Average GPU Load: {np.mean(gpu_loads):.2f}%\n"
274
+ result_text += f"• Peak GPU Load: {max(gpu_loads):.2f}%\n"
275
+ if 'memory_usage' in self.results['gpu']:
276
+ gpu_mem_usage = self.results['gpu'].get('memory_usage', [])
277
+ if gpu_mem_usage:
278
+ result_text += f"• Average GPU Memory Usage: {np.mean(gpu_mem_usage):.2f} MB\n"
279
+ result_text += f"• Peak GPU Memory Usage: {max(gpu_mem_usage):.2f} MB\n"
280
+
281
+ result_text += f"• Test Duration: {self.results.get('duration', 'N/A')} seconds\n"
282
+
283
+ self.console.print(Panel(
284
+ result_text,
285
+ title=f"System Benchmark Report - {test_type}",
286
+ border_style="blue"
287
+ ))
288
+
289
+ def main():
290
+ benchmark = SafeSystemBenchmark()
291
+
292
+ # Handle Ctrl+C gracefully
293
+ def signal_handler(sig, frame):
294
+ benchmark.running = False
295
+ print("\nBenchmark stopped by user.")
296
+ sys.exit(0)
297
+
298
+ signal.signal(signal.SIGINT, signal_handler)
299
+
300
+ # Test selection
301
+ console = Console()
302
+ console.print("\n[cyan]Select Benchmark Type:[/cyan]")
303
+ console.print("1. Mini-Test (30 seconds)")
304
+ console.print("2. God-Test (120 seconds)")
305
+
306
+ choice = input("\nEnter your choice (1 or 2): ")
307
+
308
+ if choice == "1":
309
+ benchmark.mini_test()
310
+ elif choice == "2":
311
+ benchmark.god_test()
312
+ else:
313
+ console.print("[red]Invalid choice. Exiting.[/red]")
314
+
315
+ if __name__ == "__main__":
316
+ main()
317
+
guro/core/heatmap.py ADDED
@@ -0,0 +1,349 @@
1
+ import time
2
+ import psutil
3
+ import platform
4
+ import numpy as np
5
+ from typing import List, Optional, Dict
6
+ from rich.live import Live
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.text import Text
10
+ import subprocess
11
+ from pathlib import Path
12
+ import ctypes
13
+ from ctypes import Structure
14
+ import os
15
+
16
+ # Import platform-specific modules
17
+ if platform.system() == "Windows":
18
+ from ctypes import windll, wintypes, byref, POINTER
19
+
20
+ class SYSTEM_POWER_STATUS(Structure):
21
+ _fields_ = [
22
+ ('ACLineStatus', wintypes.BYTE),
23
+ ('BatteryFlag', wintypes.BYTE),
24
+ ('BatteryLifePercent', wintypes.BYTE),
25
+ ('SystemStatusFlag', wintypes.BYTE),
26
+ ('BatteryLifeTime', wintypes.DWORD),
27
+ ('BatteryFullLifeTime', wintypes.DWORD),
28
+ ]
29
+
30
+ class PROCESSOR_POWER_INFORMATION(Structure):
31
+ _fields_ = [
32
+ ("CurrentFrequency", wintypes.ULONG),
33
+ ("MaxMhz", wintypes.ULONG),
34
+ ("CurrentMhz", wintypes.ULONG),
35
+ ("MhzLimit", wintypes.ULONG),
36
+ ("MaxIdleState", wintypes.ULONG),
37
+ ("CurrentIdleState", wintypes.ULONG),
38
+ ]
39
+
40
+ class SystemHeatmap:
41
+ def __init__(self):
42
+ self.console = Console()
43
+ self.history_size = 60
44
+ self.system = platform.system()
45
+ self.components = {
46
+ 'CPU': {'position': (2, 5), 'size': (8, 15)},
47
+ 'GPU': {'position': (12, 5), 'size': (8, 15)},
48
+ 'Motherboard': {'position': (0, 0), 'size': (25, 40)},
49
+ 'RAM': {'position': (2, 25), 'size': (4, 10)},
50
+ 'Storage': {'position': (18, 25), 'size': (4, 10)}
51
+ }
52
+ self.initialize_temp_maps()
53
+ if self.system == "Windows":
54
+ self.setup_windows_api()
55
+
56
+ def setup_windows_api(self):
57
+ if platform.system() == "Windows":
58
+ self.GetSystemPowerStatus = windll.kernel32.GetSystemPowerStatus
59
+ self.GetSystemPowerStatus.argtypes = [POINTER(SYSTEM_POWER_STATUS)]
60
+ self.GetSystemPowerStatus.restype = wintypes.BOOL
61
+ self.NtQuerySystemInformation = windll.ntdll.NtQuerySystemInformation
62
+ self.CallNtPowerInformation = windll.powrprof.CallNtPowerInformation
63
+
64
+ def initialize_temp_maps(self):
65
+ self.temp_maps = {
66
+ component: np.zeros(dims['size'])
67
+ for component, dims in self.components.items()
68
+ }
69
+
70
+ def get_windows_temps(self) -> Dict[str, float]:
71
+ if platform.system() != "Windows":
72
+ return self.get_fallback_temps()
73
+
74
+ return {
75
+ 'CPU': self.get_windows_cpu_temp(),
76
+ 'GPU': self.get_windows_gpu_temp(),
77
+ 'Motherboard': self.get_windows_motherboard_temp(),
78
+ 'Storage': self.get_windows_storage_temp(),
79
+ 'RAM': self.get_windows_ram_temp()
80
+ }
81
+
82
+ def get_windows_cpu_temp(self) -> float:
83
+ if platform.system() != "Windows":
84
+ return self.get_cpu_load_temp()
85
+
86
+ try:
87
+ buffer_size = ctypes.sizeof(PROCESSOR_POWER_INFORMATION)
88
+ buffer = ctypes.create_string_buffer(buffer_size)
89
+ if self.CallNtPowerInformation(11, None, 0, buffer, buffer_size) == 0:
90
+ info = PROCESSOR_POWER_INFORMATION.from_buffer_copy(buffer)
91
+ return float(40 + (info.CurrentMhz / max(info.MaxMhz, 1)) * 40) # Fixed division by zero
92
+ return self.get_cpu_load_temp()
93
+ except:
94
+ return self.get_cpu_load_temp()
95
+
96
+ def get_windows_gpu_temp(self) -> float:
97
+ if platform.system() != "Windows":
98
+ return self.get_gpu_load_temp()
99
+
100
+ try:
101
+ if hasattr(windll, 'd3d11'):
102
+ device = ctypes.c_void_p()
103
+ if windll.d3d11.D3D11CreateDevice(None, 0, None, 0, None, 0, 0,
104
+ ctypes.byref(device), None, None) == 0:
105
+ return self.get_gpu_load_temp()
106
+ return self.get_gpu_load_temp()
107
+ except:
108
+ return self.get_gpu_load_temp()
109
+
110
+ def get_windows_motherboard_temp(self) -> float:
111
+ if platform.system() != "Windows":
112
+ return 45.0
113
+
114
+ try:
115
+ status = SYSTEM_POWER_STATUS()
116
+ if self.GetSystemPowerStatus(byref(status)):
117
+ return float(35 + (status.BatteryLifePercent / 100) * 15) # Fixed type conversion
118
+ return 45.0
119
+ except:
120
+ return 45.0
121
+
122
+ def get_windows_storage_temp(self) -> float:
123
+ if platform.system() != "Windows":
124
+ return 35.0
125
+
126
+ try:
127
+ if hasattr(windll, 'kernel32'):
128
+ hDevice = windll.kernel32.CreateFileW(
129
+ "\\\\.\\PhysicalDrive0",
130
+ 0x80000000,
131
+ 0x3,
132
+ None,
133
+ 3,
134
+ 0,
135
+ None
136
+ )
137
+ if hDevice != -1:
138
+ return self.get_disk_load_temp()
139
+ return 35.0
140
+ except:
141
+ return 35.0
142
+
143
+ def get_windows_ram_temp(self) -> float:
144
+ return float(psutil.virtual_memory().percent / 2) # Fixed type conversion
145
+
146
+ def get_linux_temps(self) -> Dict[str, float]:
147
+ temps = {
148
+ 'CPU': 0.0,
149
+ 'GPU': 0.0,
150
+ 'Motherboard': 0.0,
151
+ 'Storage': 0.0,
152
+ 'RAM': 0.0
153
+ }
154
+
155
+ try:
156
+ # CPU Temperature
157
+ cpu_temps = psutil.sensors_temperatures()
158
+ if 'coretemp' in cpu_temps:
159
+ temps['CPU'] = float(max(temp.current for temp in cpu_temps['coretemp']))
160
+
161
+ # GPU Temperature
162
+ try:
163
+ nvidia_output = subprocess.check_output(
164
+ ["nvidia-smi", "--query-gpu=temperature.gpu", "--format=csv,noheader"],
165
+ stderr=subprocess.DEVNULL
166
+ ).decode()
167
+ temps['GPU'] = float(nvidia_output.strip())
168
+ except:
169
+ try:
170
+ for card in Path('/sys/class/drm').glob('card?'):
171
+ temp_file = next(card.glob('device/hwmon/hwmon*/temp1_input'))
172
+ with open(temp_file) as f:
173
+ temps['GPU'] = float(f.read().strip()) / 1000
174
+ break
175
+ except:
176
+ temps['GPU'] = self.get_gpu_load_temp()
177
+
178
+ # Motherboard Temperature
179
+ if 'acpitz' in cpu_temps:
180
+ temps['Motherboard'] = float(cpu_temps['acpitz'][0].current)
181
+
182
+ # Storage Temperature
183
+ try:
184
+ output = subprocess.check_output(['smartctl', '-A', '/dev/sda']).decode()
185
+ for line in output.split('\n'):
186
+ if 'Temperature' in line:
187
+ temps['Storage'] = float(line.split()[9])
188
+ break
189
+ except:
190
+ temps['Storage'] = self.get_disk_load_temp()
191
+
192
+ temps['RAM'] = float(psutil.virtual_memory().percent / 2)
193
+
194
+ return temps
195
+ except:
196
+ return self.get_fallback_temps()
197
+
198
+ def get_macos_temps(self) -> Dict[str, float]:
199
+ temps = self.get_fallback_temps() # Start with fallback temperatures
200
+
201
+ try:
202
+ # SMC temperature readings
203
+ output = subprocess.check_output(
204
+ ['sudo', 'powermetrics', '-n', '1'],
205
+ stderr=subprocess.DEVNULL
206
+ ).decode()
207
+
208
+ for line in output.split('\n'):
209
+ if 'CPU die temperature' in line:
210
+ temps['CPU'] = float(line.split(':')[1].split()[0])
211
+ elif 'GPU die temperature' in line:
212
+ temps['GPU'] = float(line.split(':')[1].split()[0])
213
+
214
+ temps['Motherboard'] = float(temps['CPU'] * 0.8)
215
+ temps['RAM'] = float(psutil.virtual_memory().percent / 2)
216
+
217
+ try:
218
+ output = subprocess.check_output(['smartctl', '-A', '/dev/disk0']).decode()
219
+ for line in output.split('\n'):
220
+ if 'Temperature' in line:
221
+ temps['Storage'] = float(line.split()[9])
222
+ break
223
+ except:
224
+ temps['Storage'] = self.get_disk_load_temp()
225
+
226
+ return temps
227
+ except:
228
+ return temps # Return the fallback temps if anything fails
229
+
230
+ def get_cpu_load_temp(self) -> float:
231
+ return float(40 + (psutil.cpu_percent() * 0.6))
232
+
233
+ def get_gpu_load_temp(self) -> float:
234
+ return float(35 + (psutil.cpu_percent() * 0.5))
235
+
236
+ def get_disk_load_temp(self) -> float:
237
+ disk_io = psutil.disk_io_counters()
238
+ if disk_io:
239
+ return float(30 + (disk_io.read_bytes + disk_io.write_bytes) / (1024 * 1024 * 1024))
240
+ return 30.0
241
+
242
+ def get_fallback_temps(self) -> Dict[str, float]:
243
+ cpu_percent = float(psutil.cpu_percent())
244
+ memory_percent = float(psutil.virtual_memory().percent)
245
+ return {
246
+ 'CPU': float(40 + (cpu_percent * 0.4)),
247
+ 'GPU': float(35 + (cpu_percent * 0.3)),
248
+ 'Motherboard': float(35 + (cpu_percent * 0.2)),
249
+ 'Storage': float(30 + (cpu_percent * 0.1)),
250
+ 'RAM': float(30 + (memory_percent * 0.2))
251
+ }
252
+
253
+ def get_system_temps(self) -> Dict[str, float]:
254
+ if self.system == "Windows":
255
+ return self.get_windows_temps()
256
+ elif self.system == "Linux":
257
+ return self.get_linux_temps()
258
+ elif self.system == "Darwin":
259
+ return self.get_macos_temps()
260
+ return self.get_fallback_temps()
261
+
262
+ def get_temp_char(self, temp: float) -> tuple:
263
+ if temp < 45:
264
+ return ('·', "green")
265
+ elif temp < 70:
266
+ return ('▒', "yellow")
267
+ else:
268
+ return ('█', "red")
269
+
270
+ def update_component_map(self, component: str, temp: float):
271
+ rows, cols = self.components[component]['size']
272
+ base_temp = float(temp) # Ensure temp is float
273
+ noise = np.random.normal(0, 2, (rows, cols))
274
+ self.temp_maps[component] = np.clip(base_temp + noise, 0, 100)
275
+
276
+ def generate_system_layout(self) -> Panel:
277
+ layout = [[' ' for _ in range(40)] for _ in range(25)]
278
+ colors = [[None for _ in range(40)] for _ in range(25)]
279
+ temps = self.get_system_temps()
280
+
281
+ for component, info in self.components.items():
282
+ pos_x, pos_y = info['position']
283
+ size_x, size_y = info['size']
284
+
285
+ self.update_component_map(component, temps[component])
286
+
287
+ for i in range(size_x):
288
+ for j in range(size_y):
289
+ temp = float(self.temp_maps[component][i, j]) # Ensure float conversion
290
+ char, color = self.get_temp_char(temp)
291
+ layout[pos_x + i][pos_y + j] = char
292
+ colors[pos_x + i][pos_y + j] = color
293
+
294
+ label_x = pos_x + size_x // 2
295
+ label_y = pos_y + size_y // 2
296
+ label = f"{component[:3]} {temps[component]:.1f}°C"
297
+ for idx, char in enumerate(label):
298
+ if 0 <= label_y + idx < len(layout[0]):
299
+ layout[label_x][label_y + idx] = char
300
+ colors[label_x][label_y + idx] = "white"
301
+
302
+ text = Text()
303
+ for row in range(len(layout)):
304
+ for col in range(len(layout[0])):
305
+ text.append(layout[row][col], style=colors[row][col])
306
+ text.append("\n")
307
+
308
+ return Panel(
309
+ text,
310
+ title=f"System Temperature Heatmap ({self.system})",
311
+ border_style="blue"
312
+ )
313
+
314
+ def run(self, interval: float = 1.0, duration: Optional[int] = None) -> int:
315
+ """
316
+ Run the system heatmap visualization.
317
+
318
+ Args:
319
+ interval (float): Update interval in seconds
320
+ duration (Optional[int]): Total duration to run in seconds
321
+
322
+ Returns:
323
+ int: Number of updates performed
324
+
325
+ Raises:
326
+ ValueError: If duration is negative or interval is zero/negative
327
+ """
328
+ if duration is not None and duration <= 0:
329
+ raise ValueError("Duration must be positive")
330
+ if interval <= 0:
331
+ raise ValueError("Interval must be positive")
332
+
333
+ start_time = time.time()
334
+ update_count = 0
335
+
336
+ with Live(self.generate_system_layout(), refresh_per_second=1) as live:
337
+ try:
338
+ while True:
339
+ live.update(self.generate_system_layout())
340
+ update_count += 1
341
+
342
+ if duration and (time.time() - start_time) >= duration:
343
+ break
344
+
345
+ time.sleep(interval)
346
+ except KeyboardInterrupt:
347
+ pass
348
+
349
+ return update_count
guro/core/monitor.py ADDED
@@ -0,0 +1,303 @@
1
+ import psutil
2
+ import platform
3
+ import datetime
4
+ from rich.console import Console
5
+ from rich.table import Table
6
+ from rich.panel import Panel
7
+ from rich.layout import Layout
8
+ import os
9
+ import time
10
+ from collections import deque
11
+ import threading
12
+ import subprocess
13
+ from typing import Dict, List, Optional
14
+ import shutil
15
+ from rich import box
16
+ # import click
17
+ import csv
18
+
19
+ class GPUDetector:
20
+ @staticmethod
21
+ def get_nvidia_info():
22
+ try:
23
+ nvidia_smi = "nvidia-smi"
24
+ output = subprocess.check_output([nvidia_smi, "--query-gpu=gpu_name,memory.total,memory.used,memory.free,temperature.gpu,utilization.gpu,fan.speed,power.draw", "--format=csv,noheader,nounits"],
25
+ universal_newlines=True)
26
+ lines = output.strip().split('\n')
27
+ gpus = []
28
+ for line in lines:
29
+ name, total, used, free, temp, util, fan, power = line.split(',')
30
+ gpus.append({
31
+ 'name': name.strip(),
32
+ 'memory_total': float(total) * 1024**2,
33
+ 'memory_used': float(used) * 1024**2,
34
+ 'memory_free': float(free) * 1024**2,
35
+ 'temperature': float(temp),
36
+ 'utilization': float(util),
37
+ 'fan_speed': float(fan) if fan.strip() != '[N/A]' else None,
38
+ 'power_draw': float(power) if power.strip() != '[N/A]' else None,
39
+ 'type': 'NVIDIA'
40
+ })
41
+ return gpus
42
+ except:
43
+ return []
44
+
45
+ @staticmethod
46
+ def get_amd_info():
47
+ try:
48
+ rocm_smi = "rocm-smi"
49
+ output = subprocess.check_output([rocm_smi, "--showuse", "--showmeminfo", "--showtemp"],
50
+ universal_newlines=True)
51
+ gpus = []
52
+ lines = output.strip().split('\n')
53
+ current_gpu = {}
54
+ for line in lines:
55
+ if 'GPU' in line and 'Card' in line:
56
+ if current_gpu:
57
+ gpus.append(current_gpu)
58
+ current_gpu = {'type': 'AMD'}
59
+ if 'GPU Memory Use' in line:
60
+ try:
61
+ used = float(line.split(':')[1].strip().split()[0]) * 1024**2
62
+ current_gpu['memory_used'] = used
63
+ except:
64
+ pass
65
+ if 'Total GPU Memory' in line:
66
+ try:
67
+ total = float(line.split(':')[1].strip().split()[0]) * 1024**2
68
+ current_gpu['memory_total'] = total
69
+ current_gpu['memory_free'] = total - current_gpu.get('memory_used', 0)
70
+ except:
71
+ pass
72
+ if 'Temperature' in line:
73
+ try:
74
+ temp = float(line.split(':')[1].strip().split()[0])
75
+ current_gpu['temperature'] = temp
76
+ except:
77
+ pass
78
+ if current_gpu:
79
+ gpus.append(current_gpu)
80
+ return gpus
81
+ except:
82
+ return []
83
+
84
+ @staticmethod
85
+ def get_all_gpus():
86
+ gpu_info = {
87
+ 'available': False,
88
+ 'gpus': []
89
+ }
90
+
91
+ nvidia_gpus = GPUDetector.get_nvidia_info()
92
+ amd_gpus = GPUDetector.get_amd_info()
93
+
94
+ all_gpus = nvidia_gpus + amd_gpus
95
+
96
+ if all_gpus:
97
+ gpu_info['available'] = True
98
+ gpu_info['gpus'] = all_gpus
99
+
100
+ return gpu_info
101
+
102
+ class ASCIIGraph:
103
+ def __init__(self, width=70, height=10):
104
+ self.width = width
105
+ self.height = height
106
+ self.data = deque(maxlen=width)
107
+ self.chars = ' ▁▂▃▄▅▆▇█'
108
+
109
+ def add_point(self, value):
110
+ self.data.append(value)
111
+
112
+ def render(self, title=""):
113
+ if not self.data:
114
+ return ""
115
+
116
+ # Normalize data
117
+ max_val = max(self.data)
118
+ if max_val == 0:
119
+ normalized = [0] * len(self.data)
120
+ else:
121
+ normalized = [min(int((val / max_val) * (len(self.chars) - 1)), len(self.chars) - 1)
122
+ for val in self.data]
123
+
124
+ # Generate graph
125
+ lines = []
126
+ lines.append("╔" + "═" * (self.width + 2) + "╗")
127
+ lines.append("║ " + title.center(self.width) + " ║")
128
+ lines.append("║ " + "─" * self.width + " ║")
129
+
130
+ graph_str = ""
131
+ for val in normalized:
132
+ graph_str += self.chars[val]
133
+ lines.append("║ " + graph_str.ljust(self.width) + " ║")
134
+
135
+ lines.append("╚" + "═" * (self.width + 2) + "╝")
136
+ return "\n".join(lines)
137
+
138
+ class SystemMonitor:
139
+ def __init__(self):
140
+ self.console = Console()
141
+ self.cpu_graph = ASCIIGraph()
142
+ self.memory_graph = ASCIIGraph()
143
+ self.monitoring_data = []
144
+
145
+ def _get_cpu_temperature(self):
146
+ if platform.system() == 'Linux':
147
+ try:
148
+ temp_file = '/sys/class/thermal/thermal_zone0/temp'
149
+ if os.path.exists(temp_file):
150
+ with open(temp_file, 'r') as f:
151
+ return float(f.read()) / 1000.0
152
+ except:
153
+ pass
154
+ return None
155
+
156
+ def get_system_info(self):
157
+ cpu_freq = psutil.cpu_freq()
158
+ memory = psutil.virtual_memory()
159
+
160
+ system_info = {
161
+ 'os': f"{platform.system()} {platform.release()}",
162
+ 'cpu_model': platform.processor(),
163
+ 'cpu_cores': psutil.cpu_count(),
164
+ 'cpu_threads': psutil.cpu_count(logical=True),
165
+ 'cpu_freq': f"{cpu_freq.current:.2f}MHz" if cpu_freq else "N/A",
166
+ 'memory_total': f"{memory.total / (1024**3):.2f}GB",
167
+ 'memory_available': f"{memory.available / (1024**3):.2f}GB",
168
+ }
169
+
170
+ temp = self._get_cpu_temperature()
171
+ if temp:
172
+ system_info['cpu_temp'] = f"{temp:.1f}°C"
173
+
174
+ return system_info
175
+
176
+ def export_monitoring_data(self):
177
+ if not self.monitoring_data:
178
+ return
179
+
180
+ with open('monitoring_data.csv', 'w', newline='') as csvfile:
181
+ fieldnames = ['timestamp', 'cpu_usage', 'memory_usage']
182
+ writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
183
+
184
+ writer.writeheader()
185
+ for data in self.monitoring_data:
186
+ writer.writerow(data)
187
+
188
+ def run_performance_test(self, interval: float = 1.0, duration: Optional[int] = 30, export_data: bool = False):
189
+ self.console.clear()
190
+ self.console.print(Panel.fit(
191
+ "[bold cyan]Welcome to System Performance Monitor[/bold cyan]\n" +
192
+ f"[yellow]Running performance test for {duration if duration else 'unlimited'} seconds...[/yellow]",
193
+ box=box.DOUBLE
194
+ ))
195
+
196
+ # System Information
197
+ sys_info = self.get_system_info()
198
+ sys_table = Table(title="System Information", box=box.HEAVY)
199
+ sys_table.add_column("Component", style="cyan")
200
+ sys_table.add_column("Details", style="green")
201
+
202
+ for key, value in sys_info.items():
203
+ sys_table.add_row(key.replace('_', ' ').title(), str(value))
204
+
205
+ self.console.print(sys_table)
206
+ self.console.print("")
207
+
208
+ # GPU Information
209
+ gpu_info = GPUDetector.get_all_gpus()
210
+ if gpu_info['available']:
211
+ gpu_table = Table(title="GPU Information", box=box.HEAVY)
212
+ gpu_table.add_column("Metric", style="cyan")
213
+ gpu_table.add_column("Value", style="green")
214
+
215
+ for i, gpu in enumerate(gpu_info['gpus']):
216
+ gpu_table.add_row(f"GPU {i} Type", gpu.get('type', 'Unknown'))
217
+ gpu_table.add_row(f"GPU {i} Name", gpu.get('name', 'Unknown'))
218
+ if gpu.get('memory_total'):
219
+ gpu_table.add_row(f"Memory Total", f"{gpu['memory_total'] / (1024**3):.2f} GB")
220
+ if gpu.get('temperature'):
221
+ gpu_table.add_row(f"Temperature", f"{gpu['temperature']}°C")
222
+
223
+ self.console.print(gpu_table)
224
+ self.console.print("")
225
+
226
+ # Performance Test
227
+ start_time = time.time()
228
+ try:
229
+ while True:
230
+ current_time = time.time()
231
+ if duration and (current_time - start_time >= duration):
232
+ break
233
+
234
+ cpu_percent = psutil.cpu_percent()
235
+ memory_percent = psutil.virtual_memory().percent
236
+
237
+ self.cpu_graph.add_point(cpu_percent)
238
+ self.memory_graph.add_point(memory_percent)
239
+
240
+ if export_data:
241
+ self.monitoring_data.append({
242
+ 'timestamp': datetime.datetime.now().isoformat(),
243
+ 'cpu_usage': cpu_percent,
244
+ 'memory_usage': memory_percent
245
+ })
246
+
247
+ self.console.clear()
248
+ self.console.print(Panel.fit(
249
+ f"[bold cyan]Performance Test Progress: {int(current_time - start_time)}s{f'/{duration}s' if duration else ''}[/bold cyan]",
250
+ box=box.DOUBLE
251
+ ))
252
+
253
+ self.console.print(self.cpu_graph.render(f"CPU Usage: {cpu_percent:.1f}%"))
254
+ self.console.print("")
255
+ self.console.print(self.memory_graph.render(f"Memory Usage: {memory_percent:.1f}%"))
256
+
257
+ time.sleep(interval)
258
+
259
+ except KeyboardInterrupt:
260
+ self.console.print("\n[yellow]Monitoring stopped by user[/yellow]")
261
+
262
+ # Final Summary
263
+ self.console.clear()
264
+ summary_table = Table(title="Performance Test Summary", box=box.HEAVY)
265
+ summary_table.add_column("Metric", style="cyan")
266
+ summary_table.add_column("Average", style="green")
267
+ summary_table.add_column("Maximum", style="red")
268
+
269
+ cpu_values = list(self.cpu_graph.data)
270
+ mem_values = list(self.memory_graph.data)
271
+
272
+ if cpu_values:
273
+ summary_table.add_row(
274
+ "CPU Usage",
275
+ f"{sum(cpu_values) / len(cpu_values):.1f}%",
276
+ f"{max(cpu_values):.1f}%"
277
+ )
278
+ if mem_values:
279
+ summary_table.add_row(
280
+ "Memory Usage",
281
+ f"{sum(mem_values) / len(mem_values):.1f}%",
282
+ f"{max(mem_values):.1f}%"
283
+ )
284
+
285
+ self.console.print(Panel.fit(
286
+ "[bold green]Performance Test Completed![/bold green]",
287
+ box=box.DOUBLE
288
+ ))
289
+ self.console.print(summary_table)
290
+
291
+ # Final Graphs
292
+ self.console.print(self.cpu_graph.render("CPU Usage History"))
293
+ self.console.print("")
294
+ self.console.print(self.memory_graph.render("Memory Usage History"))
295
+
296
+ if export_data:
297
+ self.export_monitoring_data()
298
+ self.console.print("\n[green]Monitoring data exported to 'monitoring_data.csv'[/green]")
299
+
300
+ # @click.group()
301
+ # def cli():
302
+ # """🖥️ System Performance Monitor CLI"""
303
+ # pass
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 DHANUSH KANDHAN
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.2
2
+ Name: guro
3
+ Version: 0.1.0
4
+ Summary: A Simple System Monitoring & Benchmarking Toolkit
5
+ Home-page: https://github.com/dhanushk-offl/guro
6
+ Author: Dhanush Kandhan
7
+ Author-email: dhanushkandhan75@gmail.com
8
+ Project-URL: Bug Reports, https://github.com/dhanushk-offl/guro/issues
9
+ Project-URL: Source, https://github.com/dhanushk-offl/guro
10
+ Project-URL: Documentation, https://github.com/dhanushk-offl/guro/wiki
11
+ Keywords: system-monitoring,gpu-optimization,performance-tuning,hardware-monitoring,system-administration,nvidia-gpu,amd-gpu,intel-gpu,resource-monitoring,system-optimization
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: POSIX :: Linux
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Operating System :: MacOS :: MacOS X
17
+ Classifier: Topic :: System :: Hardware
18
+ Classifier: Topic :: System :: Monitoring
19
+ Classifier: Topic :: System :: Systems Administration
20
+ Classifier: Topic :: System :: Operating System
21
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Classifier: Intended Audience :: System Administrators
24
+ Classifier: Intended Audience :: Developers
25
+ Classifier: Development Status :: 4 - Beta
26
+ Classifier: Environment :: Console
27
+ Classifier: Natural Language :: English
28
+ Requires-Python: >=3.7
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: click>=8.0.0
32
+ Requires-Dist: rich>=10.0.0
33
+ Requires-Dist: psutil>=5.8.0
34
+ Requires-Dist: gputil>=1.4.0
35
+ Requires-Dist: matplotlib>=3.5.0
36
+ Requires-Dist: nvidia-ml-py>=11.515.0
37
+ Requires-Dist: pandas>=1.3.0
38
+ Requires-Dist: plotly>=5.5.0
39
+ Requires-Dist: termcolor>=2.0.0
40
+ Requires-Dist: tabulate>=0.8.9
41
+ Requires-Dist: py-cpuinfo>=8.0.0
42
+ Requires-Dist: setproctitle>=1.2.2
43
+ Requires-Dist: keyboard>=0.13.5
44
+ Requires-Dist: pytest>=7.0.0
45
+ Requires-Dist: pytest-mock>=3.10.0
46
+ Requires-Dist: pytest-cov>=4.0.0
47
+ Requires-Dist: pytest-timeout>=2.1.0
48
+ Provides-Extra: nvidia
49
+ Requires-Dist: py3nvml>=0.2.7; extra == "nvidia"
50
+ Requires-Dist: nvidia-ml-py>=11.515.0; extra == "nvidia"
51
+ Provides-Extra: amd
52
+ Requires-Dist: pyamdgpuinfo>=2.1.0; extra == "amd"
53
+ Provides-Extra: all
54
+ Requires-Dist: py3nvml>=0.2.7; extra == "all"
55
+ Requires-Dist: nvidia-ml-py>=11.515.0; extra == "all"
56
+ Requires-Dist: pyamdgpuinfo>=2.1.0; extra == "all"
57
+ Requires-Dist: matplotlib>=3.5.0; extra == "all"
58
+ Requires-Dist: plotly>=5.5.0; extra == "all"
59
+ Provides-Extra: test
60
+ Requires-Dist: pytest>=7.0.0; extra == "test"
61
+ Requires-Dist: pytest-mock>=3.10.0; extra == "test"
62
+ Requires-Dist: pytest-cov>=4.0.0; extra == "test"
63
+ Requires-Dist: pytest-timeout>=2.1.0; extra == "test"
64
+ Dynamic: author
65
+ Dynamic: author-email
66
+ Dynamic: classifier
67
+ Dynamic: description
68
+ Dynamic: description-content-type
69
+ Dynamic: home-page
70
+ Dynamic: keywords
71
+ Dynamic: project-url
72
+ Dynamic: provides-extra
73
+ Dynamic: requires-dist
74
+ Dynamic: requires-python
75
+ Dynamic: summary
76
+
77
+ # Guro - A Simple System Monitoring & Benchmarking Toolkit 🚀
78
+
79
+
80
+ Welcome to **Guro**, the ultimate toolkit for **system monitoring** and **benchmarking**. It’s simple, fast, and designed for developers and enthusiasts who want to monitor system performance, run benchmarks, and visualize system heatmaps in an intuitive way.
81
+
82
+ ### Features:
83
+ - 📊 **Real-time system monitoring** – Monitor CPU, memory, and disk usage in real-time.
84
+ - 🔥 **Performance benchmarking** – Run benchmarks with mini and full-scale tests for your CPU and GPU.
85
+ - 🌡️ **Hardware heatmap** – Visualize your system's temperature with a heatmap in real-time.
86
+ - 💾 **Export data** – Export monitoring data to CSV for analysis.
87
+
88
+ ### Installation
89
+
90
+ ```bash
91
+ pip install guro
92
+ ```
93
+
94
+ ### Usage
95
+
96
+ Run the following commands for monitoring, benchmarking, or heatmap analysis:
97
+
98
+ #### 1. **Monitor System Resources**
99
+ ```bash
100
+ guro monitor --interval 1.0 --duration 60
101
+ ```
102
+
103
+ #### 2. **Run Benchmark Tests**
104
+ ```bash
105
+ guro benchmark --type mini --cpu-only
106
+ ```
107
+
108
+ #### 3. **Visualize System Heatmap**
109
+ ```bash
110
+ guro heatmap --interval 1.0 --duration 30
111
+ ```
112
+
113
+ #### 4. **List All Commands**
114
+ ```bash
115
+ guro list
116
+ ```
117
+
118
+ For more details, check out our [documentation](https://github.com/dhanushk-offl/guro/wiki).
119
+
120
+ ### Demo
121
+
122
+ [Watch the demo video here](https://www.youtube.com/watch?v=xyz123)
123
+
124
+ ### License
125
+
126
+ MIT License. See LICENSE for more details.
@@ -0,0 +1,13 @@
1
+ guro/__init__.py,sha256=jfsfKFXPEm3Vw2kGvN0tF6BdymKeuVwD-BKDa4UcdZI,41
2
+ guro/cli/__init__.py,sha256=Yf6zQAso40qDlQxYRO7I69vJAeZFARH3Mb4uuyVkZw8,66
3
+ guro/cli/main.py,sha256=uRS2YaI6ohK5b8SC7ls3v9yVaK3xeZQYeYa5v2siW8E,6454
4
+ guro/core/__init__.py,sha256=QnMaN9YZAoGFCQUc96je7epXpuDtxYJkIp2CmLpaJGg,88
5
+ guro/core/benchmark.py,sha256=HekY0qw18fZmDm6dAUPnYDWsYdxJAfZ1O0oQOKi27fQ,12079
6
+ guro/core/heatmap.py,sha256=x7YX7KjkBHQ89VEdISqkx8P1C2VrTNm1f6k4UdY0-Ao,13452
7
+ guro/core/monitor.py,sha256=ZgaF0U3lQdChDkjgP3g3VTODgclBWscRoRSlyndWY9g,11625
8
+ guro-0.1.0.dist-info/LICENSE,sha256=MHJpjnxHbUoDnq3h1-egX5V2xYAlKwwElYlzl_J8nHk,1093
9
+ guro-0.1.0.dist-info/METADATA,sha256=4OzeNSX5JxHev_Qm6NvHgHVqFfzemXAcIpdg6UNfJQs,4484
10
+ guro-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
11
+ guro-0.1.0.dist-info/entry_points.txt,sha256=9JtiZiie5WKQ-qCDaAeZJMIOggcorlq8UKCBAM0tFMs,43
12
+ guro-0.1.0.dist-info/top_level.txt,sha256=eUjx5tz9mwVwUwI_XxhkCZeBBH0GYj8zkwGDrsWHxOg,5
13
+ guro-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ guro = guro.cli.main:cli
@@ -0,0 +1 @@
1
+ guro