Blame iotop/ui.py

Packit 88fe6f
# This program is free software; you can redistribute it and/or modify
Packit 88fe6f
# it under the terms of the GNU General Public License as published by
Packit 88fe6f
# the Free Software Foundation; either version 2 of the License, or
Packit 88fe6f
# (at your option) any later version.
Packit 88fe6f
#
Packit 88fe6f
# This program is distributed in the hope that it will be useful,
Packit 88fe6f
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 88fe6f
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 88fe6f
# GNU Library General Public License for more details.
Packit 88fe6f
#
Packit 88fe6f
# You should have received a copy of the GNU General Public License
Packit 88fe6f
# along with this program; if not, write to the Free Software
Packit 88fe6f
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
Packit 88fe6f
#
Packit 88fe6f
# See the COPYING file for license information.
Packit 88fe6f
#
Packit 88fe6f
# Copyright (c) 2007 Guillaume Chazarain <guichaz@gmail.com>
Packit 88fe6f
Packit 88fe6f
# Allow printing with same syntax in Python 2/3
Packit 88fe6f
from __future__ import print_function
Packit 88fe6f
Packit 88fe6f
import curses
Packit 88fe6f
import errno
Packit 88fe6f
import locale
Packit 88fe6f
import math
Packit 88fe6f
import optparse
Packit 88fe6f
import os
Packit 88fe6f
import select
Packit 88fe6f
import signal
Packit 88fe6f
import sys
Packit 88fe6f
import time
Packit 88fe6f
Packit 88fe6f
from iotop.data import find_uids, TaskStatsNetlink, ProcessList, Stats
Packit 88fe6f
from iotop.data import ThreadInfo
Packit 88fe6f
from iotop.version import VERSION
Packit 88fe6f
from iotop import ioprio
Packit 88fe6f
from iotop.ioprio import IoprioSetError
Packit 88fe6f
Packit 88fe6f
#
Packit 88fe6f
# Utility functions for the UI
Packit 88fe6f
#
Packit 88fe6f
Packit 88fe6f
UNITS = ['B', 'K', 'M', 'G', 'T', 'P', 'E']
Packit 88fe6f
Packit 88fe6f
def human_size(size):
Packit 88fe6f
    if size > 0:
Packit 88fe6f
        sign = ''
Packit 88fe6f
    elif size < 0:
Packit 88fe6f
        sign = '-'
Packit 88fe6f
        size = -size
Packit 88fe6f
    else:
Packit 88fe6f
        return '0.00 B'
Packit 88fe6f
Packit 88fe6f
    expo = int(math.log(size / 2, 2) / 10)
Packit 88fe6f
    return '%s%.2f %s' % (sign, (float(size) / (1 << (10 * expo))), UNITS[expo])
Packit 88fe6f
Packit 88fe6f
def format_size(options, bytes):
Packit 88fe6f
    if options.kilobytes:
Packit 88fe6f
        return '%.2f K' % (bytes / 1024.0)
Packit 88fe6f
    return human_size(bytes)
Packit 88fe6f
Packit 88fe6f
def format_bandwidth(options, size, duration):
Packit 88fe6f
    return format_size(options, size and float(size) / duration) + '/s'
Packit 88fe6f
Packit 88fe6f
def format_stats(options, process, duration):
Packit 88fe6f
    # Keep in sync with TaskStatsNetlink.members_offsets and
Packit 88fe6f
    # IOTopUI.get_data(self)
Packit 88fe6f
    def delay2percent(delay): # delay in ns, duration in s
Packit 88fe6f
        return '%.2f %%' % min(99.99, delay / (duration * 10000000.0))
Packit 88fe6f
    if options.accumulated:
Packit 88fe6f
        stats = process.stats_accum
Packit 88fe6f
        display_format = lambda size, duration: format_size(options, size)
Packit 88fe6f
        duration = time.time() - process.stats_accum_timestamp
Packit 88fe6f
    else:
Packit 88fe6f
        stats = process.stats_delta
Packit 88fe6f
        display_format = lambda size, duration: format_bandwidth(
Packit 88fe6f
                                                        options, size, duration)
Packit 88fe6f
    io_delay = delay2percent(stats.blkio_delay_total)
Packit 88fe6f
    swapin_delay = delay2percent(stats.swapin_delay_total)
Packit 88fe6f
    read_bytes = display_format(stats.read_bytes, duration)
Packit 88fe6f
    written_bytes = stats.write_bytes - stats.cancelled_write_bytes
Packit 88fe6f
    written_bytes = max(0, written_bytes)
Packit 88fe6f
    write_bytes = display_format(written_bytes, duration)
Packit 88fe6f
    return io_delay, swapin_delay, read_bytes, write_bytes
Packit 88fe6f
Packit 88fe6f
def get_max_pid_width():
Packit 88fe6f
    try:
Packit 88fe6f
        return len(open('/proc/sys/kernel/pid_max').read().strip())
Packit 88fe6f
    except Exception as e:
Packit 88fe6f
        print(e)
Packit 88fe6f
        # Reasonable default in case something fails
Packit 88fe6f
        return 5
Packit 88fe6f
Packit 88fe6f
MAX_PID_WIDTH = get_max_pid_width()
Packit 88fe6f
Packit 88fe6f
#
Packit 88fe6f
# UI Exceptions
Packit 88fe6f
#
Packit 88fe6f
Packit 88fe6f
class CancelInput(Exception): pass
Packit 88fe6f
class InvalidInt(Exception): pass
Packit 88fe6f
class InvalidPid(Exception): pass
Packit 88fe6f
class InvalidTid(Exception): pass
Packit 88fe6f
class InvalidIoprioData(Exception): pass
Packit 88fe6f
Packit 88fe6f
#
Packit 88fe6f
# The UI
Packit 88fe6f
#
Packit 88fe6f
Packit 88fe6f
class IOTopUI(object):
Packit 88fe6f
    # key, reverse
Packit 88fe6f
    sorting_keys = [
Packit 88fe6f
        (lambda p, s: p.pid, False),
Packit 88fe6f
        (lambda p, s: p.ioprio_sort_key(), False),
Packit 88fe6f
        (lambda p, s: p.get_user(), False),
Packit 88fe6f
        (lambda p, s: s.read_bytes, True),
Packit 88fe6f
        (lambda p, s: s.write_bytes - s.cancelled_write_bytes, True),
Packit 88fe6f
        (lambda p, s: s.swapin_delay_total, True),
Packit 88fe6f
        # The default sorting (by I/O % time) should show processes doing
Packit 88fe6f
        # only writes, without waiting on them
Packit 88fe6f
        (lambda p, s: s.blkio_delay_total or
Packit 88fe6f
                      int(not(not(s.read_bytes or s.write_bytes))), True),
Packit 88fe6f
        (lambda p, s: p.get_cmdline(), False),
Packit 88fe6f
    ]
Packit 88fe6f
Packit 88fe6f
    def __init__(self, win, process_list, options):
Packit 88fe6f
        self.process_list = process_list
Packit 88fe6f
        self.options = options
Packit 88fe6f
        self.sorting_key = 6
Packit 88fe6f
        self.sorting_reverse = IOTopUI.sorting_keys[self.sorting_key][1]
Packit 88fe6f
        if not self.options.batch:
Packit 88fe6f
            self.win = win
Packit 88fe6f
            self.resize()
Packit 88fe6f
            try:
Packit 88fe6f
                curses.use_default_colors()
Packit 88fe6f
                curses.start_color()
Packit 88fe6f
                curses.curs_set(0)
Packit 88fe6f
            except curses.error:
Packit 88fe6f
                # This call can fail with misconfigured terminals, for example
Packit 88fe6f
                # TERM=xterm-color. This is harmless
Packit 88fe6f
                pass
Packit 88fe6f
Packit 88fe6f
    def resize(self):
Packit 88fe6f
        self.height, self.width = self.win.getmaxyx()
Packit 88fe6f
Packit 88fe6f
    def run(self):
Packit 88fe6f
        iterations = 0
Packit 88fe6f
        poll = select.poll()
Packit 88fe6f
        if not self.options.batch:
Packit 88fe6f
            poll.register(sys.stdin.fileno(), select.POLLIN|select.POLLPRI)
Packit 88fe6f
        while self.options.iterations is None or \
Packit 88fe6f
              iterations < self.options.iterations:
Packit 88fe6f
            total, actual = self.process_list.refresh_processes()
Packit 88fe6f
            self.refresh_display(iterations == 0, total, actual,
Packit 88fe6f
                                 self.process_list.duration)
Packit 88fe6f
            if self.options.iterations is not None:
Packit 88fe6f
                iterations += 1
Packit 88fe6f
                if iterations >= self.options.iterations:
Packit 88fe6f
                    break
Packit 88fe6f
            elif iterations == 0:
Packit 88fe6f
                iterations = 1
Packit 88fe6f
Packit 88fe6f
            try:
Packit 88fe6f
                events = poll.poll(self.options.delay_seconds * 1000.0)
Packit 88fe6f
            except select.error as e:
Packit 88fe6f
                if e.args and e.args[0] == errno.EINTR:
Packit 88fe6f
                    events = []
Packit 88fe6f
                else:
Packit 88fe6f
                    raise
Packit 88fe6f
            for (fd, event) in events:
Packit 88fe6f
                if event & (select.POLLERR | select.POLLHUP):
Packit 88fe6f
                    sys.exit(1)
Packit 88fe6f
            if not self.options.batch:
Packit 88fe6f
                self.resize()
Packit 88fe6f
            if events:
Packit 88fe6f
                key = self.win.getch()
Packit 88fe6f
                self.handle_key(key)
Packit 88fe6f
Packit 88fe6f
    def reverse_sorting(self):
Packit 88fe6f
        self.sorting_reverse = not self.sorting_reverse
Packit 88fe6f
Packit 88fe6f
    def adjust_sorting_key(self, delta):
Packit 88fe6f
        orig_sorting_key = self.sorting_key
Packit 88fe6f
        self.sorting_key += delta
Packit 88fe6f
        self.sorting_key = max(0, self.sorting_key)
Packit 88fe6f
        self.sorting_key = min(len(IOTopUI.sorting_keys) - 1, self.sorting_key)
Packit 88fe6f
        if orig_sorting_key != self.sorting_key:
Packit 88fe6f
            self.sorting_reverse = IOTopUI.sorting_keys[self.sorting_key][1]
Packit 88fe6f
Packit 88fe6f
    # I wonder if switching to urwid for the display would be better here
Packit 88fe6f
Packit 88fe6f
    def prompt_str(self, prompt, default=None, empty_is_cancel=True):
Packit 88fe6f
        self.win.hline(1, 0, ord(' ') | curses.A_NORMAL, self.width)
Packit 88fe6f
        self.win.addstr(1, 0, prompt, curses.A_BOLD)
Packit 88fe6f
        self.win.refresh()
Packit 88fe6f
        curses.echo()
Packit 88fe6f
        curses.curs_set(1)
Packit 88fe6f
        inp = self.win.getstr(1, len(prompt))
Packit 88fe6f
        curses.curs_set(0)
Packit 88fe6f
        curses.noecho()
Packit 88fe6f
        if inp not in (None, ''):
Packit 88fe6f
            return inp
Packit 88fe6f
        if empty_is_cancel:
Packit 88fe6f
            raise CancelInput()
Packit 88fe6f
        return default
Packit 88fe6f
Packit 88fe6f
    def prompt_int(self, prompt, default = None, empty_is_cancel = True):
Packit 88fe6f
        inp = self.prompt_str(prompt, default, empty_is_cancel)
Packit 88fe6f
        try:
Packit 88fe6f
            return int(inp)
Packit 88fe6f
        except ValueError:
Packit 88fe6f
            raise InvalidInt()
Packit 88fe6f
Packit 88fe6f
    def prompt_pid(self):
Packit 88fe6f
        try:
Packit 88fe6f
            return self.prompt_int('PID to ionice: ')
Packit 88fe6f
        except InvalidInt:
Packit 88fe6f
            raise InvalidPid()
Packit 88fe6f
        except CancelInput:
Packit 88fe6f
            raise
Packit 88fe6f
Packit 88fe6f
    def prompt_tid(self):
Packit 88fe6f
        try:
Packit 88fe6f
            return self.prompt_int('TID to ionice: ')
Packit 88fe6f
        except InvalidInt:
Packit 88fe6f
            raise InvalidTid()
Packit 88fe6f
        except CancelInput:
Packit 88fe6f
            raise
Packit 88fe6f
Packit 88fe6f
    def prompt_data(self, ioprio_data):
Packit 88fe6f
        try:
Packit 88fe6f
            if ioprio_data is not None:
Packit 88fe6f
                inp = self.prompt_int('I/O priority data (0-7, currently %s): '
Packit 88fe6f
                                      % ioprio_data, ioprio_data, False)
Packit 88fe6f
            else:
Packit 88fe6f
                inp = self.prompt_int('I/O priority data (0-7): ', None, False)
Packit 88fe6f
        except InvalidInt:
Packit 88fe6f
            raise InvalidIoprioData()
Packit 88fe6f
        if inp < 0 or inp > 7:
Packit 88fe6f
            raise InvalidIoprioData()
Packit 88fe6f
        return inp
Packit 88fe6f
Packit 88fe6f
    def prompt_set(self, prompt, display_list, ret_list, selected):
Packit 88fe6f
        try:
Packit 88fe6f
            selected = ret_list.index(selected)
Packit 88fe6f
        except ValueError:
Packit 88fe6f
            selected = -1
Packit 88fe6f
        set_len = len(display_list) - 1
Packit 88fe6f
        while True:
Packit 88fe6f
            self.win.hline(1, 0, ord(' ') | curses.A_NORMAL, self.width)
Packit 88fe6f
            self.win.insstr(1, 0, prompt, curses.A_BOLD)
Packit 88fe6f
            offset = len(prompt)
Packit 88fe6f
            for i, item in enumerate(display_list):
Packit 88fe6f
                display = ' %s ' % item
Packit 88fe6f
                if i is selected:
Packit 88fe6f
                    attr = curses.A_REVERSE
Packit 88fe6f
                else:
Packit 88fe6f
                    attr = curses.A_NORMAL
Packit 88fe6f
                self.win.insstr(1, offset, display, attr)
Packit 88fe6f
                offset += len(display)
Packit 88fe6f
            while True:
Packit 88fe6f
                key = self.win.getch()
Packit 88fe6f
                if key in (curses.KEY_LEFT, ord('l')) and selected > 0:
Packit 88fe6f
                    selected -= 1
Packit 88fe6f
                    break
Packit 88fe6f
                elif key in (curses.KEY_RIGHT, ord('r')) and selected < set_len:
Packit 88fe6f
                    selected += 1
Packit 88fe6f
                    break
Packit 88fe6f
                elif key in (curses.KEY_ENTER, ord('\n'), ord('\r')):
Packit 88fe6f
                    return ret_list[selected]
Packit 88fe6f
                elif key in (27, curses.KEY_CANCEL, curses.KEY_CLOSE,
Packit 88fe6f
                             curses.KEY_EXIT, ord('q'), ord('Q')):
Packit 88fe6f
                    raise CancelInput()
Packit 88fe6f
Packit 88fe6f
    def prompt_class(self, ioprio_class=None):
Packit 88fe6f
        prompt = 'I/O priority class: '
Packit 88fe6f
        classes_prompt = ['Real-time', 'Best-effort', 'Idle']
Packit 88fe6f
        classes_ret = ['rt', 'be', 'idle']
Packit 88fe6f
        if ioprio_class is None:
Packit 88fe6f
            ioprio_class = 2
Packit 88fe6f
        inp = self.prompt_set(prompt, classes_prompt, classes_ret, ioprio_class)
Packit 88fe6f
        return inp
Packit 88fe6f
Packit 88fe6f
    def prompt_error(self, error = 'Error!'):
Packit 88fe6f
        self.win.hline(1, 0, ord(' ') | curses.A_NORMAL, self.width)
Packit 88fe6f
        self.win.insstr(1, 0, '  %s  ' % error, curses.A_REVERSE)
Packit 88fe6f
        self.win.refresh()
Packit 88fe6f
        time.sleep(1)
Packit 88fe6f
Packit 88fe6f
    def prompt_clear(self):
Packit 88fe6f
        self.win.hline(1, 0, ord(' ') | curses.A_NORMAL, self.width)
Packit 88fe6f
        self.win.refresh()
Packit 88fe6f
Packit 88fe6f
    def handle_key(self, key):
Packit 88fe6f
        def toggle_accumulated():
Packit 88fe6f
            self.options.accumulated ^= True
Packit 88fe6f
        def toggle_only_io():
Packit 88fe6f
            self.options.only ^= True
Packit 88fe6f
        def toggle_processes():
Packit 88fe6f
            self.options.processes ^= True
Packit 88fe6f
            self.process_list.clear()
Packit 88fe6f
            self.process_list.refresh_processes()
Packit 88fe6f
        def ionice():
Packit 88fe6f
            try:
Packit 88fe6f
                if self.options.processes:
Packit 88fe6f
                    pid = self.prompt_pid()
Packit 88fe6f
                    exec_unit = self.process_list.get_process(pid)
Packit 88fe6f
                else:
Packit 88fe6f
                    tid = self.prompt_tid()
Packit 88fe6f
                    exec_unit = ThreadInfo(tid,
Packit 88fe6f
                                         self.process_list.taskstats_connection)
Packit 88fe6f
                ioprio_value = exec_unit.get_ioprio()
Packit 88fe6f
                (ioprio_class, ioprio_data) = \
Packit 88fe6f
                                          ioprio.to_class_and_data(ioprio_value)
Packit 88fe6f
                ioprio_class = self.prompt_class(ioprio_class)
Packit 88fe6f
                if ioprio_class == 'idle':
Packit 88fe6f
                    ioprio_data = 0
Packit 88fe6f
                else:
Packit 88fe6f
                    ioprio_data = self.prompt_data(ioprio_data)
Packit 88fe6f
                exec_unit.set_ioprio(ioprio_class, ioprio_data)
Packit 88fe6f
                self.process_list.clear()
Packit 88fe6f
                self.process_list.refresh_processes()
Packit 88fe6f
            except IoprioSetError as e:
Packit 88fe6f
                self.prompt_error('Error setting I/O priority: %s' % e.err)
Packit 88fe6f
            except InvalidPid:
Packit 88fe6f
                self.prompt_error('Invalid process id!')
Packit 88fe6f
            except InvalidTid:
Packit 88fe6f
                self.prompt_error('Invalid thread id!')
Packit 88fe6f
            except InvalidIoprioData:
Packit 88fe6f
                self.prompt_error('Invalid I/O priority data!')
Packit 88fe6f
            except InvalidInt:
Packit 88fe6f
                self.prompt_error('Invalid integer!')
Packit 88fe6f
            except CancelInput:
Packit 88fe6f
                self.prompt_clear()
Packit 88fe6f
            else:
Packit 88fe6f
                self.prompt_clear()
Packit 88fe6f
Packit 88fe6f
        key_bindings = {
Packit 88fe6f
            ord('q'):
Packit 88fe6f
                lambda: sys.exit(0),
Packit 88fe6f
            ord('Q'):
Packit 88fe6f
                lambda: sys.exit(0),
Packit 88fe6f
            ord('r'):
Packit 88fe6f
                lambda: self.reverse_sorting(),
Packit 88fe6f
            ord('R'):
Packit 88fe6f
                lambda: self.reverse_sorting(),
Packit 88fe6f
            ord('a'):
Packit 88fe6f
                toggle_accumulated,
Packit 88fe6f
            ord('A'):
Packit 88fe6f
                toggle_accumulated,
Packit 88fe6f
            ord('o'):
Packit 88fe6f
                toggle_only_io,
Packit 88fe6f
            ord('O'):
Packit 88fe6f
                toggle_only_io,
Packit 88fe6f
            ord('p'):
Packit 88fe6f
                toggle_processes,
Packit 88fe6f
            ord('P'):
Packit 88fe6f
                toggle_processes,
Packit 88fe6f
            ord('i'):
Packit 88fe6f
                ionice,
Packit 88fe6f
            ord('I'):
Packit 88fe6f
                ionice,
Packit 88fe6f
            curses.KEY_LEFT:
Packit 88fe6f
                lambda: self.adjust_sorting_key(-1),
Packit 88fe6f
            curses.KEY_RIGHT:
Packit 88fe6f
                lambda: self.adjust_sorting_key(1),
Packit 88fe6f
            curses.KEY_HOME:
Packit 88fe6f
                lambda: self.adjust_sorting_key(-len(IOTopUI.sorting_keys)),
Packit 88fe6f
            curses.KEY_END:
Packit 88fe6f
                lambda: self.adjust_sorting_key(len(IOTopUI.sorting_keys))
Packit 88fe6f
        }
Packit 88fe6f
Packit 88fe6f
        action = key_bindings.get(key, lambda: None)
Packit 88fe6f
        action()
Packit 88fe6f
Packit 88fe6f
    def get_data(self):
Packit 88fe6f
        def format(p):
Packit 88fe6f
            stats = format_stats(self.options, p, self.process_list.duration)
Packit 88fe6f
            io_delay, swapin_delay, read_bytes, write_bytes = stats
Packit 88fe6f
            if Stats.has_blkio_delay_total:
Packit 88fe6f
                delay_stats = '%7s %7s ' % (swapin_delay, io_delay)
Packit 88fe6f
            else:
Packit 88fe6f
                delay_stats = ' ?unavailable?  '
Packit 88fe6f
            pid_format = '%%%dd' % MAX_PID_WIDTH
Packit 88fe6f
            line = (pid_format + ' %4s %-8s %11s %11s %s') % (
Packit 88fe6f
                p.pid, p.get_ioprio(), p.get_user()[:8], read_bytes,
Packit 88fe6f
                write_bytes, delay_stats)
Packit 88fe6f
            cmdline = p.get_cmdline()
Packit 88fe6f
            if not self.options.batch:
Packit 88fe6f
                remaining_length = self.width - len(line)
Packit 88fe6f
                if 2 < remaining_length < len(cmdline):
Packit 88fe6f
                    len1 = (remaining_length - 1) // 2
Packit 88fe6f
                    offset2 = -(remaining_length - len1 - 1)
Packit 88fe6f
                    cmdline = cmdline[:len1] + '~' + cmdline[offset2:]
Packit 88fe6f
            line += cmdline
Packit 88fe6f
            if not self.options.batch:
Packit 88fe6f
                line = line[:self.width]
Packit 88fe6f
            return line
Packit 88fe6f
Packit 88fe6f
        def should_format(p):
Packit 88fe6f
            return not self.options.only or \
Packit 88fe6f
                   p.did_some_io(self.options.accumulated)
Packit 88fe6f
Packit 88fe6f
        processes = list(filter(should_format,
Packit 88fe6f
                                self.process_list.processes.values()))
Packit 88fe6f
        key = IOTopUI.sorting_keys[self.sorting_key][0]
Packit 88fe6f
        if self.options.accumulated:
Packit 88fe6f
            stats_lambda = lambda p: p.stats_accum
Packit 88fe6f
        else:
Packit 88fe6f
            stats_lambda = lambda p: p.stats_delta
Packit 88fe6f
        processes.sort(key=lambda p: key(p, stats_lambda(p)),
Packit 88fe6f
                       reverse=self.sorting_reverse)
Packit 88fe6f
        if not self.options.batch:
Packit 88fe6f
            del processes[self.height - 2:]
Packit 88fe6f
        return list(map(format, processes))
Packit 88fe6f
Packit 88fe6f
    def refresh_display(self, first_time, total, actual, duration):
Packit 88fe6f
        summary = [
Packit 88fe6f
                'Total DISK READ : %s | Total DISK WRITE : %s' % (
Packit 88fe6f
                format_bandwidth(self.options, total[0], duration).rjust(14),
Packit 88fe6f
                format_bandwidth(self.options, total[1], duration).rjust(14)),
Packit 88fe6f
                'Actual DISK READ: %s | Actual DISK WRITE: %s' % (
Packit 88fe6f
                format_bandwidth(self.options, actual[0], duration).rjust(14),
Packit 88fe6f
                format_bandwidth(self.options, actual[1], duration).rjust(14))
Packit 88fe6f
        ]
Packit 88fe6f
Packit 88fe6f
        pid = max(0, (MAX_PID_WIDTH - 3)) * ' '
Packit 88fe6f
        if self.options.processes:
Packit 88fe6f
            pid += 'PID'
Packit 88fe6f
        else:
Packit 88fe6f
            pid += 'TID'
Packit 88fe6f
        titles = [pid, '  PRIO', '  USER', '     DISK READ', '  DISK WRITE',
Packit 88fe6f
                  '  SWAPIN', '      IO', '    COMMAND']
Packit 88fe6f
        lines = self.get_data()
Packit 88fe6f
        if self.options.time:
Packit 88fe6f
            titles = ['    TIME'] + titles
Packit 88fe6f
            current_time = time.strftime('%H:%M:%S ')
Packit 88fe6f
            lines = [current_time + l for l in lines]
Packit 88fe6f
            summary = [current_time + s for s in summary]
Packit 88fe6f
        if self.options.batch:
Packit 88fe6f
            if self.options.quiet <= 2:
Packit 88fe6f
                for s in summary:
Packit 88fe6f
                    print(s)
Packit 88fe6f
                if self.options.quiet <= int(first_time):
Packit 88fe6f
                    print(''.join(titles))
Packit 88fe6f
            for l in lines:
Packit 88fe6f
                print(l)
Packit 88fe6f
            sys.stdout.flush()
Packit 88fe6f
        else:
Packit 88fe6f
            self.win.erase()
Packit 88fe6f
            for i, s in enumerate(summary):
Packit 88fe6f
                self.win.addstr(i, 0, s[:self.width])
Packit 88fe6f
            self.win.hline(len(summary), 0, ord(' ') | curses.A_REVERSE,
Packit 88fe6f
                           self.width)
Packit 88fe6f
            remaining_cols = self.width
Packit 88fe6f
            for i in range(len(titles)):
Packit 88fe6f
                attr = curses.A_REVERSE
Packit 88fe6f
                title = titles[i]
Packit 88fe6f
                if i == self.sorting_key:
Packit 88fe6f
                    title = title[1:]
Packit 88fe6f
                if i == self.sorting_key:
Packit 88fe6f
                    attr |= curses.A_BOLD
Packit 88fe6f
                    title += self.sorting_reverse and '>' or '<'
Packit 88fe6f
                title = title[:remaining_cols]
Packit 88fe6f
                remaining_cols -= len(title)
Packit 88fe6f
                self.win.addstr(title, attr)
Packit 88fe6f
            if Stats.has_blkio_delay_total:
Packit 88fe6f
                status_msg = None
Packit 88fe6f
            else:
Packit 88fe6f
                status_msg = ('CONFIG_TASK_DELAY_ACCT not enabled in kernel, '
Packit 88fe6f
                              'cannot determine SWAPIN and IO %')
Packit 88fe6f
            num_lines = min(len(lines), self.height - 2 - int(bool(status_msg)))
Packit 88fe6f
            for i in range(num_lines):
Packit 88fe6f
                try:
Packit 88fe6f
                    def print_line(line):
Packit 88fe6f
                        self.win.addstr(i + len(summary) + 1, 0, line)
Packit 88fe6f
                    try:
Packit 88fe6f
                        print_line(lines[i])
Packit 88fe6f
                    except UnicodeEncodeError:
Packit 88fe6f
                        # Python2: 'ascii' codec can't encode character ...
Packit 88fe6f
                        # http://bugs.debian.org/708252
Packit 88fe6f
                        print_line(lines[i].encode('utf-8'))
Packit 88fe6f
                except curses.error:
Packit 88fe6f
                    pass
Packit 88fe6f
            if status_msg:
Packit 88fe6f
                self.win.insstr(self.height - len(summary), 0, status_msg,
Packit 88fe6f
                                curses.A_BOLD)
Packit 88fe6f
            self.win.refresh()
Packit 88fe6f
Packit 88fe6f
def run_iotop_window(win, options):
Packit 88fe6f
    if options.batch:
Packit 88fe6f
        signal.signal(signal.SIGPIPE, signal.SIG_DFL)
Packit 88fe6f
    else:
Packit 88fe6f
        def clean_exit(*args, **kwargs):
Packit 88fe6f
            sys.exit(0)
Packit 88fe6f
        signal.signal(signal.SIGINT, clean_exit)
Packit 88fe6f
        signal.signal(signal.SIGTERM, clean_exit)
Packit 88fe6f
    taskstats_connection = TaskStatsNetlink(options)
Packit 88fe6f
    process_list = ProcessList(taskstats_connection, options)
Packit 88fe6f
    ui = IOTopUI(win, process_list, options)
Packit 88fe6f
    ui.run()
Packit 88fe6f
Packit 88fe6f
def run_iotop(options):
Packit 88fe6f
    try:
Packit 88fe6f
        if options.batch:
Packit 88fe6f
            return run_iotop_window(None, options)
Packit 88fe6f
        else:
Packit 88fe6f
            return curses.wrapper(run_iotop_window, options)
Packit 88fe6f
    except OSError as e:
Packit 88fe6f
        if e.errno == errno.EPERM:
Packit 88fe6f
            print(e, file=sys.stderr)
Packit 88fe6f
            print('''
Packit 88fe6f
The Linux kernel interfaces that iotop relies on now require root priviliges
Packit 88fe6f
or the NET_ADMIN capability. This change occured because a security issue
Packit 88fe6f
(CVE-2011-2494) was found that allows leakage of sensitive data across user
Packit 88fe6f
boundaries. If you require the ability to run iotop as a non-root user, please
Packit 88fe6f
configure sudo to allow you to run iotop as root.
Packit 88fe6f
Packit 88fe6f
Please do not file bugs on iotop about this.''', file=sys.stderr)
Packit 88fe6f
            sys.exit(1)
Packit 88fe6f
        else:
Packit 88fe6f
            raise
Packit 9a3822
    except curses.error as e:
Packit 9a3822
        stre = str(e)
Packit 9a3822
        if stre.find('ERR')>=0 and (
Packit 9a3822
            stre.find('nocbreak()')>=0 or stre.find('endwin()')>=0
Packit 9a3822
            ):
Packit 9a3822
            pass
Packit 9a3822
            # endwin and nocbreak can cause error (and raise hard to catch 
Packit 9a3822
            # exception) if iotop was running in the terminal and that 
Packit 9a3822
            # terminal got closed while iotop was still running
Packit 9a3822
        else:
Packit 9a3822
            raise
Packit 88fe6f
Packit 88fe6f
#
Packit 88fe6f
# Profiling
Packit 88fe6f
#
Packit 88fe6f
Packit 88fe6f
def _profile(continuation):
Packit 88fe6f
    prof_file = 'iotop.prof'
Packit 88fe6f
    try:
Packit 88fe6f
        import cProfile
Packit 88fe6f
        import pstats
Packit 88fe6f
        print('Profiling using cProfile')
Packit 88fe6f
        cProfile.runctx('continuation()', globals(), locals(), prof_file)
Packit 88fe6f
        stats = pstats.Stats(prof_file)
Packit 88fe6f
    except ImportError:
Packit 88fe6f
        import hotshot
Packit 88fe6f
        import hotshot.stats
Packit 88fe6f
        prof = hotshot.Profile(prof_file, lineevents=1)
Packit 88fe6f
        print('Profiling using hotshot')
Packit 88fe6f
        prof.runcall(continuation)
Packit 88fe6f
        prof.close()
Packit 88fe6f
        stats = hotshot.stats.load(prof_file)
Packit 88fe6f
    stats.strip_dirs()
Packit 88fe6f
    stats.sort_stats('time', 'calls')
Packit 88fe6f
    stats.print_stats(50)
Packit 88fe6f
    stats.print_callees(50)
Packit 88fe6f
    os.remove(prof_file)
Packit 88fe6f
Packit 88fe6f
#
Packit 88fe6f
# Main program
Packit 88fe6f
#
Packit 88fe6f
Packit 88fe6f
USAGE = '''%s [OPTIONS]
Packit 88fe6f
Packit 88fe6f
DISK READ and DISK WRITE are the block I/O bandwidth used during the sampling
Packit 88fe6f
period. SWAPIN and IO are the percentages of time the thread spent respectively
Packit 88fe6f
while swapping in and waiting on I/O more generally. PRIO is the I/O priority at
Packit 88fe6f
which the thread is running (set using the ionice command).
Packit 88fe6f
Packit 88fe6f
Controls: left and right arrows to change the sorting column, r to invert the
Packit 88fe6f
sorting order, o to toggle the --only option, p to toggle the --processes
Packit 88fe6f
option, a to toggle the --accumulated option, i to change I/O priority, q to
Packit 88fe6f
quit, any other key to force a refresh.''' % sys.argv[0]
Packit 88fe6f
Packit 88fe6f
def main():
Packit 88fe6f
    try:
Packit 88fe6f
        locale.setlocale(locale.LC_ALL, '')
Packit 88fe6f
    except locale.Error:
Packit 88fe6f
        print('unable to set locale, falling back to the default locale')
Packit 88fe6f
    parser = optparse.OptionParser(usage=USAGE, version='iotop ' + VERSION)
Packit 88fe6f
    parser.add_option('-o', '--only', action='store_true',
Packit 88fe6f
                      dest='only', default=False,
Packit 88fe6f
                      help='only show processes or threads actually doing I/O')
Packit 88fe6f
    parser.add_option('-b', '--batch', action='store_true', dest='batch',
Packit 88fe6f
                      help='non-interactive mode')
Packit 88fe6f
    parser.add_option('-n', '--iter', type='int', dest='iterations',
Packit 88fe6f
                      metavar='NUM',
Packit 88fe6f
                      help='number of iterations before ending [infinite]')
Packit 88fe6f
    parser.add_option('-d', '--delay', type='float', dest='delay_seconds',
Packit 88fe6f
                      help='delay between iterations [1 second]',
Packit 88fe6f
                      metavar='SEC', default=1)
Packit 88fe6f
    parser.add_option('-p', '--pid', type='int', dest='pids', action='append',
Packit 88fe6f
                      help='processes/threads to monitor [all]', metavar='PID')
Packit 88fe6f
    parser.add_option('-u', '--user', type='str', dest='users', action='append',
Packit 88fe6f
                      help='users to monitor [all]', metavar='USER')
Packit 88fe6f
    parser.add_option('-P', '--processes', action='store_true',
Packit 88fe6f
                      dest='processes', default=False,
Packit 88fe6f
                      help='only show processes, not all threads')
Packit 88fe6f
    parser.add_option('-a', '--accumulated', action='store_true',
Packit 88fe6f
                      dest='accumulated', default=False,
Packit 88fe6f
                      help='show accumulated I/O instead of bandwidth')
Packit 88fe6f
    parser.add_option('-k', '--kilobytes', action='store_true',
Packit 88fe6f
                      dest='kilobytes', default=False,
Packit 88fe6f
                      help='use kilobytes instead of a human friendly unit')
Packit 88fe6f
    parser.add_option('-t', '--time', action='store_true', dest='time',
Packit 88fe6f
                      help='add a timestamp on each line (implies --batch)')
Packit 88fe6f
    parser.add_option('-q', '--quiet', action='count', dest='quiet', default=0,
Packit 88fe6f
                      help='suppress some lines of header (implies --batch)')
Packit 88fe6f
    parser.add_option('--profile', action='store_true', dest='profile',
Packit 88fe6f
                      default=False, help=optparse.SUPPRESS_HELP)
Packit 88fe6f
Packit 88fe6f
    options, args = parser.parse_args()
Packit 88fe6f
    if args:
Packit 88fe6f
        parser.error('Unexpected arguments: ' + ' '.join(args))
Packit 88fe6f
    find_uids(options)
Packit 88fe6f
    options.pids = options.pids or []
Packit 88fe6f
    options.batch = options.batch or options.time or options.quiet
Packit 88fe6f
Packit 88fe6f
    main_loop = lambda: run_iotop(options)
Packit 88fe6f
Packit 88fe6f
    if options.profile:
Packit 88fe6f
        def safe_main_loop():
Packit 88fe6f
            try:
Packit 88fe6f
                main_loop()
Packit 88fe6f
            except:
Packit 88fe6f
                pass
Packit 88fe6f
        _profile(safe_main_loop)
Packit 88fe6f
    else:
Packit 88fe6f
        main_loop()
Packit 88fe6f