Hello community, here is the log from the commit of package iotop for openSUSE:Factory checked in at 2013-03-25 20:30:57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/iotop (Old) and /work/SRC/openSUSE:Factory/.iotop.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "iotop", Maintainer is "pth@suse.com" Changes: -------- --- /work/SRC/openSUSE:Factory/iotop/iotop.changes 2011-11-02 11:54:05.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.iotop.new/iotop.changes 2013-03-25 20:31:31.000000000 +0100 @@ -1,0 +2,9 @@ +Sun Mar 3 07:44:09 UTC 2013 - zaitor@opensuse.org + +- Update to version 0.5: + + Adapt the display to the maximum pid width. + + Include both total and actual disk bandwidth in the summary. + + Conversion to Python 3. + + Installation to sbin instead of bin. + +------------------------------------------------------------------- Old: ---- iotop-0.4.4.tar.bz2 New: ---- iotop-0.5.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ iotop.spec ++++++ --- /var/tmp/diff_new_pack.FSeEBM/_old 2013-03-25 20:31:32.000000000 +0100 +++ /var/tmp/diff_new_pack.FSeEBM/_new 2013-03-25 20:31:32.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package iotop # -# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,16 +19,16 @@ %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} Name: iotop -Version: 0.4.4 -Release: 1 +Version: 0.5 +Release: 0 Summary: Top Like UI to Show Per-Process I/O Going on +License: GPL-2.0 +Group: System/Monitoring Source: http://guichaz.free.fr/iotop/files/iotop-%{version}.tar.bz2 Source1: %{name}-rpmlintrc Url: http://guichaz.free.fr/iotop/ -Group: System/Monitoring -License: GPL-2.0 BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildRequires: python-devel >= 2.5 +BuildRequires: python-devel >= 2.7 Requires: python-curses %if 0%{?suse_version} >= 1120 BuildArch: noarch ++++++ iotop-0.4.4.tar.bz2 -> iotop-0.5.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/.gitignore new/iotop-0.5/.gitignore --- old/iotop-0.4.4/.gitignore 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/.gitignore 2013-02-03 19:50:02.000000000 +0100 @@ -1 +1,2 @@ *.pyc +/build/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/ChangeLog new/iotop-0.5/ChangeLog --- old/iotop-0.4.4/ChangeLog 2011-10-30 21:56:10.000000000 +0100 +++ new/iotop-0.5/ChangeLog 2013-02-03 20:12:50.000000000 +0100 @@ -1,3 +1,120 @@ +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * README, iotop/data.py: Update python requirements + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * NEWS: Also advertise the move to sbin/ as it's significant + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * .install-rpm.sh: The RPM should also install to sbin. + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * bin/iotop, sbin/iotop: Moved to sbin. + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * .install-rpm.sh, MANIFEST.in: Finish man page renaming + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * NEWS, iotop/version.py: Version bump + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * NEWS, THANKS: Advertise the newly introduced differentiation + between total and actual I/O. + +2013-02-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/ui.py: 80 cols + +2012-10-10 Igor Bazhitov <ibazhitov@parallels.com> + + * iotop.8, iotop/data.py, iotop/ui.py: Add 'Actual' bandwidth stats + to summary header 'Total' values in the summary header may look confusing to users. + They represent actual kernel <-> disk I/O bandwidth, while + individual values for processes/threads show process <-> kernel I/O + bandwidth. Rename 'Total' to 'Actual' and add old 'Total' status line that sums + up all individual process/thread bandwidths. Explain the difference + between 'Total' and 'Actual' in the manpage. + +2012-10-09 Igor Bazhitov <ibazhitov@parallels.com> + + * README: Update manpage name in README + +2012-12-05 Paul Wise <pabs3@bonedaddy.net> + + * iotop/data.py: Fix crash when running under python3. This reverts cd6ffb5913664844290f44a7ea48533caf8c459e Traceback (most recent call last): File "./iotop.py", line 12, in <module> main() File "./iotop/iotop/ui.py", line 597, in main main_loop() File "./iotop/iotop/ui.py", line 587, in <lambda> main_loop = lambda: run_iotop(options) File "./iotop/iotop/ui.py", line 485, in run_iotop return curses.wrapper(run_iotop_window, options) File "/usr/lib/python3.2/curses/wrapper.py", line 43, in wrapper return func(stdscr, *args, **kwds) File "./iotop/iotop/ui.py", line 478, in run_iotop_window ui.run() File "./iotop/iotop/ui.py", line 153, in run total = self.process_list.refresh_processes() File "./iotop/iotop/data.py", line 459, in refresh_processes self.processes.items() if File "./iotop/iotop/data.py", line 460, in <listcomp> process.update_stats()]) File "./iotop/iotop/data.py", line 358, in update_stats for tid, thread in self.threads.items(): RuntimeError: + dictionary changed size during iteration [This is valid since 0fc4ab84c8cbba1fbe83dc71fb89100b87c54898 added the self.threads = dict(...)] + +2012-09-02 Paul Wise <pabs3@bonedaddy.net> + + * iotop.1, iotop.8, setup.py: Move iotop out of the path for users + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/ui.py: Fix the setting of the I/O priority and advertise it + a litle more. + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/ui.py: Here we print a string, not bytes. + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/netlink.py: Remove stray print added during the python3 + conversion. + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/data.py: Restore compatibility with python2 + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/data.py: Put back code deleted in the python3 conversion + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/data.py: Some missed python3 conversions + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/data.py, iotop/ui.py: Cosmetic fixes + +2012-09-02 Paul Wise <pabs3@bonedaddy.net> + + * iotop/data.py, iotop/genetlink.py, iotop/ioprio.py, + iotop/netlink.py, iotop/ui.py: Port to Python 3 Not entirely sure about all parts of this but it works in Python 2/3 + +2012-09-03 Guillaume Chazarain <guichaz@gmail.com> + + * THANKS, iotop/data.py: Show custom thread names. + +2012-05-13 Paul Wise <pabs3@bonedaddy.net> + + * iotop/ui.py: Improve the message that is printed when Linux denies + access to taskstats. + +2012-03-08 Guillaume Chazarain <guichaz@gmail.com> + + * README: Consistent option names + +2012-01-22 Guillaume Chazarain <guichaz@gmail.com> + + * iotop/ui.py: Restore the default SIGPIPE handler so that sudo + ./iotop.py -b|head does what's expected. + +2012-01-22 Guillaume Chazarain <guichaz@gmail.com> + + * NEWS, iotop/ui.py: Adapt the display to the maximum pid width + +2012-01-18 Guillaume Chazarain <guichaz@gmail.com> + + * .gitignore: Ignore the build directory. + 2011-10-30 Guillaume Chazarain <guichaz@gmail.com> * .install-rpm.sh, setup.cfg: Actually install-rpm.sh is still diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/NEWS new/iotop-0.5/NEWS --- old/iotop-0.4.4/NEWS 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/NEWS 2013-02-03 19:50:02.000000000 +0100 @@ -1,3 +1,10 @@ +0.5 +~~~ +o Adapt the display to the maximum pid width +o Include both total and actual disk bandwidth in the summary +o Conversion to Python 3 +o Installation to sbin instead of bin + 0.4.4 ~~~~~ o Cosmetic fixes, including a better error message when missing root diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/PKG-INFO new/iotop-0.5/PKG-INFO --- old/iotop-0.4.4/PKG-INFO 2011-10-30 21:56:10.000000000 +0100 +++ new/iotop-0.5/PKG-INFO 2013-02-03 20:12:50.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: iotop -Version: 0.4.4 +Version: 0.5 Summary: Per process I/O bandwidth monitor Home-page: http://guichaz.free.fr/iotop Author: Guillaume Chazarain diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/README new/iotop-0.5/README --- old/iotop-0.4.4/README 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/README 2013-02-03 19:50:02.000000000 +0100 @@ -1,7 +1,7 @@ Iotop is a Python program with a top like UI used to show of behalf of which -process is the I/O going on. It requires Python >= 2.5 (or Python >= 2.4 with -the ctypes module) and a Linux kernel >= 2.6.20 with the TASK_DELAY_ACCT -CONFIG_TASKSTATS, TASK_IO_ACCOUNTING and CONFIG_VM_EVENT_COUNTERS options on. +process is the I/O going on. It requires Python >= 2.7 and a Linux kernel >= +2.6.20 with the CONFIG_TASK_DELAY_ACCT CONFIG_TASKSTATS, +CONFIG_TASK_IO_ACCOUNTING and CONFIG_VM_EVENT_COUNTERS options on. To run a local version of iotop: @@ -11,7 +11,7 @@ The documentation is available in the man page: -$ man ./iotop.1 +$ man ./iotop.8 To install iotop, you should use a package provided by your distribution. If you diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/THANKS new/iotop-0.5/THANKS --- old/iotop-0.4.4/THANKS 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/THANKS 2013-02-03 19:50:02.000000000 +0100 @@ -42,3 +42,9 @@ Florian Mickler <florian@mickler.org> Contributed a fixed implementation of the taskstats parsing code. + +Ka-Hing Cheung <kcheung@riverbed.com> + Contributed code to show custom thread names. + +Igor Bazhitov <ibazhitov@parallels.com> + Contributed the differentiation between total and actual I/O. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/bin/iotop new/iotop-0.5/bin/iotop --- old/iotop-0.4.4/bin/iotop 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/bin/iotop 1970-01-01 01:00:00.000000000 +0100 @@ -1,19 +0,0 @@ -#!/usr/bin/python -# iotop: Display I/O usage of processes in a top like UI -# Copyright (c) 2007, 2008 Guillaume Chazarain <guichaz@gmail.com>, GPLv2 -# See iotop --help for some help - -import sys - -try: - from iotop.ui import main -except ImportError, e: - print e - print 'To run an uninstalled copy of iotop,' - print 'launch iotop.py in the top directory' -else: - try: - main() - except KeyboardInterrupt: - pass - sys.exit(0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/data.py new/iotop-0.5/iotop/data.py --- old/iotop-0.4.4/iotop/data.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/data.py 2013-02-03 19:50:02.000000000 +0100 @@ -16,6 +16,9 @@ # # Copyright (c) 2007 Guillaume Chazarain <guichaz@gmail.com> +# Allow printing with same syntax in Python 2/3 +from __future__ import print_function + import errno import os import pprint @@ -28,19 +31,11 @@ # # Check for requirements: # o Linux >= 2.6.20 with I/O accounting and VM event counters -# o Python >= 2.5 or Python 2.4 + ctypes # ioaccounting = os.path.exists('/proc/self/io') try: - import ctypes -except ImportError: - has_ctypes = False -else: - has_ctypes = True - -try: from iotop.vmstat import VmStat vmstat_f = VmStat() except: @@ -48,24 +43,20 @@ else: vm_event_counters = True -if not ioaccounting or not has_ctypes or not vm_event_counters: - print 'Could not run iotop as some of the requirements are not met:' - if not ioaccounting or not vm_event_counters: - print '- Linux >= 2.6.20 with' - if not ioaccounting: - print ' - I/O accounting support ' \ - '(CONFIG_TASKSTATS, CONFIG_TASK_DELAY_ACCT, ' \ - 'CONFIG_TASK_IO_ACCOUNTING)' - if not vm_event_counters: - print ' - VM event counters (CONFIG_VM_EVENT_COUNTERS)' - if not has_ctypes: - print '- Python >= 2.5 or Python 2.4 with the ctypes module' - +if not ioaccounting or not vm_event_counters: + print('Could not run iotop as some of the requirements are not met:') + print('- Linux >= 2.6.20 with') + if not ioaccounting: + print(' - I/O accounting support ' \ + '(CONFIG_TASKSTATS, CONFIG_TASK_DELAY_ACCT, ' \ + 'CONFIG_TASK_IO_ACCOUNTING)') + if not vm_event_counters: + print(' - VM event counters (CONFIG_VM_EVENT_COUNTERS)') sys.exit(1) from iotop import ioprio, vmstat -from netlink import Connection, NETLINK_GENERIC, U32Attr, NLM_F_REQUEST -from genetlink import Controller, GeNlMessage +from iotop.netlink import Connection, NETLINK_GENERIC, U32Attr, NLM_F_REQUEST +from iotop.genetlink import Controller, GeNlMessage class DumpableObject(object): """Base class for all objects that allows easy introspection when printed""" @@ -154,12 +145,12 @@ thread.task_stats_request.send(self.connection) try: reply = GeNlMessage.recv(self.connection) - except OSError, e: + except OSError as e: if e.errno == errno.ESRCH: # OSError: Netlink error: No such process (3) return raise - for attr_type, attr_value in reply.attrs.iteritems(): + for attr_type, attr_value in reply.attrs.items(): if attr_type == TASKSTATS_TYPE_AGGR_PID: reply = attr_value.nested() break @@ -188,7 +179,7 @@ try: passwd = pwd.getpwnam(u) except KeyError: - print >> sys.stderr, 'Unknown user:', u + print('Unknown user:', u, file=sys.stderr) error = True else: uid = passwd.pw_uid @@ -197,11 +188,25 @@ if error: sys.exit(1) + +def parse_proc_pid_status(pid): + result_dict = {} + try: + for line in open('/proc/%d/status' % pid): + key, value = line.split(':\t', 1) + result_dict[key] = value.strip() + except IOError: + pass # No such process + return result_dict + + def safe_utf8_decode(s): try: return s.decode('utf-8') except UnicodeDecodeError: return s.encode('string_escape') + except AttributeError: + return s class ThreadInfo(DumpableObject): """Stats for a single thread""" @@ -273,26 +278,10 @@ if uid is not None and not self.user: try: self.user = safe_utf8_decode(pwd.getpwuid(uid).pw_name) - except KeyError: + except (KeyError, AttributeError): self.user = str(uid) return self.user or '{none}' - def get_proc_status_name(self): - try: - first_line = open('/proc/%d/status' % self.pid).readline() - except IOError: - return '{no such process}' - prefix = 'Name:\t' - if first_line.startswith(prefix): - name = first_line[6:].strip() - else: - name = '' - if name: - name = '[%s]' % name - else: - name = '{no name}' - return name - def get_cmdline(self): # A process may exec, so we must always reread its cmdline try: @@ -300,32 +289,46 @@ cmdline = proc_cmdline.read(4096) except IOError: return '{no such process}' + proc_status = parse_proc_pid_status(self.pid) if not cmdline: # Probably a kernel thread, get its name from /proc/PID/status - return self.get_proc_status_name() + proc_status_name = proc_status.get('Name', '') + if proc_status_name: + proc_status_name = '[%s]' % proc_status_name + else: + proc_status_name = '{no name}' + return proc_status_name + suffix = '' + tgid = int(proc_status.get('Tgid', self.pid)) + if tgid != self.pid: + # Not the main thread, maybe it has a custom name + tgid_name = parse_proc_pid_status(tgid).get('Name', '') + thread_name = proc_status.get('Name', '') + if thread_name != tgid_name: + suffix += ' [%s]' % thread_name parts = cmdline.split('\0') if parts[0].startswith('/'): first_command_char = parts[0].rfind('/') + 1 parts[0] = parts[0][first_command_char:] cmdline = ' '.join(parts).strip() - return safe_utf8_decode(cmdline) + return safe_utf8_decode(cmdline + suffix) def did_some_io(self, accumulated): if accumulated: return not self.stats_accum.is_all_zero() - for t in self.threads.itervalues(): + for t in self.threads.values(): if not t.stats_delta.is_all_zero(): return True return False def get_ioprio(self): - priorities = set(t.get_ioprio() for t in self.threads.itervalues()) + priorities = set(t.get_ioprio() for t in self.threads.values()) if len(priorities) == 1: return priorities.pop() return '?dif' def set_ioprio(self, ioprio_class, ioprio_data): - for thread in self.threads.itervalues(): + for thread in self.threads.values(): thread.set_ioprio(ioprio_class, ioprio_data) def ioprio_sort_key(self): @@ -341,10 +344,10 @@ def update_stats(self): stats_delta = Stats.build_all_zero() for tid, thread in self.threads.items(): - if thread.mark: - del self.threads[tid] - else: + if not thread.mark: stats_delta.accumulate(thread.stats_delta, stats_delta) + self.threads = dict([(tid, thread) for tid, thread in + self.threads.items() if not thread.mark]) nr_threads = len(self.threads) if not nr_threads: @@ -404,7 +407,7 @@ return [tgid] try: - tids = map(int, os.listdir('/proc/%d/task' % tgid)) + tids = list(map(int, os.listdir('/proc/%d/task' % tgid))) except OSError: return [] @@ -418,6 +421,8 @@ self.duration = new_timestamp - self.timestamp self.timestamp = new_timestamp + total_read = total_write = 0 + for tgid in self.list_tgids(): process = self.get_process(tgid) if not process: @@ -427,20 +432,22 @@ stats = self.taskstats_connection.get_single_task_stats(thread) if stats: thread.update_stats(stats) + delta = thread.stats_delta + total_read += delta.read_bytes + total_write += delta.write_bytes thread.mark = False - - return self.vmstat.delta() + return (total_read, total_write), self.vmstat.delta() def refresh_processes(self): - for process in self.processes.itervalues(): - for thread in process.threads.itervalues(): + for process in self.processes.values(): + for thread in process.threads.values(): thread.mark = True total_read_and_write = self.update_process_counts() - for pid, process in self.processes.items(): - if not process.update_stats(): - del self.processes[pid] + self.processes = dict([(pid, process) for pid, process in + self.processes.items() if + process.update_stats()]) return total_read_and_write diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/genetlink.py new/iotop-0.5/iotop/genetlink.py --- old/iotop-0.4.4/iotop/genetlink.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/genetlink.py 2013-02-03 19:50:02.000000000 +0100 @@ -7,8 +7,8 @@ ''' import struct -from netlink import NLM_F_REQUEST, NLMSG_MIN_TYPE, Message, parse_attributes -from netlink import NulStrAttr, Connection, NETLINK_GENERIC +from iotop.netlink import NLM_F_REQUEST, NLMSG_MIN_TYPE, Message, parse_attributes +from iotop.netlink import NulStrAttr, Connection, NETLINK_GENERIC CTRL_CMD_UNSPEC = 0 CTRL_CMD_NEWFAMILY = 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/ioprio.py new/iotop-0.5/iotop/ioprio.py --- old/iotop-0.4.4/iotop/ioprio.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/ioprio.py 2013-02-03 19:50:02.000000000 +0100 @@ -175,6 +175,6 @@ pid = int(sys.argv[1]) else: pid = os.getpid() - print 'pid:', pid - print 'ioprio:', get(pid) + print('pid:', pid) + print('ioprio:', get(pid)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/netlink.py new/iotop-0.5/iotop/netlink.py --- old/iotop-0.4.4/iotop/netlink.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/netlink.py 2013-02-03 19:50:02.000000000 +0100 @@ -102,7 +102,7 @@ hdr = struct.pack("HH", len(self.data)+4, self.type) length = len(self.data) pad = ((length + 4 - 1) & ~3 ) - length - return hdr + self.data + '\0' * pad + return hdr + self.data + b'\0' * pad def __repr__(self): return '<Attr type %d, data "%s">' % (self.type, repr(self.data)) @@ -124,11 +124,11 @@ class StrAttr(Attr): def __init__(self, attr_type, data): - Attr.__init__(self, attr_type, "%ds" % len(data), data) + Attr.__init__(self, attr_type, "%ds" % len(data), data.encode('utf-8')) class NulStrAttr(Attr): def __init__(self, attr_type, data): - Attr.__init__(self, attr_type, "%dsB" % len(data), data, 0) + Attr.__init__(self, attr_type, "%dsB" % len(data), data.encode('utf-8'), 0) class U32Attr(Attr): def __init__(self, attr_type, val): @@ -181,7 +181,7 @@ contents = [] for attr in payload: contents.append(attr._dump()) - self.payload = ''.join(contents) + self.payload = b''.join(contents) else: self.payload = payload diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/ui.py new/iotop-0.5/iotop/ui.py --- old/iotop-0.4.4/iotop/ui.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/ui.py 2013-02-03 19:50:02.000000000 +0100 @@ -16,6 +16,9 @@ # # Copyright (c) 2007 Guillaume Chazarain <guichaz@gmail.com> +# Allow printing with same syntax in Python 2/3 +from __future__ import print_function + import curses import errno import locale @@ -23,14 +26,15 @@ import optparse import os import select +import signal import sys import time from iotop.data import find_uids, TaskStatsNetlink, ProcessList, Stats from iotop.data import ThreadInfo from iotop.version import VERSION -import ioprio -from ioprio import IoprioSetError +from iotop import ioprio +from iotop.ioprio import IoprioSetError # # Utility functions for the UI @@ -79,6 +83,16 @@ write_bytes = display_format(written_bytes, duration) return io_delay, swapin_delay, read_bytes, write_bytes +def get_max_pid_width(): + try: + return len(open('/proc/sys/kernel/pid_max').read().strip()) + except Exception as e: + print(e) + # Reasonable default in case something fails + return 5 + +MAX_PID_WIDTH = get_max_pid_width() + # # UI Exceptions # @@ -136,9 +150,8 @@ poll.register(sys.stdin.fileno(), select.POLLIN|select.POLLPRI) while self.options.iterations is None or \ iterations < self.options.iterations: - total = self.process_list.refresh_processes() - total_read, total_write = total - self.refresh_display(iterations == 0, total_read, total_write, + total, actual = self.process_list.refresh_processes() + self.refresh_display(iterations == 0, total, actual, self.process_list.duration) if self.options.iterations is not None: iterations += 1 @@ -149,7 +162,7 @@ try: events = poll.poll(self.options.delay_seconds * 1000.0) - except select.error, e: + except select.error as e: if e.args and e.args[0] == errno.EINTR: events = 0 else: @@ -304,7 +317,7 @@ exec_unit.set_ioprio(ioprio_class, ioprio_data) self.process_list.clear() self.process_list.refresh_processes() - except IoprioSetError, e: + except IoprioSetError as e: self.prompt_error('Error setting I/O priority: %s' % e.err) except InvalidPid: self.prompt_error('Invalid process id!') @@ -365,7 +378,8 @@ delay_stats = '%7s %7s ' % (swapin_delay, io_delay) else: delay_stats = ' ?unavailable? ' - line = '%5d %4s %-8s %11s %11s %s' % ( + pid_format = '%%%dd' % MAX_PID_WIDTH + line = (pid_format + ' %4s %-8s %11s %11s %s') % ( p.pid, p.get_ioprio(), p.get_user()[:8], read_bytes, write_bytes, delay_stats) cmdline = p.get_cmdline() @@ -384,7 +398,8 @@ return not self.options.only or \ p.did_some_io(self.options.accumulated) - processes = filter(should_format, self.process_list.processes.values()) + processes = list(filter(should_format, + self.process_list.processes.values())) key = IOTopUI.sorting_keys[self.sorting_key][0] if self.options.accumulated: stats_lambda = lambda p: p.stats_accum @@ -394,16 +409,23 @@ reverse=self.sorting_reverse) if not self.options.batch: del processes[self.height - 2:] - return map(format, processes) + return list(map(format, processes)) + + def refresh_display(self, first_time, total, actual, duration): + summary = [ + 'Total DISK READ : %s | Total DISK WRITE : %s' % ( + format_bandwidth(self.options, total[0], duration).rjust(14), + format_bandwidth(self.options, total[1], duration).rjust(14)), + 'Actual DISK READ: %s | Actual DISK WRITE: %s' % ( + format_bandwidth(self.options, actual[0], duration).rjust(14), + format_bandwidth(self.options, actual[1], duration).rjust(14)) + ] - def refresh_display(self, first_time, total_read, total_write, duration): - summary = 'Total DISK READ: %s | Total DISK WRITE: %s' % ( - format_bandwidth(self.options, total_read, duration).rjust(14), - format_bandwidth(self.options, total_write, duration).rjust(14)) + pid = max(0, (MAX_PID_WIDTH - 3)) * ' ' if self.options.processes: - pid = ' PID' + pid += 'PID' else: - pid = ' TID' + pid += 'TID' titles = [pid, ' PRIO', ' USER', ' DISK READ', ' DISK WRITE', ' SWAPIN', ' IO', ' COMMAND'] lines = self.get_data() @@ -411,21 +433,24 @@ titles = [' TIME'] + titles current_time = time.strftime('%H:%M:%S ') lines = [current_time + l for l in lines] - summary = current_time + summary + summary = [current_time + s for s in summary] if self.options.batch: if self.options.quiet <= 2: - print summary + for s in summary: + print(s) if self.options.quiet <= int(first_time): - print ''.join(titles) + print(''.join(titles)) for l in lines: - print l.encode('utf-8') + print(l) sys.stdout.flush() else: self.win.erase() - self.win.addstr(summary[:self.width]) - self.win.hline(1, 0, ord(' ') | curses.A_REVERSE, self.width) + for i, s in enumerate(summary): + self.win.addstr(i, 0, s[:self.width]) + self.win.hline(len(summary), 0, ord(' ') | curses.A_REVERSE, + self.width) remaining_cols = self.width - for i in xrange(len(titles)): + for i in range(len(titles)): attr = curses.A_REVERSE title = titles[i] if i == self.sorting_key: @@ -442,16 +467,19 @@ status_msg = ('CONFIG_TASK_DELAY_ACCT not enabled in kernel, ' 'cannot determine SWAPIN and IO %') num_lines = min(len(lines), self.height - 2 - int(bool(status_msg))) - for i in xrange(num_lines): + for i in range(num_lines): try: - self.win.addstr(i + 2, 0, lines[i].encode('utf-8')) + self.win.addstr(i + len(summary) + 1, 0, lines[i]) except curses.error: pass if status_msg: - self.win.insstr(self.height - 1, 0, status_msg, curses.A_BOLD) + self.win.insstr(self.height - len(summary), 0, status_msg, + curses.A_BOLD) self.win.refresh() def run_iotop_window(win, options): + if options.batch: + signal.signal(signal.SIGPIPE, signal.SIG_DFL) taskstats_connection = TaskStatsNetlink(options) process_list = ProcessList(taskstats_connection, options) ui = IOTopUI(win, process_list, options) @@ -463,11 +491,17 @@ return run_iotop_window(None, options) else: return curses.wrapper(run_iotop_window, options) - except OSError, e: + except OSError as e: if e.errno == errno.EPERM: - print >> sys.stderr, e - print >> sys.stderr, ('iotop requires root or the NET_ADMIN ' - 'capability.') + print(e, file=sys.stderr) + print(''' +The Linux kernel interfaces that iotop relies on now require root priviliges +or the NET_ADMIN capability. This change occured because a security issue +(CVE-2011-2494) was found that allows leakage of sensitive data across user +boundaries. If you require the ability to run iotop as a non-root user, please +configure sudo to allow you to run iotop as root. + +Please do not file bugs on iotop about this.''', file=sys.stderr) sys.exit(1) else: raise @@ -481,14 +515,14 @@ try: import cProfile import pstats - print 'Profiling using cProfile' + print('Profiling using cProfile') cProfile.runctx('continuation()', globals(), locals(), prof_file) stats = pstats.Stats(prof_file) except ImportError: import hotshot import hotshot.stats prof = hotshot.Profile(prof_file, lineevents=1) - print 'Profiling using hotshot' + print('Profiling using hotshot') prof.runcall(continuation) prof.close() stats = hotshot.stats.load(prof_file) @@ -511,14 +545,14 @@ Controls: left and right arrows to change the sorting column, r to invert the sorting order, o to toggle the --only option, p to toggle the --processes -option, a to toggle the --accumulated option, q to quit, any other key to force -a refresh.''' % sys.argv[0] +option, a to toggle the --accumulated option, i to change I/O priority, q to +quit, any other key to force a refresh.''' % sys.argv[0] def main(): try: locale.setlocale(locale.LC_ALL, '') except locale.Error: - print 'unable to set locale, falling back to the default locale' + print('unable to set locale, falling back to the default locale') parser = optparse.OptionParser(usage=USAGE, version='iotop ' + VERSION) parser.add_option('-o', '--only', action='store_true', dest='only', default=False, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop/version.py new/iotop-0.5/iotop/version.py --- old/iotop-0.4.4/iotop/version.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop/version.py 2013-02-03 19:50:02.000000000 +0100 @@ -1 +1 @@ -VERSION = '0.4.4' +VERSION = '0.5' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop.1 new/iotop-0.5/iotop.1 --- old/iotop-0.4.4/iotop.1 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/iotop.1 1970-01-01 01:00:00.000000000 +0100 @@ -1,89 +0,0 @@ -.\" Debian manual page, has been forwarded upstream -.TH IOTOP "1" "April 2009" -.SH NAME -iotop \- simple top\-like I/O monitor -.SH SYNOPSIS -.B iotop -[\fIOPTIONS\fR] -.SH DESCRIPTION -iotop watches I/O usage information output by the Linux kernel (requires -2.6.20 or later) and displays a table of current I/O usage by processes -or threads on the system. At least the CONFIG_TASK_DELAY_ACCT, -CONFIG_TASK_IO_ACCOUNTING, CONFIG_TASKSTATS and CONFIG_VM_EVENT_COUNTERS -options need to be enabled in your Linux kernel build configuration. -.PP -iotop displays columns for the I/O bandwidth read and written by each -process/thread during the sampling period. It also displays the percentage -of time the thread/process spent while swapping in and while waiting on I/O. For each process, its I/O priority (class/level) is shown. -In addition, the total I/O bandwidth read and written during the sampling -period is displayed at the top of the interface. -.PP -Use the left and right arrows to change the sorting, r to reverse the -sorting order, o to toggle the \-\-only option, p to toggle the \-\-processes option, a to toggle the \-\-accumulated option, q to quit or i to change the priority of a thread or a process' thread(s). Any other key will force a refresh. -.SH OPTIONS -.TP -\fB\-\-version\fR -Show the version number and exit -.TP -\fB\-h\fR, \fB\-\-help\fR -Show usage information and exit -.TP -\fB\-o\fR, \fB\-\-only\fR -Only show processes or threads actually doing I/O, instead of showing all processes or threads. This can be dynamically toggled by pressing o. -.TP -\fB\-b\fR, \fB\-\-batch\fR -Turn on non\-interactive mode. -Useful for logging I/O usage over time. -.TP -\fB\-n\fR NUM, \fB\-\-iter\fR=\fINUM\fR -Set the number of iterations before quitting (never quit by default). -This is most useful in non\-interactive mode. -.TP -\fB\-d\fR SEC, \fB\-\-delay\fR=\fISEC\fR -Set the delay between iterations in seconds (1 second by default). -Accepts non-integer values such as 1.1 seconds. -.TP -\fB\-p\fR PID, \fB\-\-pid\fR=\fIPID\fR -A list of processes/threads to monitor (all by default). -.TP -\fB\-u\fR USER, \fB\-\-user\fR=\fIUSER\fR -A list of users to monitor (all by default) -.TP -\fB\-P\fR, \fB\-\-processes\fR -Only show processes. Normally iotop shows all threads. -.TP -\fB\-a\fR, \fB\-\-accumulated\fR -Show accumulated I/O instead of bandwidth. In this mode, iotop shows the amount of I/O processes have done since iotop started. -.TP -\fB\-k\fR, \fB\-\-kilobytes\fR -Use kilobytes instead of a human friendly unit. This mode is useful when scripting the batch mode of iotop. Instead of choosing the most appropriate unit iotop will display all sizes in kilobytes. -.TP -\fB\-t\fR, \fB\-\-time\fR -Add a timestamp on each line (implies \-\-batch). Each line will be prefixed by the current time. -.TP -\fB\-q\fR, \fB\-\-quiet\fR -suppress some lines of header (implies \-\-batch). This option can be specified up to three times to remove header lines. -.RS -.PD 0 -.TP -.B \-q -column names are only printed on the first iteration, -.TP -.B \-qq -column names are never printed, -.TP -.B \-qqq -the I/O summary is never printed. -.PD 1 -.RE -.SH SEE ALSO -.BR ionice (1), -.BR top (1), -.BR vmstat (1), -.BR atop (1), -.BR htop (1) -.SH AUTHOR -iotop was written by Guillaume Chazarain. -.PP -This manual page was started by Paul Wise for the -Debian project and is placed in the public domain. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/iotop.8 new/iotop-0.5/iotop.8 --- old/iotop-0.4.4/iotop.8 1970-01-01 01:00:00.000000000 +0100 +++ new/iotop-0.5/iotop.8 2013-02-03 19:50:02.000000000 +0100 @@ -0,0 +1,97 @@ +.\" Debian manual page, has been forwarded upstream +.TH IOTOP "8" "April 2009" +.SH NAME +iotop \- simple top\-like I/O monitor +.SH SYNOPSIS +.B iotop +[\fIOPTIONS\fR] +.SH DESCRIPTION +iotop watches I/O usage information output by the Linux kernel (requires +2.6.20 or later) and displays a table of current I/O usage by processes +or threads on the system. At least the CONFIG_TASK_DELAY_ACCT, +CONFIG_TASK_IO_ACCOUNTING, CONFIG_TASKSTATS and CONFIG_VM_EVENT_COUNTERS +options need to be enabled in your Linux kernel build configuration. +.PP +iotop displays columns for the I/O bandwidth read and written by each +process/thread during the sampling period. It also displays the percentage +of time the thread/process spent while swapping in and while waiting on I/O. For each process, its I/O priority (class/level) is shown. +.PP +In addition, the total I/O bandwidth read and written during the sampling +period is displayed at the top of the interface. +\fBTotal DISK READ\fR and \fBTotal DISK WRITE\fR values represent total read +and write bandwidth between processes and kernel threads on the one side and +kernel block device subsystem on the other. While \fBActual DISK READ\fR and +\fBActual DISK WRITE\fR values represent corresponding bandwidths for actual +disk I/O between kernel block device subsystem and underlying hardware (HDD, SSD, etc.). +Thus \fBTotal\fR and \fBActual\fR values may not be equal at any given moment of time +due to data caching and I/O operations reordering that take place inside Linux kernel. +.PP +Use the left and right arrows to change the sorting, r to reverse the +sorting order, o to toggle the \-\-only option, p to toggle the \-\-processes option, a to toggle the \-\-accumulated option, q to quit or i to change the priority of a thread or a process' thread(s). Any other key will force a refresh. +.SH OPTIONS +.TP +\fB\-\-version\fR +Show the version number and exit +.TP +\fB\-h\fR, \fB\-\-help\fR +Show usage information and exit +.TP +\fB\-o\fR, \fB\-\-only\fR +Only show processes or threads actually doing I/O, instead of showing all processes or threads. This can be dynamically toggled by pressing o. +.TP +\fB\-b\fR, \fB\-\-batch\fR +Turn on non\-interactive mode. +Useful for logging I/O usage over time. +.TP +\fB\-n\fR NUM, \fB\-\-iter\fR=\fINUM\fR +Set the number of iterations before quitting (never quit by default). +This is most useful in non\-interactive mode. +.TP +\fB\-d\fR SEC, \fB\-\-delay\fR=\fISEC\fR +Set the delay between iterations in seconds (1 second by default). +Accepts non-integer values such as 1.1 seconds. +.TP +\fB\-p\fR PID, \fB\-\-pid\fR=\fIPID\fR +A list of processes/threads to monitor (all by default). +.TP +\fB\-u\fR USER, \fB\-\-user\fR=\fIUSER\fR +A list of users to monitor (all by default) +.TP +\fB\-P\fR, \fB\-\-processes\fR +Only show processes. Normally iotop shows all threads. +.TP +\fB\-a\fR, \fB\-\-accumulated\fR +Show accumulated I/O instead of bandwidth. In this mode, iotop shows the amount of I/O processes have done since iotop started. +.TP +\fB\-k\fR, \fB\-\-kilobytes\fR +Use kilobytes instead of a human friendly unit. This mode is useful when scripting the batch mode of iotop. Instead of choosing the most appropriate unit iotop will display all sizes in kilobytes. +.TP +\fB\-t\fR, \fB\-\-time\fR +Add a timestamp on each line (implies \-\-batch). Each line will be prefixed by the current time. +.TP +\fB\-q\fR, \fB\-\-quiet\fR +suppress some lines of header (implies \-\-batch). This option can be specified up to three times to remove header lines. +.RS +.PD 0 +.TP +.B \-q +column names are only printed on the first iteration, +.TP +.B \-qq +column names are never printed, +.TP +.B \-qqq +the I/O summary is never printed. +.PD 1 +.RE +.SH SEE ALSO +.BR ionice (1), +.BR top (1), +.BR vmstat (1), +.BR atop (1), +.BR htop (1) +.SH AUTHOR +iotop was written by Guillaume Chazarain. +.PP +This manual page was started by Paul Wise for the +Debian project and is placed in the public domain. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/sbin/iotop new/iotop-0.5/sbin/iotop --- old/iotop-0.4.4/sbin/iotop 1970-01-01 01:00:00.000000000 +0100 +++ new/iotop-0.5/sbin/iotop 2013-02-03 19:50:02.000000000 +0100 @@ -0,0 +1,19 @@ +#!/usr/bin/python +# iotop: Display I/O usage of processes in a top like UI +# Copyright (c) 2007, 2008 Guillaume Chazarain <guichaz@gmail.com>, GPLv2 +# See iotop --help for some help + +import sys + +try: + from iotop.ui import main +except ImportError, e: + print e + print 'To run an uninstalled copy of iotop,' + print 'launch iotop.py in the top directory' +else: + try: + main() + except KeyboardInterrupt: + pass + sys.exit(0) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/iotop-0.4.4/setup.py new/iotop-0.5/setup.py --- old/iotop-0.4.4/setup.py 2011-10-30 21:36:22.000000000 +0100 +++ new/iotop-0.5/setup.py 2013-02-03 19:50:02.000000000 +0100 @@ -12,8 +12,8 @@ author='Guillaume Chazarain', author_email='guichaz@gmail.com', url='http://guichaz.free.fr/iotop', - scripts=['bin/iotop'], - data_files=[('share/man/man1', ['iotop.1'])], + scripts=['sbin/iotop'], + data_files=[('share/man/man8', ['iotop.8'])], packages=['iotop'], license='GPL' ) -- To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-commit+help@opensuse.org