Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added topio and topbio plugins.

  • Loading branch information...
commit 34fb339e378ba6701675408cde21ab3544813414 1 parent ceb8a5f
@dagwieers authored
View
1  ChangeLog
@@ -11,6 +11,7 @@
- Fixed a few inaccuracies in the man page. (John Goggan)
- Fixed opening vanished files in /proc in dstat_topcpu.
- Fixed formatting bug in dstat_topcpu.
+- Added external dstat_topio and dstat_topbio plugins
* 0.6.6 - Unemployed - released 28/04/2007
- Removed SwapCached from the Cached counter (Dbt 418326, Peter Rabbitson)
View
7 TODO
@@ -39,8 +39,9 @@ contact me as well. :) Send an email to: Dag Wieers <dag@wieers.com>
+ Add i2c plugin (see /sys/class/i2c-adapter/i2c-*/*/*/*/*/*)
+ Allow for SNMP counters to be added
+ Add LVM stats
++ Add 'most expensive io app' based on /proc/pid/io (topio_ops)
++ Add 'most expensive X app' (look at xrestop)
+ Add number of (active) X sessions and X clients
-+ Add 'most expensive io app' and 'most expensive X app'
+ Allow to have multiple '1st expensive ... app' and '2nd expensive ... app'
### Documentation (help welcome!)
@@ -58,10 +59,8 @@ contact me as well. :) Send an email to: Dag Wieers <dag@wieers.com>
+ When stdout is suspend (Ctrl-S) you get: IOError: [Errno 4] Interrupted system call (Dbt 309953, Marc Lehmann, supastuff@freenode)
### Plugin issues
-+ app plugin: reasonably slow
-+ app plugin: has problem opening too many files [Errno 24]
++ plugins that use /proc/pid are reasonably slow
+ app plugin: takes second argument when finding known interpreter (is wrong when second argument
-+ app plugin: prints ANSI characters to CSV
+ disk plugin: /proc/partitions can have negative numbers, seen on systems with long uptime. dstat handles this except for calculating the very first stat, no work-around possible?
+ proc plugin: (run and blk) does not work on 2.4.24+, to be confirmed
+ proc plugin: seem to be off-by-one compared to vmstat (some of the time, this is what I get from /proc/stat)
View
85 plugins/dstat_topbio.py
@@ -0,0 +1,85 @@
+### Dstat most expensive block I/O process plugin
+### Displays the name of the most expensive block I/O process
+###
+### Authority: dag@wieers.com
+
+global string
+import string
+
+class dstat_topbio(dstat):
+ def __init__(self):
+ self.name = 'most expensive'
+ self.format = ('s', 22, 1024)
+ self.nick = ('block i/o process',)
+ self.vars = self.nick
+ self.pid = str(os.getpid())
+ self.cn1 = {}; self.cn2 = {}; self.val = {}
+
+ def check(self):
+ try:
+ open('/proc/self/io')
+ except:
+ raise Exception, 'Kernel has no I/O accounting, use at least 2.6.20.'
+ return True
+
+ def extract(self):
+ self.val['usage'] = 0.0
+ for pid in os.listdir('/proc/'):
+ try:
+ int(pid)
+ if pid == self.pid: continue
+ if not self.cn2.has_key(pid):
+ self.cn2[pid] = {'read_bytes:': 0, 'write_bytes:': 0}
+ if not self.cn1.has_key(pid):
+ self.cn1[pid] = {'read_bytes:': 0, 'write_bytes:': 0}
+
+ for line in open('/proc/%s/io' % pid).readlines():
+ l = string.split(line)
+ if len(l) != 2: continue
+ self.cn2[pid][l[0]] = int(l[1])
+ except ValueError:
+ continue
+
+ read_usage = (self.cn2[pid]['read_bytes:'] - self.cn1[pid]['read_bytes:']) * 1.0 / tick
+ write_usage = (self.cn2[pid]['write_bytes:'] - self.cn1[pid]['write_bytes:']) * 1.0 / tick
+ usage = read_usage + write_usage
+
+ ### Get the process that spends the most jiffies
+ if usage > self.val['usage']:
+ self.val['usage'] = usage
+ self.val['read_usage'] = read_usage
+ self.val['write_usage'] = write_usage
+ self.val['pid'] = pid
+ st = os.stat("/proc/%s" % pid)
+
+ if self.val['usage'] == 0.0:
+ self.val['process'] = ''
+ else:
+ l = string.split(open('/proc/%s/stat' % self.val['pid']).read())
+ self.val['name'] = l[1][1:-1]
+ ### If the name is a known interpreter, take the second argument from the cmdline
+ if self.val['name'] in ('bash', 'csh', 'ksh', 'perl', 'python', 'sh'):
+ ### Using dopen() will cause too many open files
+# l = string.split(dopen('/proc/%s/cmdline' % self.val['pid']).read(), '\0')
+ l = string.split(open('/proc/%s/cmdline' % self.val['pid']).read(), '\0')
+ if len(l) > 2:
+ self.val['process'] = os.path.basename(l[1])
+ else:
+ self.val['process'] = self.val['name']
+
+ ### Debug (show PID)
+# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.format[1]-6, self.val['name'])
+
+ if step == op.delay:
+ self.cn1.update(self.cn2)
+
+ def show(self):
+ if self.val['usage'] == 0.0:
+ return '%-*s' % (self.format[1], '')
+ else:
+ return '%s%-*s%s:%s' % (ansi['default'], self.format[1]-11, self.val['process'][0:self.format[1]-11], cprint(self.val['read_usage'], ('f', 5, 1024)), cprint(self.val['write_usage'], ('f', 5, 1024)))
+
+ def showcsv(self):
+ return '%s / %d:%d' % (self.val['name'], self.val['read_usage'], selv.val['write_usage'])
+
+# vim:ts=4:sw=4:et
View
87 plugins/dstat_topio.py
@@ -0,0 +1,87 @@
+### Dstat most expensive I/O process plugin
+### Displays the name of the most expensive I/O process
+###
+### Authority: dag@wieers.com
+
+global string
+import string
+
+class dstat_topio(dstat):
+ def __init__(self):
+ self.name = 'most expensive'
+ self.format = ('s', 22, 1024)
+ self.nick = ('i/o process',)
+ self.vars = self.nick
+ self.pid = str(os.getpid())
+ self.cn1 = {}; self.cn2 = {}; self.val = {}
+
+ def check(self):
+ try:
+ open('/proc/self/io')
+ except:
+ raise Exception, 'Kernel has no I/O accounting, use at least 2.6.20.'
+ return True
+
+ def extract(self):
+ self.val['usage'] = 0.0
+ for pid in os.listdir('/proc/'):
+ try:
+ int(pid)
+ if pid == self.pid: continue
+ if not self.cn2.has_key(pid):
+ self.cn2[pid] = {'rchar:': 0, 'wchar:': 0}
+ if not self.cn1.has_key(pid):
+ self.cn1[pid] = {'rchar:': 0, 'wchar:': 0}
+
+ for line in open('/proc/%s/io' % pid).readlines():
+ l = string.split(line)
+ if len(l) != 2: continue
+ self.cn2[pid][l[0]] = int(l[1])
+ except ValueError:
+ continue
+
+ read_usage = (self.cn2[pid]['rchar:'] - self.cn1[pid]['rchar:']) * 1.0 / tick
+ write_usage = (self.cn2[pid]['wchar:'] - self.cn1[pid]['wchar:']) * 1.0 / tick
+ usage = read_usage + write_usage
+# if usage > 0.0:
+# print '%s %s:%s' % (pid, read_usage, write_usage)
+
+ ### Get the process that spends the most jiffies
+ if usage > self.val['usage']:
+ self.val['usage'] = usage
+ self.val['read_usage'] = read_usage
+ self.val['write_usage'] = write_usage
+ self.val['pid'] = pid
+ st = os.stat("/proc/%s" % pid)
+
+ if self.val['usage'] == 0.0:
+ self.val['process'] = ''
+ else:
+ l = string.split(open('/proc/%s/stat' % self.val['pid']).read())
+ self.val['name'] = l[1][1:-1]
+ ### If the name is a known interpreter, take the second argument from the cmdline
+ if self.val['name'] in ('bash', 'csh', 'ksh', 'perl', 'python', 'sh'):
+ ### Using dopen() will cause too many open files
+# l = string.split(dopen('/proc/%s/cmdline' % self.val['pid']).read(), '\0')
+ l = string.split(open('/proc/%s/cmdline' % self.val['pid']).read(), '\0')
+ if len(l) > 2:
+ self.val['process'] = os.path.basename(l[1])
+ else:
+ self.val['process'] = self.val['name']
+
+ ### Debug (show PID)
+# self.val['process'] = '%*s %-*s' % (5, self.val['pid'], self.format[1]-6, self.val['name'])
+
+ if step == op.delay:
+ self.cn1.update(self.cn2)
+
+ def show(self):
+ if self.val['usage'] == 0.0:
+ return '%-*s' % (self.format[1], '')
+ else:
+ return '%s%-*s%s:%s' % (ansi['default'], self.format[1]-11, self.val['process'][0:self.format[1]-11], cprint(self.val['read_usage'], ('f', 5, 1024)), cprint(self.val['write_usage'], ('f', 5, 1024)))
+
+ def showcsv(self):
+ return '%s / %d:%d' % (self.val['name'], self.val['read_usage'], selv.val['write_usage'])
+
+# vim:ts=4:sw=4:et
Please sign in to comment.
Something went wrong with that request. Please try again.