OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # | |
3 # $Id: iotop.py 1143 2011-10-05 19:11:59Z g.rodola $ | |
4 # | |
5 # Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. | |
6 # Use of this source code is governed by a BSD-style license that can be | |
7 # found in the LICENSE file. | |
8 | |
9 """ | |
10 A clone of iotop (http://guichaz.free.fr/iotop/) showing real time | |
11 disk I/O statistics. | |
12 | |
13 It works on UNIX only as curses module is not available on Windows. | |
14 | |
15 Author: Giampaolo Rodola' <g.rodola@gmail.com> | |
16 """ | |
17 | |
18 import time | |
19 import curses | |
20 import atexit | |
21 | |
22 import psutil | |
23 | |
24 win = curses.initscr() | |
25 | |
26 def bytes2human(n): | |
27 """ | |
28 >>> bytes2human(10000) | |
29 '9.8 K/s' | |
30 >>> bytes2human(100001221) | |
31 '95.4 M/s' | |
32 """ | |
33 symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') | |
34 prefix = {} | |
35 for i, s in enumerate(symbols): | |
36 prefix[s] = 1 << (i+1)*10 | |
37 for s in reversed(symbols): | |
38 if n >= prefix[s]: | |
39 value = float(n) / prefix[s] | |
40 return '%.2f %s/s' % (value, s) | |
41 return "0.00 B/s" | |
42 | |
43 def poll(interval): | |
44 """Calculate IO usage by comparing IO statics before and | |
45 after the interval. | |
46 Return a tuple including all currently running processes | |
47 sorted by IO activity and total disks I/O activity. | |
48 """ | |
49 # first get a list of all processes and disk io counters | |
50 procs = [p for p in psutil.process_iter()] | |
51 for p in procs[:]: | |
52 try: | |
53 p._before = p.get_io_counters() | |
54 except psutil.Error: | |
55 procs.remove(p) | |
56 continue | |
57 disks_before = psutil.disk_io_counters() | |
58 | |
59 # sleep some time | |
60 time.sleep(interval) | |
61 | |
62 # then retrieve the same info again | |
63 for p in procs[:]: | |
64 try: | |
65 p._after = p.get_io_counters() | |
66 p._cmdline = ' '.join(p.cmdline) | |
67 if not p._cmdline: | |
68 p._cmdline = p.name | |
69 p._username = p.username | |
70 except psutil.NoSuchProcess: | |
71 procs.remove(p) | |
72 disks_after = psutil.disk_io_counters() | |
73 | |
74 # finally calculate results by comparing data before and | |
75 # after the interval | |
76 for p in procs: | |
77 p._read_per_sec = p._after.read_bytes - p._before.read_bytes | |
78 p._write_per_sec = p._after.write_bytes - p._before.write_bytes | |
79 p._total = p._read_per_sec + p._write_per_sec | |
80 | |
81 disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes | |
82 disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes | |
83 | |
84 # sort processes by total disk IO so that the more intensive | |
85 # ones get listed first | |
86 processes = sorted(procs, key=lambda p: p._total, reverse=True) | |
87 | |
88 return (processes, disks_read_per_sec, disks_write_per_sec) | |
89 | |
90 def run(win): | |
91 """Print results on screen by using curses.""" | |
92 curses.endwin() | |
93 templ = "%-5s %-7s %11s %11s %s" | |
94 interval = 0 | |
95 while 1: | |
96 procs, disks_read, disks_write = poll(interval) | |
97 win.erase() | |
98 | |
99 disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \ | |
100 % (bytes2human(disks_read), bytes2human(disks_write)) | |
101 win.addstr(0, 0, disks_tot) | |
102 | |
103 header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND") | |
104 header += " " * (win.getmaxyx()[1] - len(header)) | |
105 win.addstr(1, 0, header, curses.A_REVERSE) | |
106 | |
107 lineno = 2 | |
108 for p in procs: | |
109 line = templ % (p.pid, | |
110 p._username[:7], | |
111 bytes2human(p._read_per_sec), | |
112 bytes2human(p._write_per_sec), | |
113 p._cmdline) | |
114 try: | |
115 win.addstr(lineno, 0, line) | |
116 except curses.error: | |
117 break | |
118 win.refresh() | |
119 lineno += 1 | |
120 interval = 1 | |
121 | |
122 def main(): | |
123 def tear_down(): | |
124 win.keypad(0) | |
125 curses.nocbreak() | |
126 curses.echo() | |
127 curses.endwin() | |
128 | |
129 atexit.register(tear_down) | |
130 try: | |
131 run(win) | |
132 except (KeyboardInterrupt, SystemExit): | |
133 pass | |
134 | |
135 if __name__ == '__main__': | |
136 main() | |
OLD | NEW |