-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSystemMonitorGadget.py
More file actions
133 lines (110 loc) · 4.19 KB
/
SystemMonitorGadget.py
File metadata and controls
133 lines (110 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import psutil
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
from collections import deque
# --- Settings ---
UPDATE_INTERVAL = 1000 # ms
HISTORY_LENGTH = 60
# Track history
cpu_history = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
mem_history = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
disk_history = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
net_history = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
# Top process histories
top_cpu_hist = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
top_disk_hist = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
top_net_hist = deque([0]*HISTORY_LENGTH, maxlen=HISTORY_LENGTH)
job = None # handle for .after()
def get_top_processes():
processes = []
for p in psutil.process_iter(['pid','name','cpu_percent','io_counters']):
try:
if p.info['name'] == "System Idle Process":
continue
io = p.info['io_counters']
read_write = (io.read_bytes + io.write_bytes) if io else 0
processes.append((p.info['pid'], p.info['name'], p.info['cpu_percent'], read_write))
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
if not processes:
return None, None
top_cpu = max(processes, key=lambda x: x[2], default=None)
top_disk = max(processes, key=lambda x: x[3], default=None)
return top_cpu, top_disk
def update_data():
global job
# System usage
cpu = psutil.cpu_percent()
mem = psutil.virtual_memory().percent
disk = psutil.disk_io_counters()
net = psutil.net_io_counters()
disk_rate = (disk.read_bytes + disk.write_bytes) / 1024
net_rate = (net.bytes_sent + net.bytes_recv) / 1024
cpu_history.append(cpu)
mem_history.append(mem)
disk_history.append(disk_rate)
net_history.append(net_rate)
top_cpu, top_disk = get_top_processes()
if top_cpu: top_cpu_hist.append(top_cpu[2])
if top_disk: top_disk_hist.append(top_disk[3]/1024)
top_net_hist.append(net_rate)
# Update graphs
def draw_line(ax, data, color="blue"):
ax.clear()
ax.plot(list(data), color=color)
ax.set_ylim(0, max(max(data)*1.5, 1))
ax.set_xticks([])
ax.set_yticks([])
ax.set_facecolor("black")
ax.tick_params(colors="white")
for label in ax.get_xticklabels()+ax.get_yticklabels():
label.set_fontname("Arial")
draw_line(ax_cpu, cpu_history, "cyan")
draw_line(ax_mem, mem_history, "purple")
draw_line(ax_disk, disk_history, "green")
draw_line(ax_net, net_history, "orange")
# Top processes stacked
ax_top.clear()
ax_top.plot(list(top_cpu_hist), label="Top CPU %", color="red")
ax_top.plot(list(top_disk_hist), label="Top Disk KB/s", color="green")
ax_top.plot(list(top_net_hist), label="Top Net KB/s", color="orange")
ax_top.set_ylim(0, max(
max(top_cpu_hist, default=1),
max(top_disk_hist, default=1),
max(top_net_hist, default=1)
)*1.5)
ax_top.legend(loc="upper right", fontsize=8)
ax_top.set_facecolor("black")
ax_top.tick_params(colors="white")
for label in ax_top.get_xticklabels()+ax_top.get_yticklabels():
label.set_fontname("Arial")
canvas.draw()
job = root.after(UPDATE_INTERVAL, update_data)
def on_close():
global job
if job:
root.after_cancel(job) # cancel scheduled job
root.destroy()
# --- GUI Setup ---
root = tk.Tk()
root.title("System Monitor")
root.configure(bg="black")
# Move window to top-right
root.update_idletasks()
screen_width = root.winfo_screenwidth()
window_width = 600
window_height = 600
root.geometry(f"{window_width}x{window_height}+{screen_width-window_width}+0")
fig, ((ax_cpu, ax_mem), (ax_disk, ax_net), (ax_top, _)) = plt.subplots(3, 2, figsize=(6,6))
fig.subplots_adjust(hspace=0.5, wspace=0.3)
for ax in [ax_cpu, ax_mem, ax_disk, ax_net, ax_top]:
ax.set_facecolor("black")
ax.tick_params(colors="white")
# Remove unused subplot
fig.delaxes(_)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
root.protocol("WM_DELETE_WINDOW", on_close) # safe exit
update_data()
root.mainloop()