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 |