michael@0: #!/usr/bin/env python michael@0: # michael@0: # $Id: iotop.py 1160 2011-10-14 18:50:36Z g.rodola@gmail.com $ michael@0: # michael@0: # Copyright (c) 2009, Giampaolo Rodola'. All rights reserved. michael@0: # Use of this source code is governed by a BSD-style license that can be michael@0: # found in the LICENSE file. michael@0: michael@0: """ michael@0: Shows real-time network statistics. michael@0: michael@0: Author: Giampaolo Rodola' michael@0: """ michael@0: michael@0: import sys michael@0: import os michael@0: if os.name != 'posix': michael@0: sys.exit('platform not supported') michael@0: import curses michael@0: import atexit michael@0: import time michael@0: michael@0: import psutil michael@0: michael@0: michael@0: # --- curses stuff michael@0: def tear_down(): michael@0: win.keypad(0) michael@0: curses.nocbreak() michael@0: curses.echo() michael@0: curses.endwin() michael@0: michael@0: win = curses.initscr() michael@0: atexit.register(tear_down) michael@0: curses.endwin() michael@0: lineno = 0 michael@0: michael@0: def print_line(line, highlight=False): michael@0: """A thin wrapper around curses's addstr().""" michael@0: global lineno michael@0: try: michael@0: if highlight: michael@0: line += " " * (win.getmaxyx()[1] - len(line)) michael@0: win.addstr(lineno, 0, line, curses.A_REVERSE) michael@0: else: michael@0: win.addstr(lineno, 0, line, 0) michael@0: except curses.error: michael@0: lineno = 0 michael@0: win.refresh() michael@0: raise michael@0: else: michael@0: lineno += 1 michael@0: # --- curses stuff michael@0: michael@0: michael@0: def bytes2human(n): michael@0: """ michael@0: >>> bytes2human(10000) michael@0: '9.8 K' michael@0: >>> bytes2human(100001221) michael@0: '95.4 M' michael@0: """ michael@0: symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') michael@0: prefix = {} michael@0: for i, s in enumerate(symbols): michael@0: prefix[s] = 1 << (i+1)*10 michael@0: for s in reversed(symbols): michael@0: if n >= prefix[s]: michael@0: value = float(n) / prefix[s] michael@0: return '%.2f %s' % (value, s) michael@0: return '%.2f B' % (n) michael@0: michael@0: def poll(interval): michael@0: """Retrieve raw stats within an interval window.""" michael@0: tot_before = psutil.net_io_counters() michael@0: pnic_before = psutil.net_io_counters(pernic=True) michael@0: # sleep some time michael@0: time.sleep(interval) michael@0: tot_after = psutil.net_io_counters() michael@0: pnic_after = psutil.net_io_counters(pernic=True) michael@0: return (tot_before, tot_after, pnic_before, pnic_after) michael@0: michael@0: michael@0: def refresh_window(tot_before, tot_after, pnic_before, pnic_after): michael@0: """Print stats on screen.""" michael@0: global lineno michael@0: michael@0: # totals michael@0: print_line("total bytes: sent: %-10s received: %s" \ michael@0: % (bytes2human(tot_after.bytes_sent), michael@0: bytes2human(tot_after.bytes_recv)) michael@0: ) michael@0: print_line("total packets: sent: %-10s received: %s" \ michael@0: % (tot_after.packets_sent, tot_after.packets_recv) michael@0: ) michael@0: michael@0: michael@0: # per-network interface details: let's sort network interfaces so michael@0: # that the ones which generated more traffic are shown first michael@0: print_line("") michael@0: nic_names = list(pnic_after.keys()) michael@0: nic_names.sort(key=lambda x: sum(pnic_after[x]), reverse=True) michael@0: for name in nic_names: michael@0: stats_before = pnic_before[name] michael@0: stats_after = pnic_after[name] michael@0: templ = "%-15s %15s %15s" michael@0: print_line(templ % (name, "TOTAL", "PER-SEC"), highlight=True) michael@0: print_line(templ % ( michael@0: "bytes-sent", michael@0: bytes2human(stats_after.bytes_sent), michael@0: bytes2human(stats_after.bytes_sent - stats_before.bytes_sent) + '/s', michael@0: )) michael@0: print_line(templ % ( michael@0: "bytes-recv", michael@0: bytes2human(stats_after.bytes_recv), michael@0: bytes2human(stats_after.bytes_recv - stats_before.bytes_recv) + '/s', michael@0: )) michael@0: print_line(templ % ( michael@0: "pkts-sent", michael@0: stats_after.packets_sent, michael@0: stats_after.packets_sent - stats_before.packets_sent, michael@0: )) michael@0: print_line(templ % ( michael@0: "pkts-recv", michael@0: stats_after.packets_recv, michael@0: stats_after.packets_recv - stats_before.packets_recv, michael@0: )) michael@0: print_line("") michael@0: win.refresh() michael@0: lineno = 0 michael@0: michael@0: michael@0: def main(): michael@0: try: michael@0: interval = 0 michael@0: while 1: michael@0: args = poll(interval) michael@0: refresh_window(*args) michael@0: interval = 1 michael@0: except (KeyboardInterrupt, SystemExit): michael@0: pass michael@0: michael@0: if __name__ == '__main__': michael@0: main()