forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			179 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env python
 | 
						|
 | 
						|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
 | 
						|
# Use of this source code is governed by a BSD-style license that can be
 | 
						|
# found in the LICENSE file.
 | 
						|
 | 
						|
"""
 | 
						|
A clone of iotop (http://guichaz.free.fr/iotop/) showing real time
 | 
						|
disk I/O statistics.
 | 
						|
 | 
						|
It works on Linux only (FreeBSD and OSX are missing support for IO
 | 
						|
counters).
 | 
						|
It doesn't work on Windows as curses module is required.
 | 
						|
 | 
						|
Example output:
 | 
						|
 | 
						|
$ python examples/iotop.py
 | 
						|
Total DISK READ: 0.00 B/s | Total DISK WRITE: 472.00 K/s
 | 
						|
PID   USER      DISK READ  DISK WRITE  COMMAND
 | 
						|
13155 giampao    0.00 B/s  428.00 K/s  /usr/bin/google-chrome-beta
 | 
						|
3260  giampao    0.00 B/s    0.00 B/s  bash
 | 
						|
3779  giampao    0.00 B/s    0.00 B/s  gnome-session --session=ubuntu
 | 
						|
3830  giampao    0.00 B/s    0.00 B/s  /usr/bin/dbus-launch
 | 
						|
3831  giampao    0.00 B/s    0.00 B/s  //bin/dbus-daemon --fork --print-pid 5
 | 
						|
3841  giampao    0.00 B/s    0.00 B/s  /usr/lib/at-spi-bus-launcher
 | 
						|
3845  giampao    0.00 B/s    0.00 B/s  /bin/dbus-daemon
 | 
						|
3848  giampao    0.00 B/s    0.00 B/s  /usr/lib/at-spi2-core/at-spi2-registryd
 | 
						|
3862  giampao    0.00 B/s    0.00 B/s  /usr/lib/gnome-settings-daemon
 | 
						|
 | 
						|
Author: Giampaolo Rodola' <g.rodola@gmail.com>
 | 
						|
"""
 | 
						|
 | 
						|
import atexit
 | 
						|
import time
 | 
						|
import sys
 | 
						|
try:
 | 
						|
    import curses
 | 
						|
except ImportError:
 | 
						|
    sys.exit('platform not supported')
 | 
						|
 | 
						|
import psutil
 | 
						|
 | 
						|
 | 
						|
# --- curses stuff
 | 
						|
def tear_down():
 | 
						|
    win.keypad(0)
 | 
						|
    curses.nocbreak()
 | 
						|
    curses.echo()
 | 
						|
    curses.endwin()
 | 
						|
 | 
						|
win = curses.initscr()
 | 
						|
atexit.register(tear_down)
 | 
						|
curses.endwin()
 | 
						|
lineno = 0
 | 
						|
 | 
						|
 | 
						|
def print_line(line, highlight=False):
 | 
						|
    """A thin wrapper around curses's addstr()."""
 | 
						|
    global lineno
 | 
						|
    try:
 | 
						|
        if highlight:
 | 
						|
            line += " " * (win.getmaxyx()[1] - len(line))
 | 
						|
            win.addstr(lineno, 0, line, curses.A_REVERSE)
 | 
						|
        else:
 | 
						|
            win.addstr(lineno, 0, line, 0)
 | 
						|
    except curses.error:
 | 
						|
        lineno = 0
 | 
						|
        win.refresh()
 | 
						|
        raise
 | 
						|
    else:
 | 
						|
        lineno += 1
 | 
						|
# --- /curses stuff
 | 
						|
 | 
						|
 | 
						|
def bytes2human(n):
 | 
						|
    """
 | 
						|
    >>> bytes2human(10000)
 | 
						|
    '9.8 K/s'
 | 
						|
    >>> bytes2human(100001221)
 | 
						|
    '95.4 M/s'
 | 
						|
    """
 | 
						|
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
 | 
						|
    prefix = {}
 | 
						|
    for i, s in enumerate(symbols):
 | 
						|
        prefix[s] = 1 << (i + 1) * 10
 | 
						|
    for s in reversed(symbols):
 | 
						|
        if n >= prefix[s]:
 | 
						|
            value = float(n) / prefix[s]
 | 
						|
            return '%.2f %s/s' % (value, s)
 | 
						|
    return '%.2f B/s' % (n)
 | 
						|
 | 
						|
 | 
						|
def poll(interval):
 | 
						|
    """Calculate IO usage by comparing IO statics before and
 | 
						|
    after the interval.
 | 
						|
    Return a tuple including all currently running processes
 | 
						|
    sorted by IO activity and total disks I/O activity.
 | 
						|
    """
 | 
						|
    # first get a list of all processes and disk io counters
 | 
						|
    procs = [p for p in psutil.process_iter()]
 | 
						|
    for p in procs[:]:
 | 
						|
        try:
 | 
						|
            p._before = p.io_counters()
 | 
						|
        except psutil.Error:
 | 
						|
            procs.remove(p)
 | 
						|
            continue
 | 
						|
    disks_before = psutil.disk_io_counters()
 | 
						|
 | 
						|
    # sleep some time
 | 
						|
    time.sleep(interval)
 | 
						|
 | 
						|
    # then retrieve the same info again
 | 
						|
    for p in procs[:]:
 | 
						|
        try:
 | 
						|
            p._after = p.io_counters()
 | 
						|
            p._cmdline = ' '.join(p.cmdline())
 | 
						|
            if not p._cmdline:
 | 
						|
                p._cmdline = p.name()
 | 
						|
            p._username = p.username()
 | 
						|
        except (psutil.NoSuchProcess, psutil.ZombieProcess):
 | 
						|
            procs.remove(p)
 | 
						|
    disks_after = psutil.disk_io_counters()
 | 
						|
 | 
						|
    # finally calculate results by comparing data before and
 | 
						|
    # after the interval
 | 
						|
    for p in procs:
 | 
						|
        p._read_per_sec = p._after.read_bytes - p._before.read_bytes
 | 
						|
        p._write_per_sec = p._after.write_bytes - p._before.write_bytes
 | 
						|
        p._total = p._read_per_sec + p._write_per_sec
 | 
						|
 | 
						|
    disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes
 | 
						|
    disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes
 | 
						|
 | 
						|
    # sort processes by total disk IO so that the more intensive
 | 
						|
    # ones get listed first
 | 
						|
    processes = sorted(procs, key=lambda p: p._total, reverse=True)
 | 
						|
 | 
						|
    return (processes, disks_read_per_sec, disks_write_per_sec)
 | 
						|
 | 
						|
 | 
						|
def refresh_window(procs, disks_read, disks_write):
 | 
						|
    """Print results on screen by using curses."""
 | 
						|
    curses.endwin()
 | 
						|
    templ = "%-5s %-7s %11s %11s  %s"
 | 
						|
    win.erase()
 | 
						|
 | 
						|
    disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
 | 
						|
                % (bytes2human(disks_read), bytes2human(disks_write))
 | 
						|
    print_line(disks_tot)
 | 
						|
 | 
						|
    header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
 | 
						|
    print_line(header, highlight=True)
 | 
						|
 | 
						|
    for p in procs:
 | 
						|
        line = templ % (
 | 
						|
            p.pid,
 | 
						|
            p._username[:7],
 | 
						|
            bytes2human(p._read_per_sec),
 | 
						|
            bytes2human(p._write_per_sec),
 | 
						|
            p._cmdline)
 | 
						|
        try:
 | 
						|
            print_line(line)
 | 
						|
        except curses.error:
 | 
						|
            break
 | 
						|
    win.refresh()
 | 
						|
 | 
						|
 | 
						|
def main():
 | 
						|
    try:
 | 
						|
        interval = 0
 | 
						|
        while True:
 | 
						|
            args = poll(interval)
 | 
						|
            refresh_window(*args)
 | 
						|
            interval = 1
 | 
						|
    except (KeyboardInterrupt, SystemExit):
 | 
						|
        pass
 | 
						|
 | 
						|
if __name__ == '__main__':
 | 
						|
    main()
 |