| 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 |