Introduction
Introduction Statistics Contact Development Disclaimer Help
cpu_mon.py - sites - public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log
Files
Refs
---
cpu_mon.py (8598B)
---
1 #!/usr/bin/python
2 # coding: utf-8
3 """
4 GENMON APPLET USAGE EXAMPLE
5
6 A Custom CPU monitor.
7
8 Challenge: We want a bit of history and cpu monitoring anyway needs some…
9
10 So we run this as daemon.
11 It keeps writing cpu infos to file -> start me in autostart.sh
12
13 Hightlights:
14 - cpu per core
15 - top cpu eating process, customized with own config (not colliding with…
16 - arbitray long symbol lists, will pick per percent
17 - output colorized using pango
18
19 Lowlights:
20 Linux Only. Not hard to rewrite, but now it's just Linux, looking into /…
21 For BSD check the suckless' slstatus regarding how to derive load.
22
23 Usage:
24 Start this tool e.g. in autostart.sh and leave running.
25 In genmon use `cat $HOME/.dwm/out.cpu_mon` for the single shot tray icon…
26 """
27
28 import os, sys, psutil, time, subprocess as sp
29 import time
30
31 here = os.path.abspath((os.path.dirname(__file__)))
32
33 # ----------------------------------------------------------------------…
34 col_norm = '#a093c7'
35 col_high = '#bf568b'
36
37 # we run top whenever a core if over this:
38 th_cpu_min_to_snapshot_top = 20
39 # we show proc names whenever its utilizaition is over this:
40 th_cpu_min_to_show_procs = 80
41 # 0: show always (>0: no space taken for core)
42 th_min_cpu_show_core = 0
43 show_max_procs = 3
44 th_color_high_cpu = 80
45 top_output_max_lines = 20
46
47 top_rc_dir = here + '/.config/procps'
48 top = 'HOME="%s" top -b -1 -n 1 -w 56 | head -n %s' % (here, top_output_…
49 Sensors = ['cpu']
50 # Sensors = ['time']
51 bars = ' ▁▂▃▄▅▆▇'
52 # ----------------------------------------------------------------------…
53
54
55 # configure the panel item to cat this file:
56 fn_out = here + '/out.cpu_mon'
57
58
59 # maybe we want arrows stuff some day:
60 Traffic100 = 1024 # bytes
61 # arr_downs = ' 🢓↓⬇ﰬ🡇'
62 arr_downs = ' ↓⬇ﰬ🡇'
63 arr_ups = ' ↑⬆🡅'
64
65 s = []
66 CPUs = psutil.cpu_count()
67 # normal way to read load: read /proc/stat
68 ctx = {'proc_stat': [0 for i in range(CPUs)], 'traffic': [0, 0], 'fifo':…
69
70
71 bar_intv = 100.0 / len(bars)
72 arr_downs_intv = 100.0 / len(arr_downs)
73 arr_ups_intv = 100.0 / len(arr_ups)
74 arrows = [[arr_downs, arr_downs_intv], [arr_ups, arr_ups_intv]]
75
76 # delivers the *cummulated* load values - per cpu.
77 # A difference of 100 within 1 sec means: fully loaded
78 proc_stat = '/proc/stat'
79
80
81 run_top = lambda: os.popen(top).read()
82
83
84 def cmd_colmn():
85 # cache the position of the COMMAND column, we need it all the time
86 n = 'cpu_top_cmd_col'
87 c = ctx.get(n)
88 if not c:
89 t = ctx['cpu_top']
90 c = ctx[n] = len(t.split(' COMMAND', 1)[0].rsplit('\n', 1)[1])
91 return c
92
93
94 def add_top_cpu_eaters(r, count, cpu):
95 """Get the <count> top most cpu eating procs names as shown by top"""
96 # TODO: import re would not hurt
97 t = ctx['cpu_top']
98 p = t.split('COMMAND', 1)[1].split('\n', 1 + count)
99 colmn = cmd_colmn()
100 for i in range(count, 0, -1):
101 if cpu[i - 1] < th_cpu_min_to_show_procs:
102 continue
103 # P = p)[nr].split()[11:])
104 r.insert(0, '%s ' % p[i][colmn:].replace(' ', '')[:10])
105
106
107 class sensors:
108 def cpu():
109 r = []
110 l = ctx.pop('cpu_top', 0)
111 if l:
112 ctx['cpu_top_old'] = l
113 ctx['cpu_top_old_ts'] = time.time()
114 with open(proc_stat) as fd:
115 t = fd.read()
116 o = ctx['proc_stat']
117 h = []
118 for i in range(CPUs):
119 v, t = t.split('cpu%s ' % i, 1)[1].split('\n', 1)
120 v = int(v.split(' ', 1)[0])
121 d = min(v - o[i], 99.9)
122 o[i] = v
123 # print(i, d, file=sys.stderr)
124 h.append(d)
125 h = list(reversed(sorted(h)))
126 # show top process:
127 if h[0] > th_cpu_min_to_snapshot_top: # 20
128 ctx['cpu_top'] = run_top() # for hover tip - only when ther…
129 if h[0] > th_cpu_min_to_show_procs:
130 add_top_cpu_eaters(r, show_max_procs, h) # for status b…
131 ctx['col_cpu'] = col_high if h[0] > th_color_high_cpu else col_n…
132 v = lambda d: '' if d < th_min_cpu_show_core else bars[int(d / b…
133 [r.append(v(d)) for d in h]
134 return ''.join(r)
135
136
137 # These would be other sensors - but for those we take the original ones…
138 # def time():
139 # t = time.ctime().split()
140 # t.pop(1) # month
141 # t.pop()
142 # return ' '.join(t)
143
144 # def mem():
145 # return '%s' % psutil.virtual_memory().percent
146
147 # def traffic():
148 # r = []
149 # o = ctx['traffic']
150 # h = psutil.net_io_counters(pernic=False)
151 # v = [h.bytes_sent, h.bytes_recv]
152 # print('')
153 # for i in range(2):
154 # d = 100 * (min((v[i] - o[i]), Traffic100 - 1) / Traffic100)
155 # # print('%s\t%s' % (v[i] - o[i], d))
156 # o[i] = v[i]
157 # arrs, arr_int = arrows[i]
158 # col = '\x04' if i == 0 else '\x03'
159 # s = arrs[int(d / arr_int)]
160 # r.append('%s%s' % (col, s))
161 # return ''.join(r)
162
163 # def battery():
164 # B = ''
165 # P = 'ﮤ'
166 # d = psutil.sensors_battery()
167 # d, pp = int(d.percent), d.power_plugged
168 # p = '\x02' + P[0] if pp else '\x04' + P[1]
169 # s = B[int(min(d, 99) / (100 / len(B)))]
170 # if d < 30:
171 # s = '\x04' + s
172 # if d < 60:
173 # s = '\x03' + s
174 # else:
175 # s = '\x02' + s
176 # if d > 90 and pp:
177 # return ''
178 # return s + ' ' + p + ' '
179
180
181 # for dwm's status bar (old version, caused high cpu):
182 # def xsetroot(sl):
183 # if os.system('xsetroot -name "%s"' % sl):
184 # print('exitting status.py')
185 # sys.exit(1)
186
187
188 def to_stdout(sl):
189 sl = '<txt><span fgcolor="%s">%s</span></txt>' % (ctx['col_cpu'], sl)
190 t = ctx.get('cpu_top')
191 if not t:
192 t = ctx.get('cpu_top_old')
193 if t:
194 t = '%s Seconds Ago:\n' % (int(time.time() - ctx['cpu_top_ol…
195
196 if t:
197 sl += '<tool><span font_family="monospace">%s</span></tool>' % t
198 print(sl)
199 fd = ctx['fd_out']
200 fd.seek(0)
201 fd.write(sl)
202 fd.flush()
203
204
205 def main():
206 ctx['fd_out'] = open(fn_out, 'w')
207 out = to_stdout
208 while True:
209 s.clear()
210 for w in Sensors:
211 k = getattr(sensors, w)()
212 s.append('%s ' % k)
213 sl = ''.join(s)
214 r = os.popen('ls -lta --color=always').read()
215 out(sl)
216 time.sleep(1) # other values: load calc must be adapted.
217
218
219 # Follows the top config - you cant use CLI flags for this.
220 # Created by: `HOME=~/.dwm top` -> F (select fields) -> W (write toprc)
221 # then:
222 # cat .dwm/.config/procps/toprc | base64 >> $HOME/bin/cpu_mon.py (is bi…
223 top_cfg = '''
224 dG9wJ3MgQ29uZmlnIEZpbGUgKExpbnV4IHByb2Nlc3NlcyB3aXRoIHdpbmRvd3MpCklkOmos…
225 ZGVfYWx0c2NyPTAsIE1vZGVfaXJpeHBzPTEsIERlbGF5X3RpbWU9My4wLCBDdXJ3aW49MApE…
226 ZmllbGRzY3VyPaWmqDO0Oz1AxLe6OcUnKSorLC0uLzAxMjU2ODw+P0FCQ0ZHSElKS0xNTk9Q…
227 VFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Cgl3aW5mbGFncz0xNjEw…
228 IHNvcnRpbmR4PTE4LCBtYXh0YXNrcz0wLCBncmFwaF9jcHVzPTAsIGdyYXBoX21lbXM9MCwg…
229 YmxlX3VwPTAsIGNvbWJpbmVfY3B1cz0wCglzdW1tY2xyPTEsIG1zZ3NjbHI9MSwgaGVhZGNs…
230 LCB0YXNrY2xyPTEKSm9iCWZpZWxkc2N1cj2lprm3uiiztMS7vUA8p8UpKissLS4vMDEyNTY4…
231 QkNGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5…
232 d2luZmxhZ3M9MTkzODQ0LCBzb3J0aW5keD0wLCBtYXh0YXNrcz0wLCBncmFwaF9jcHVzPTAs…
233 YXBoX21lbXM9MCwgZG91YmxlX3VwPTAsIGNvbWJpbmVfY3B1cz0wCglzdW1tY2xyPTYsIG1z…
234 bHI9NiwgaGVhZGNscj03LCB0YXNrY2xyPTYKTWVtCWZpZWxkc2N1cj2lurs8vb6/wMFNQk7D…
235 t8UmJygpKissLS4vMDEyNTY4OUZHSElKS0xPUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlq…
236 bm9wcXJzdHV2d3h5egoJd2luZmxhZ3M9MTkzODQ0LCBzb3J0aW5keD0yMSwgbWF4dGFza3M9…
237 Z3JhcGhfY3B1cz0wLCBncmFwaF9tZW1zPTAsIGRvdWJsZV91cD0wLCBjb21iaW5lX2NwdXM9…
238 c3VtbWNscj01LCBtc2dzY2xyPTUsIGhlYWRjbHI9NCwgdGFza2Nscj01ClVzcglmaWVsZHNj…
239 paanqKqwube6xMUpKywtLi8xMjM0NTY4Ozw9Pj9AQUJDRkdISUpLTE1OT1BRUlNUVVZXWFla…
240 Xl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoKCXdpbmZsYWdzPTE5Mzg0NCwgc29ydGlu…
241 MywgbWF4dGFza3M9MCwgZ3JhcGhfY3B1cz0wLCBncmFwaF9tZW1zPTAsIGRvdWJsZV91cD0w…
242 b21iaW5lX2NwdXM9MAoJc3VtbWNscj0zLCBtc2dzY2xyPTMsIGhlYWRjbHI9MiwgdGFza2Ns…
243 CkZpeGVkX3dpZGVzdD0wLCBTdW1tX21zY2FsZT0xLCBUYXNrX21zY2FsZT0wLCBaZXJvX3N1…
244 ZXNzPTAK
245 '''.strip()
246
247
248 import base64
249
250
251 def write_top_cfg():
252 os.makedirs(top_rc_dir, exist_ok=True)
253 with open(top_rc_dir + '/toprc', 'wb') as fd:
254 fd.write(base64.standard_b64decode(top_cfg))
255
256
257 if __name__ == '__main__':
258 write_top_cfg()
259 try:
260 main()
261 finally:
262 ctx['fd_out'].close()
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.