3
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
4
# Use of this source code is governed by a BSD-style license that can be
5
# found in the LICENSE file.
7
"""A clone of top / htop.
9
Author: Giampaolo Rodola' <g.rodola@gmail.com>
11
$ python3 scripts/top.py
16
Mem [||||||||||||||||||||||||||||| ] 73.0% 11017M / 15936M
17
Swap [ ] 1.3% 276M / 20467M
18
Processes: 347 (sleeping=273, running=1, idle=73)
19
Load average: 1.10 1.28 1.34 Uptime: 8 days, 21:15:40
21
PID USER NI VIRT RES CPU% MEM% TIME+ NAME
22
5368 giampaol 0 7.2G 4.3G 41.8 27.7 56:34.18 VirtualBox
23
24976 giampaol 0 2.1G 487.2M 18.7 3.1 22:05.16 Web Content
24
22731 giampaol 0 3.2G 596.2M 11.6 3.7 35:04.90 firefox
25
1202 root 0 807.4M 288.5M 10.6 1.8 12:22.12 Xorg
26
22811 giampaol 0 2.8G 741.8M 9.0 4.7 2:26.61 Web Content
27
2590 giampaol 0 2.3G 579.4M 5.5 3.6 28:02.70 compiz
28
22990 giampaol 0 3.0G 1.2G 4.2 7.6 4:30.32 Web Content
29
18412 giampaol 0 90.1M 14.5M 3.5 0.1 0:00.26 python3
30
26971 netdata 0 20.8M 3.9M 2.9 0.0 3:17.14 apps.plugin
31
2421 giampaol 0 3.3G 36.9M 2.3 0.2 57:14.21 pulseaudio
43
sys.exit('platform not supported')
46
from psutil._common import bytes2human
51
colors_map = dict(green=3, red=10, yellow=4)
54
def printl(line, color=None, bold=False, highlight=False):
55
"""A thin wrapper around curses's addstr()."""
60
flags |= curses.color_pair(colors_map[color])
62
flags |= curses.A_BOLD
64
line += " " * (win.getmaxyx()[1] - len(line))
65
flags |= curses.A_STANDOUT
66
win.addstr(lineno, 0, line, flags)
83
for p in psutil.process_iter():
96
procs_status[p.dict['status']] += 1
98
procs_status[p.dict['status']] = 1
99
except psutil.NoSuchProcess:
104
# return processes sorted by CPU percent usage
106
procs, key=lambda p: p.dict['cpu_percent'], reverse=True
108
return (processes, procs_status)
120
def print_header(procs_status, num_procs):
121
"""Print system-related info, above the process list."""
123
def get_dashes(perc):
124
dashes = "|" * int(float(perc) / 10 * 4)
125
empty_dashes = " " * (40 - len(dashes))
126
return dashes, empty_dashes
129
percs = psutil.cpu_percent(interval=0, percpu=True)
130
for cpu_num, perc in enumerate(percs):
131
dashes, empty_dashes = get_dashes(perc)
132
line = " CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes, perc)
133
printl(line, color=get_color(perc))
136
mem = psutil.virtual_memory()
137
dashes, empty_dashes = get_dashes(mem.percent)
138
line = " Mem [%s%s] %5s%% %6s / %s" % (
142
bytes2human(mem.used),
143
bytes2human(mem.total),
145
printl(line, color=get_color(mem.percent))
148
swap = psutil.swap_memory()
149
dashes, empty_dashes = get_dashes(swap.percent)
150
line = " Swap [%s%s] %5s%% %6s / %s" % (
154
bytes2human(swap.used),
155
bytes2human(swap.total),
157
printl(line, color=get_color(swap.percent))
159
# processes number and status
161
for x, y in procs_status.items():
163
st.append("%s=%s" % (x, y))
164
st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
165
printl(" Processes: %s (%s)" % (num_procs, ', '.join(st)))
166
# load average, uptime
167
uptime = datetime.datetime.now() - datetime.datetime.fromtimestamp(
170
av1, av2, av3 = psutil.getloadavg()
171
line = " Load average: %.2f %.2f %.2f Uptime: %s" % (
175
str(uptime).split('.')[0],
180
def refresh_window(procs, procs_status):
181
"""Print results on screen by using curses."""
183
templ = "%-6s %-8s %4s %6s %6s %5s %5s %9s %2s"
196
print_header(procs_status, len(procs))
198
printl(header, bold=True, highlight=True)
200
# TIME+ column shows process CPU cumulative time and it
201
# is expressed as: "mm:ss.ms"
202
if p.dict['cpu_times'] is not None:
203
ctime = datetime.timedelta(seconds=sum(p.dict['cpu_times']))
204
ctime = "%s:%s.%s" % (
205
ctime.seconds // 60 % 60,
206
str(ctime.seconds % 60).zfill(2),
207
str(ctime.microseconds)[:2],
211
if p.dict['memory_percent'] is not None:
212
p.dict['memory_percent'] = round(p.dict['memory_percent'], 1)
214
p.dict['memory_percent'] = ''
215
if p.dict['cpu_percent'] is None:
216
p.dict['cpu_percent'] = ''
217
username = p.dict['username'][:8] if p.dict['username'] else ''
222
bytes2human(getattr(p.dict['memory_info'], 'vms', 0)),
223
bytes2human(getattr(p.dict['memory_info'], 'rss', 0)),
224
p.dict['cpu_percent'],
225
p.dict['memory_percent'],
227
p.dict['name'] or '',
238
curses.use_default_colors()
239
for i in range(curses.COLORS):
240
curses.init_pair(i + 1, i, -1)
257
if win.getch() == ord('q'):
259
args = poll(interval)
260
refresh_window(*args)
262
except (KeyboardInterrupt, SystemExit):
268
if __name__ == '__main__':