~ubuntu-branches/ubuntu/trusty/python-psutil/trusty-proposed

« back to all changes in this revision

Viewing changes to examples/iotop.py

  • Committer: Charlie Smotherman
  • Date: 2011-12-05 06:55:50 UTC
  • mfrom: (2.1.8 sid)
  • Revision ID: cjsmo@cableone.net-20111205065550-lkhxf2gxwzm180w7
Tags: 0.4.0-1ubuntu1
* Merge with Debian unstable (LP: #900001).  Remaining Ubuntu changes:
  - Switch to dh_python2. (LP: #788514)
* New upstream release
* debian/python-psutil.examples
  - install examples
* debian/rules
  - don't compress .py files

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
#
 
3
# $Id: iotop.py 1213 2011-10-29 03:30:41Z 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 Linux only (FreeBSD and OSX are missing support for IO
 
14
counters).
 
15
It doesn't work on Windows as curses module is required.
 
16
 
 
17
Author: Giampaolo Rodola' <g.rodola@gmail.com>
 
18
"""
 
19
 
 
20
import os
 
21
import sys
 
22
import psutil
 
23
if not hasattr(psutil.Process, 'get_io_counters') or os.name != 'posix':
 
24
    sys.exit('platform not supported')
 
25
import time
 
26
import curses
 
27
import atexit
 
28
 
 
29
 
 
30
# --- curses stuff
 
31
def tear_down():
 
32
    win.keypad(0)
 
33
    curses.nocbreak()
 
34
    curses.echo()
 
35
    curses.endwin()
 
36
 
 
37
win = curses.initscr()
 
38
atexit.register(tear_down)
 
39
curses.endwin()
 
40
lineno = 0
 
41
 
 
42
def print_line(line, highlight=False):
 
43
    """A thin wrapper around curses's addstr()."""
 
44
    global lineno
 
45
    try:
 
46
        if highlight:
 
47
            line += " " * (win.getmaxyx()[1] - len(line))
 
48
            win.addstr(lineno, 0, line, curses.A_REVERSE)
 
49
        else:
 
50
            win.addstr(lineno, 0, line, 0)
 
51
    except curses.error:
 
52
        lineno = 0
 
53
        win.refresh()
 
54
        raise
 
55
    else:
 
56
        lineno += 1
 
57
# --- /curses stuff
 
58
 
 
59
 
 
60
def bytes2human(n):
 
61
    """
 
62
    >>> bytes2human(10000)
 
63
    '9.8 K/s'
 
64
    >>> bytes2human(100001221)
 
65
    '95.4 M/s'
 
66
    """
 
67
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
 
68
    prefix = {}
 
69
    for i, s in enumerate(symbols):
 
70
        prefix[s] = 1 << (i+1)*10
 
71
    for s in reversed(symbols):
 
72
        if n >= prefix[s]:
 
73
            value = float(n) / prefix[s]
 
74
            return '%.2f %s/s' % (value, s)
 
75
    return "0.00 B/s"
 
76
 
 
77
def poll(interval):
 
78
    """Calculate IO usage by comparing IO statics before and
 
79
    after the interval.
 
80
    Return a tuple including all currently running processes
 
81
    sorted by IO activity and total disks I/O activity.
 
82
    """
 
83
    # first get a list of all processes and disk io counters
 
84
    procs = [p for p in psutil.process_iter()]
 
85
    for p in procs[:]:
 
86
        try:
 
87
            p._before = p.get_io_counters()
 
88
        except psutil.Error:
 
89
            procs.remove(p)
 
90
            continue
 
91
    disks_before = psutil.disk_io_counters()
 
92
 
 
93
    # sleep some time
 
94
    time.sleep(interval)
 
95
 
 
96
    # then retrieve the same info again
 
97
    for p in procs[:]:
 
98
        try:
 
99
            p._after = p.get_io_counters()
 
100
            p._cmdline = ' '.join(p.cmdline)
 
101
            if not p._cmdline:
 
102
                p._cmdline = p.name
 
103
            p._username = p.username
 
104
        except psutil.NoSuchProcess:
 
105
            procs.remove(p)
 
106
    disks_after = psutil.disk_io_counters()
 
107
 
 
108
    # finally calculate results by comparing data before and
 
109
    # after the interval
 
110
    for p in procs:
 
111
        p._read_per_sec = p._after.read_bytes - p._before.read_bytes
 
112
        p._write_per_sec = p._after.write_bytes - p._before.write_bytes
 
113
        p._total = p._read_per_sec + p._write_per_sec
 
114
 
 
115
    disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes
 
116
    disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes
 
117
 
 
118
    # sort processes by total disk IO so that the more intensive
 
119
    # ones get listed first
 
120
    processes = sorted(procs, key=lambda p: p._total, reverse=True)
 
121
 
 
122
    return (processes, disks_read_per_sec, disks_write_per_sec)
 
123
 
 
124
 
 
125
def refresh_window(procs, disks_read, disks_write):
 
126
    """Print results on screen by using curses."""
 
127
    curses.endwin()
 
128
    templ = "%-5s %-7s %11s %11s  %s"
 
129
    win.erase()
 
130
 
 
131
    disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \
 
132
                % (bytes2human(disks_read), bytes2human(disks_write))
 
133
    print_line(disks_tot)
 
134
 
 
135
    header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND")
 
136
    print_line(header, highlight=True)
 
137
 
 
138
    for p in procs:
 
139
        line = templ % (p.pid,
 
140
                        p._username[:7],
 
141
                        bytes2human(p._read_per_sec),
 
142
                        bytes2human(p._write_per_sec),
 
143
                        p._cmdline)
 
144
        try:
 
145
            print_line(line)
 
146
        except curses.error:
 
147
            break
 
148
    win.refresh()
 
149
 
 
150
def main():
 
151
    try:
 
152
        interval = 0
 
153
        while 1:
 
154
            args = poll(interval)
 
155
            refresh_window(*args) 
 
156
            interval = 1
 
157
    except (KeyboardInterrupt, SystemExit):
 
158
        print
 
159
 
 
160
if __name__ == '__main__':
 
161
    main()