summaryrefslogtreecommitdiff
path: root/src/pmcollectl
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmcollectl
downloadpcp-debian.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmcollectl')
-rw-r--r--src/pmcollectl/GNUmakefile28
-rwxr-xr-xsrc/pmcollectl/pmcollectl.py708
2 files changed, 736 insertions, 0 deletions
diff --git a/src/pmcollectl/GNUmakefile b/src/pmcollectl/GNUmakefile
new file mode 100644
index 0000000..c094578
--- /dev/null
+++ b/src/pmcollectl/GNUmakefile
@@ -0,0 +1,28 @@
+#
+# Copyright (c) 2012 Red Hat.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+TOPDIR = ../..
+include $(TOPDIR)/src/include/builddefs
+
+TARGET = pmcollectl
+PYFILES = $(TARGET).py
+
+default default_pcp: $(PYFILES)
+
+include $(BUILDRULES)
+
+install install_pcp: $(PYFILES)
+ifneq "$(PYTHON)" ""
+ $(INSTALL) -m 755 $(PYFILES) $(PCP_BIN_DIR)/$(TARGET)
+endif
diff --git a/src/pmcollectl/pmcollectl.py b/src/pmcollectl/pmcollectl.py
new file mode 100755
index 0000000..13769f9
--- /dev/null
+++ b/src/pmcollectl/pmcollectl.py
@@ -0,0 +1,708 @@
+#!/usr/bin/python
+
+#
+# pmcollectl.py
+#
+# Copyright (C) 2012-2014 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+
+"""System status collector using the libpcp Wrapper module
+
+Additional Information:
+
+Performance Co-Pilot Web Site
+http://www.performancecopilot.org
+"""
+
+# ignore line too long, missing docstring, method could be a function,
+# too many public methods
+# pylint: disable=C0301
+# pylint: disable=C0111
+# pylint: disable=R0201
+# pylint: disable=R0904
+
+##############################################################################
+#
+# imports
+#
+
+import os
+import sys
+import time
+import cpmapi as c_api
+import cpmgui as c_gui
+from pcp import pmapi, pmgui
+from pcp.pmsubsys import Subsystem
+
+ME = "pmcollectl"
+
+
+# scale -----------------------------------------------------------------
+
+
+def scale(value, magnitude):
+ return (value + (magnitude / 2)) / magnitude
+
+
+# record ---------------------------------------------------------------
+
+def record(context, config, duration, path, host):
+ if os.path.exists(path):
+ print ME + "archive %s already exists\n" % path
+ sys.exit(1)
+ # Non-graphical application using libpcp_gui services - never want
+ # to see popup dialogs from pmlogger(1) here, so force the issue.
+ os.environ['PCP_XCONFIRM_PROG'] = '/bin/true'
+ interval = pmapi.timeval.fromInterval(str(duration) + " seconds")
+ context.pmRecordSetup(path, ME, 0) # pylint: disable=W0621
+ context.pmRecordAddHost(host, 1, config) # just a filename
+ deadhand = "-T" + str(interval) + "seconds"
+ context.pmRecordControl(0, c_gui.PM_REC_SETARG, deadhand)
+ context.pmRecordControl(0, c_gui.PM_REC_ON, "")
+ interval.sleep()
+ context.pmRecordControl(0, c_gui.PM_REC_OFF, "")
+ # Note: pmlogger has a deadhand timer that will make it stop of its
+ # own accord once -T limit is reached; but we send an OFF-recording
+ # message anyway for cleanliness, just prior to pmcollectl exiting.
+
+# record_add_creator ------------------------------------------------------
+
+def record_add_creator(path):
+ fdesc = open(path, "a+")
+ args = ""
+ for i in sys.argv:
+ args = args + i + " "
+ fdesc.write("# Created by " + args)
+ fdesc.write("\n#\n")
+ fdesc.close()
+
+# _CollectPrint -------------------------------------------------------
+
+
+class _CollectPrint(object):
+ def __init__(self, ss):
+ self.ss = ss
+ def print_header1(self):
+ if self.verbosity == "brief":
+ self.print_header1_brief()
+ elif self.verbosity == "detail":
+ self.print_header1_detail()
+ elif self.verbosity == "verbose":
+ self.print_header1_verbose()
+ sys.stdout.flush()
+ def print_header2(self):
+ if self.verbosity == "brief":
+ self.print_header2_brief()
+ elif self.verbosity == "detail":
+ self.print_header2_detail()
+ elif self.verbosity == "verbose":
+ self.print_header2_verbose()
+ sys.stdout.flush()
+ def print_header1_brief(self):
+ True # pylint: disable-msg=W0104
+ def print_header2_brief(self):
+ True # pylint: disable-msg=W0104
+ def print_header1_detail(self):
+ True # pylint: disable-msg=W0104
+ def print_header2_detail(self):
+ True # pylint: disable-msg=W0104
+ def print_header1_verbose(self):
+ True # pylint: disable-msg=W0104
+ def print_header2_verbose(self):
+ True # pylint: disable-msg=W0104
+ def print_line(self):
+ if self.verbosity == "brief":
+ self.print_brief()
+ elif self.verbosity == "detail":
+ self.print_detail()
+ elif self.verbosity == "verbose":
+ self.print_verbose()
+ def print_brief(self):
+ True # pylint: disable-msg=W0104
+ def print_verbose(self):
+ True # pylint: disable-msg=W0104
+ def print_detail(self):
+ True # pylint: disable-msg=W0104
+ def divide_check(self, dividend, divisor):
+ if divisor == 0:
+ return 0
+ else:
+ return dividend / divisor
+ def set_verbosity(self, cpverbosity):
+ self.verbosity = cpverbosity # pylint: disable-msg=W0201
+
+
+# _cpuCollectPrint --------------------------------------------------
+
+
+class _cpuCollectPrint(_CollectPrint):
+ def print_header1_brief(self):
+ sys.stdout.write('#<--------CPU-------->')
+ def print_header1_detail(self):
+ print '# SINGLE CPU STATISTICS'
+ def print_header1_verbose(self):
+ print '# CPU SUMMARY (INTR, CTXSW & PROC /sec)'
+
+ def print_header2_brief(self):
+ sys.stdout.write('#cpu sys inter ctxsw')
+ def print_header2_detail(self):
+ print '# Cpu User Nice Sys Wait IRQ Soft Steal Idle'
+ def print_header2_verbose(self):
+ print '#User Nice Sys Wait IRQ Soft Steal Idle CPUs Intr Ctxsw Proc RunQ Run Avg1 Avg5 Avg15 RunT BlkT'
+
+ def print_brief(self):
+ print "%4d" % (100 * (self.ss.get_metric_value('kernel.all.cpu.nice') +
+ self.ss.get_metric_value('kernel.all.cpu.user') +
+ self.ss.get_metric_value('kernel.all.cpu.intr') +
+ self.ss.get_metric_value('kernel.all.cpu.sys') +
+ self.ss.get_metric_value('kernel.all.cpu.steal') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.hard') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.soft')) /
+ ss.cpu_total),
+ print "%3d" % (100 * (self.ss.get_metric_value('kernel.all.cpu.intr') +
+ self.ss.get_metric_value('kernel.all.cpu.sys') +
+ self.ss.get_metric_value('kernel.all.cpu.steal') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.hard') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.soft')) /
+ ss.cpu_total),
+ print "%5d %6d" % (self.ss.get_metric_value('kernel.all.intr'),
+ self.ss.get_metric_value('kernel.all.pswitch')),
+ def print_detail(self):
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.cpu.user'))):
+ print " %3d %4d %4d %3d %4d %3d %4d %5d %4d" % (
+ k,
+ (100 * (self.ss.get_scalar_value('kernel.percpu.cpu.nice', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.user', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.intr', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.sys', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.steal', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft', k)) /
+ ss.cpu_total),
+ self.ss.get_scalar_value('kernel.percpu.cpu.nice', k),
+ (100 * (self.ss.get_scalar_value('kernel.percpu.cpu.intr', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.sys', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.steal', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard', k) +
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft', k)) /
+ ss.cpu_total),
+ self.ss.get_scalar_value('kernel.percpu.cpu.wait.total', k),
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard', k),
+ self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft', k),
+ self.ss.get_scalar_value('kernel.percpu.cpu.steal', k),
+ self.ss.get_scalar_value('kernel.percpu.cpu.idle', k) / 10)
+ def print_verbose(self):
+ ncpu = self.ss.get_metric_value('hinv.ncpu')
+ print "%4d %6d %5d %4d %4d %5d " % (
+ (100 * (self.ss.get_metric_value('kernel.all.cpu.nice') +
+ self.ss.get_metric_value('kernel.all.cpu.user') +
+ self.ss.get_metric_value('kernel.all.cpu.intr') +
+ self.ss.get_metric_value('kernel.all.cpu.sys') +
+ self.ss.get_metric_value('kernel.all.cpu.steal') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.hard') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.soft')) /
+ ss.cpu_total),
+ self.ss.get_metric_value('kernel.all.cpu.nice'),
+ (100 * (self.ss.get_metric_value('kernel.all.cpu.intr') +
+ self.ss.get_metric_value('kernel.all.cpu.sys') +
+ self.ss.get_metric_value('kernel.all.cpu.steal') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.hard') +
+ self.ss.get_metric_value('kernel.all.cpu.irq.soft')) /
+ ss.cpu_total),
+ self.ss.get_metric_value('kernel.all.cpu.wait.total'),
+ self.ss.get_metric_value('kernel.all.cpu.irq.hard'),
+ self.ss.get_metric_value('kernel.all.cpu.irq.soft')
+ ),
+ print "%6d %6d %5d %5d %6d" % (
+ self.ss.get_metric_value('kernel.all.cpu.steal'),
+ self.ss.get_metric_value('kernel.all.cpu.idle') / (10 * ncpu),
+ ncpu,
+ self.ss.get_metric_value('kernel.all.intr'),
+ self.ss.get_metric_value('kernel.all.pswitch')
+ ),
+ print "%5d %5d %5d %5.2f %5.2f %5.2f %4d %4d" % (
+ self.ss.get_metric_value('kernel.all.nprocs'),
+ self.ss.get_metric_value('kernel.all.runnable'),
+ self.ss.get_metric_value('proc.runq.runnable'),
+ self.ss.get_metric_value('kernel.all.load')[0],
+ self.ss.get_metric_value('kernel.all.load')[1],
+ self.ss.get_metric_value('kernel.all.load')[2],
+ self.ss.get_metric_value('kernel.all.runnable'),
+ self.ss.get_metric_value('proc.runq.blocked'))
+
+
+# _interruptCollectPrint ---------------------------------------------
+
+
+class _interruptCollectPrint(_CollectPrint):
+ def print_header1_brief(self):
+ ndashes = (((self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))) * 6) - 6) / 2
+ hdr = "#<"
+ for k in range(ndashes):
+ hdr += "-"
+ hdr += "Int"
+ for k in range(ndashes):
+ hdr += "-"
+ hdr += ">"
+ print hdr,
+ def print_header1_detail(self):
+ print '# INTERRUPT DETAILS'
+ print '# Int ',
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ print 'Cpu%d ' % k,
+ print 'Type Device(s)'
+ def print_header1_verbose(self):
+ print '# INTERRUPT SUMMARY'
+ def print_header2_brief(self):
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ if k == 0:
+ print '#Cpu%d ' % k,
+ else:
+ print 'Cpu%d ' % k,
+ def print_header2_verbose(self):
+ print '# ',
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ print 'Cpu%d ' % k,
+ print
+ def print_brief(self):
+ int_count = []
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ int_count.append(0)
+ for j in ss.metrics:
+ if j[0:24] == 'kernel.percpu.interrupts':
+ int_count[k] += self.ss.get_scalar_value(self.ss.metrics_dict[j], k)
+
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ print "%4d " % (int_count[k]),
+ def print_detail(self):
+ for j in ss.metrics:
+ if j[0:24] != 'kernel.percpu.interrupts':
+ continue
+ j_i = self.ss.metrics_dict[j]
+ have_nonzero_value = False
+ for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ if self.ss.get_scalar_value(j_i, k) != 0:
+ have_nonzero_value = True
+ if not have_nonzero_value:
+ continue
+ if have_nonzero_value:
+ # pcp does not give the interrupt # so print spaces
+ print "%-8s" % self.ss.metrics[j_i].split(".")[3],
+ for i in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))):
+ print "%4d " % (self.ss.get_scalar_value(j_i, i)),
+ text = (pm.pmLookupText(self.ss.metric_pmids[j_i], c_api.PM_TEXT_ONELINE))
+ print "%-18s %s" % (text[:(str.index(text, " "))],
+ text[(str.index(text, " ")):])
+ def print_verbose(self):
+ print " ",
+ self.print_brief()
+ print
+
+
+# _diskCollectPrint --------------------------------------------------
+
+
+class _diskCollectPrint(_CollectPrint):
+ def print_header1_brief(self):
+ sys.stdout.write('<----------Disks----------->')
+ def print_header1_detail(self):
+ print '# DISK STATISTICS (/sec)'
+ def print_header1_verbose(self):
+ print '\n\n# DISK SUMMARY (/sec)'
+ def print_header2_brief(self):
+ sys.stdout.write(' KBRead Reads KBWrit Writes')
+ def print_header2_detail(self):
+ print '# <---------reads---------><---------writes---------><--------averages--------> Pct'
+ print '#Name KBytes Merged IOs Size KBytes Merged IOs Size RWSize QLen Wait SvcTim Util'
+ def print_header2_verbose(self):
+ sys.stdout.write('#KBRead RMerged Reads SizeKB KBWrite WMerged Writes SizeKB\n')
+ def print_brief(self):
+ sys.stdout.write("%6d %6d %6d %6d" % (
+ self.ss.get_metric_value('disk.all.read_bytes'),
+ self.ss.get_metric_value('disk.all.read'),
+ self.ss.get_metric_value('disk.all.write_bytes'),
+ self.ss.get_metric_value('disk.all.write')))
+ def print_detail(self):
+ for j in xrange(len(self.ss.metric_pmids)):
+ try:
+ if self.ss.metrics[j] == 'disk.dev.read':
+ (inst, iname) = pm.pmGetInDom(self.ss.metric_descs[j])
+ break
+ except pmapi.pmErr, e:
+ iname = "X"
+
+ # metric values may be scalars or arrays depending on # of disks
+ for j in xrange(len(iname)):
+ print "%-10s %6d %6d %4d %4d %6d %6d %4d %4d %6d %6d %4d %6d %4d" % (
+ iname[j],
+ self.ss.get_scalar_value('disk.dev.read_bytes', j),
+ self.ss.get_scalar_value('disk.dev.read_merge', j),
+ self.ss.get_scalar_value('disk.dev.read', j),
+ self.ss.get_scalar_value('disk.dev.blkread', j),
+ self.ss.get_scalar_value('disk.dev.write_bytes', j),
+ self.ss.get_scalar_value('disk.dev.write_merge', j),
+ self.ss.get_scalar_value('disk.dev.write', j),
+ self.ss.get_scalar_value('disk.dev.blkwrite', j),
+ 0, 0, 0, 0, 0)
+# ??? replace 0 with required fields
+
+ def print_verbose(self):
+ avgrdsz = avgwrsz = 0
+ if self.ss.get_metric_value('disk.all.read') > 0:
+ avgrdsz = self.ss.get_metric_value('disk.all.read_bytes')
+ avgrdsz /= self.ss.get_metric_value('disk.all.read')
+ if self.ss.get_metric_value('disk.all.write') > 0:
+ avgwrsz = self.ss.get_metric_value('disk.all.write_bytes')
+ avgwrsz /= self.ss.get_metric_value('disk.all.write')
+
+ print '%6d %6d %6d %6d %7d %8d %6d %6d' % (
+ avgrdsz,
+ self.ss.get_metric_value('disk.all.read_merge'),
+ self.ss.get_metric_value('disk.all.read'),
+ 0,
+ avgwrsz,
+ self.ss.get_metric_value('disk.all.write_merge'),
+ self.ss.get_metric_value('disk.all.write'),
+ 0)
+
+
+# _memoryCollectPrint ------------------------------------------------
+
+
+class _memoryCollectPrint(_CollectPrint):
+ def print_header1_brief(self):
+ sys.stdout.write('#<-----------Memory----------->')
+ def print_header1_verbose(self):
+ print '# MEMORY SUMMARY'
+ def print_header2_brief(self):
+ print '#Free Buff Cach Inac Slab Map'
+ def print_header2_verbose(self):
+ print '#<-------------------------------Physical Memory--------------------------------------><-----------Swap------------><-------Paging------>'
+ print '# Total Used Free Buff Cached Slab Mapped Anon Commit Locked Inact Total Used Free In Out Fault MajFt In Out'
+ def print_brief(self):
+ print "%4dM %3dM %3dM %3dM %3dM %3dM " % (
+ scale(self.ss.get_metric_value('mem.freemem'), 1000),
+ scale(self.ss.get_metric_value('mem.util.bufmem'), 1000),
+ scale(self.ss.get_metric_value('mem.util.cached'), 1000),
+ scale(self.ss.get_metric_value('mem.util.inactive'), 1000),
+ scale(self.ss.get_metric_value('mem.util.slab'), 1000),
+ scale(self.ss.get_metric_value('mem.util.mapped'), 1000)),
+ def print_verbose(self):
+ print "%8dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %5dM %5dM %5dM %5dM %6d %6d %6d %6d %6d %6d " % (
+ scale(self.ss.get_metric_value('mem.physmem'), 1000),
+ scale(self.ss.get_metric_value('mem.util.used'), 1000),
+ scale(self.ss.get_metric_value('mem.freemem'), 1000),
+ scale(self.ss.get_metric_value('mem.util.bufmem'), 1000),
+ scale(self.ss.get_metric_value('mem.util.cached'), 1000),
+ scale(self.ss.get_metric_value('mem.util.slab'), 1000),
+ scale(self.ss.get_metric_value('mem.util.mapped'), 1000),
+ scale(self.ss.get_metric_value('mem.util.anonpages'), 1000),
+ scale(self.ss.get_metric_value('mem.util.committed_AS'), 1000),
+ scale(self.ss.get_metric_value('mem.util.mlocked'), 1000),
+ scale(self.ss.get_metric_value('mem.util.inactive'), 1000),
+ scale(self.ss.get_metric_value('mem.util.swapTotal'), 1000),
+ scale(self.ss.get_metric_value('swap.used'), 1000),
+ scale(self.ss.get_metric_value('swap.free'), 1000),
+ scale(self.ss.get_metric_value('swap.pagesin'), 1000),
+ scale(self.ss.get_metric_value('swap.pagesout'), 1000),
+ scale(self.ss.get_metric_value('mem.vmstat.pgfault') -
+ self.ss.get_metric_value('mem.vmstat.pgmajfault'), 1000),
+ scale(self.ss.get_metric_value('mem.vmstat.pgmajfault'), 1000),
+ scale(self.ss.get_metric_value('mem.vmstat.pgpgin'), 1000),
+ scale(self.ss.get_metric_value('mem.vmstat.pgpgout'), 1000))
+
+
+# _netCollectPrint --------------------------------------------------
+
+
+class _netCollectPrint(_CollectPrint):
+ def print_header1_brief(self):
+ sys.stdout.write('<----------Network---------->')
+ def print_header1_detail(self):
+ print '# NETWORK STATISTICS (/sec)'
+ def print_header1_verbose(self):
+ print '\n\n# NETWORK SUMMARY (/sec)'
+ def print_header2_brief(self):
+ sys.stdout.write(' KBIn PktIn KBOut PktOut')
+ def print_header2_detail(self):
+ print '#Num Name KBIn PktIn SizeIn MultI CmpI ErrsI KBOut PktOut SizeO CmpO ErrsO'
+ def print_header2_verbose(self):
+ print '# KBIn PktIn SizeIn MultI CmpI ErrsI KBOut PktOut SizeO CmpO ErrsO'
+ def print_brief(self):
+ print "%5d %6d %6d %6d" % (
+ sum(self.ss.get_metric_value('network.interface.in.bytes')) / 1024,
+ sum(self.ss.get_metric_value('network.interface.in.packets')),
+ sum(self.ss.get_metric_value('network.interface.out.bytes')) / 1024,
+ sum(self.ss.get_metric_value('network.interface.out.packets'))),
+ def average_packet_size(self, bytes, packets):
+ # calculate mean packet size safely (note that divisor may be zero)
+ result = 0
+ bin = sum(self.ss.get_metric_value('network.interface.' + bytes))
+ pin = sum(self.ss.get_metric_value('network.interface.' + packets))
+ if pin > 0:
+ result = bin / pin
+ return result
+ def print_verbose(self):
+ # don't include loopback; TODO: pmDelProfile would be more appropriate
+ self.ss.get_metric_value('network.interface.in.bytes')[0] = 0
+ self.ss.get_metric_value('network.interface.out.bytes')[0] = 0
+ print '%6d %5d %6d %6d %6d %6d %6d %6d %6d %6d %7d' % (
+ sum(self.ss.get_metric_value('network.interface.in.bytes')) / 1024,
+ sum(self.ss.get_metric_value('network.interface.in.packets')),
+ self.average_packet_size('in.bytes', 'in.packets'),
+ sum(self.ss.get_metric_value('network.interface.in.mcasts')),
+ sum(self.ss.get_metric_value('network.interface.in.compressed')),
+ sum(self.ss.get_metric_value('network.interface.in.errors')),
+ sum(self.ss.get_metric_value('network.interface.out.bytes')) / 1024,
+ sum(self.ss.get_metric_value('network.interface.out.packets')),
+ self.average_packet_size('out.bytes', 'out.packets'),
+ sum(self.ss.get_metric_value('network.interface.total.mcasts')),
+ sum(self.ss.get_metric_value('network.interface.out.errors')))
+ def print_detail(self):
+ for j in xrange(len(self.ss.metric_pmids)):
+ try:
+ if self.ss.metrics[j] == 'network.interface.in.bytes':
+ (inst, iname) = pm.pmGetInDom(self.ss.metric_descs[j])
+ break
+ except pmapi.pmErr, e: # pylint: disable-msg=C0103
+ iname = "X"
+
+ for j in xrange(len(iname)):
+ print '%4d %-7s %6d %5d %6d %6d %6d %6d %6d %6d %6d %6d %7d' % (
+ j, iname[j],
+ self.ss.get_metric_value('network.interface.in.bytes')[j] / 1024,
+ self.ss.get_metric_value('network.interface.in.packets')[j],
+ self.divide_check(self.ss.get_metric_value('network.interface.in.bytes')[j],
+ self.ss.get_metric_value('network.interface.in.packets')[j]),
+ self.ss.get_metric_value('network.interface.in.mcasts')[j],
+ self.ss.get_metric_value('network.interface.in.compressed')[j],
+ self.ss.get_metric_value('network.interface.in.errors')[j],
+ self.ss.get_metric_value('network.interface.in.packets')[j],
+ self.ss.get_metric_value('network.interface.out.packets')[j],
+ self.divide_check(self.ss.get_metric_value('network.interface.in.packets')[j],
+ self.ss.get_metric_value('network.interface.out.packets')[j]) / 1024,
+ self.ss.get_metric_value('network.interface.total.mcasts')[j],
+ self.ss.get_metric_value(
+ 'network.interface.out.compressed')[j])
+
+class _Options(object):
+ def __init__(self):
+ self.subsys_arg = ""
+ self.verbosity = "brief"
+ self.input_file = ""
+ self.output_file = ""
+ self.archive = []
+ self.host = "local:"
+ self.create_archive = False
+ self.replay_archive = False
+ self.interval_arg = 1
+ self.n_samples = 0
+ self.duration_arg = 0
+ self.opts = self.setup()
+
+ def setup(self):
+ """ Setup default command line argument option handling """
+ opts = pmapi.pmOptions()
+ opts.pmSetOptionCallback(self.option_callback)
+ opts.pmSetOverrideCallback(self.override)
+ opts.pmSetShortOptions("vp:c:f:R:i:s:h:?")
+ opts.pmSetLongOptionHeader("Options")
+ opts.pmSetLongOption("verbose", 0, 'v', '', "Produce verbose output")
+ opts.pmSetLongOption("playback", 0, 'p', '', "Read sample data from file")
+ opts.pmSetLongOption("count", 1, 'c', 'COUNT', "Number of samples")
+ opts.pmSetLongOption("filename", 1, 'f', 'FILENAME', "Name of output file")
+ opts.pmSetLongOption("runtime", 1, 'R', 'N', "How long to take samples")
+ opts.pmSetLongOption("interval", 1, 'i', 'N', "The sample time interval")
+ opts.pmSetLongOption("subsys", 1, 's', 'SUBSYS', "The subsystem to sample")
+ opts.pmSetShortUsage("[options]\nInteractive: [-v] [-h host] [-s subsys] [-c N] [-i N] [-R N]\nWrite raw logfile: pmcollectl -f rawfile [-c N] [-i N] [-R N]\nRead raw logfile: pmcollectl -p rawfile")
+ opts.pmSetLongOptionHost()
+ opts.pmSetLongOptionVersion()
+ opts.pmSetLongOptionHelp()
+ return opts
+
+
+ def override(self, opt):
+ """ Override a few standard PCP options to match free(1) """
+ # pylint: disable=R0201
+ if opt == 's' or opt == 'i' or opt == 'h' or opt == "p":
+ return 1
+ return 0
+
+ def option_callback(self, opt, optarg, index):
+ """ Perform setup for an individual command line option """
+
+ s_options = {"d":[disk, "brief"], "D":[disk, "detail"],
+ "c":[cpu, "brief"], "C":[cpu, "detail"],
+ "n":[net, "brief"], "N":[net, "detail"],
+ "j":[interrupt, "brief"], "J":[interrupt, "detail"],
+ "m":[memory, "brief"], # "M":[ss, "detail"],
+ }
+
+ # pylint: disable=W0613
+ if opt == 's':
+ for ssx in xrange(len(optarg)):
+ self.subsys_arg = optarg[ssx:ssx+1]
+ try:
+ subsys.append(s_options[self.subsys_arg][0])
+ except KeyError:
+ print sys.argv[0] + \
+ ": Unimplemented subsystem -s" + self.subsys_arg
+ sys.exit(1)
+ if self.subsys_arg.isupper():
+ self.verbosity = s_options[self.subsys_arg][1]
+ elif opt == 'R':
+ self.duration_arg = optarg
+ elif opt == 'p':
+ self.opts.pmSetOptionArchiveFolio(optarg)
+ self.input_file = optarg
+ self.replay_archive = True
+ elif opt == 'f':
+ self.output_file = optarg
+ self.create_archive = True
+ elif opt == 'v':
+ if self.verbosity != "detail":
+ self.verbosity = "verbose"
+ elif opt == 'i':
+ self.opts.pmSetOptionInterval(optarg)
+ self.interval_arg = self.opts.pmGetOptionInterval()
+ elif opt == 'c':
+ self.opts.pmSetOptionSamples(optarg)
+ self.n_samples = int(self.opts.pmGetOptionSamples())
+ elif opt == 'h':
+ self.host = optarg
+
+# main -----------------------------------------------------------------
+
+
+# ignore These are actually global names; ignore invalid name warning for now
+# TODO move main into a def and enable
+# pylint: disable-msg=C0103
+
+
+if __name__ == '__main__':
+ subsys = list()
+ output_file = ""
+ input_file = ""
+ duration = 0.0
+
+ ss = Subsystem()
+ ss.init_processor_metrics()
+ ss.init_interrupt_metrics()
+ ss.init_disk_metrics()
+ ss.init_memory_metrics()
+ ss.init_network_metrics()
+
+ cpu = _cpuCollectPrint(ss)
+ interrupt = _interruptCollectPrint(ss)
+ disk = _diskCollectPrint(ss)
+ memory = _memoryCollectPrint(ss)
+ net = _netCollectPrint(ss)
+
+ # Establish a PMAPI context to archive, host or local, via args
+ opts = _Options()
+ if c_api.pmGetOptionsFromList(sys.argv) != 0:
+ c_api.pmUsageMessage()
+ sys.exit(1)
+
+ if len(subsys) == 0:
+ if opts.create_archive:
+ map(subsys.append, (cpu, disk, net, interrupt, memory))
+ else:
+ map(subsys.append, (cpu, disk, net))
+
+ if opts.duration_arg != 0:
+ (timeval, errmsg) = pm.pmParseInterval(str(opts.duration_arg))
+ duration = c_api.pmtimevalToReal(timeval)
+
+ pm = pmapi.pmContext.fromOptions(opts.opts, sys.argv)
+ if pm.type == c_api.PM_CONTEXT_ARCHIVE:
+ pm.pmSetMode(c_api.PM_MODE_FORW, pmapi.timeval(0, 0), 0)
+
+ # Find server-side pmcd host-name
+ host = pm.pmGetContextHostName()
+
+ (delta, errmsg) = pmapi.pmContext.pmParseInterval(str(opts.interval_arg) + " seconds")
+
+ if opts.create_archive:
+ delta_seconds = c_api.pmtimevalToReal(delta.tv_sec, delta.tv_usec)
+ msec = str(int(1000.0 * delta_seconds))
+ configuration = "log mandatory on every " + msec + " milliseconds { "
+ configuration += ss.dump_metrics()
+ configuration += "}"
+ if duration == 0.0:
+ if opts.n_samples != 0:
+ duration = float(opts.n_samples) * delta_seconds
+ else:
+ duration = float(10) * delta_seconds
+ record(pmgui.GuiClient(), configuration, duration, opts.output_file, host)
+ record_add_creator(opts.output_file)
+ sys.exit(0)
+
+ try:
+ ss.setup_metrics(pm)
+ ss.get_stats(pm)
+ except pmapi.pmErr, e:
+ if opts.replay_archive:
+ import textwrap
+ print "One of the following metrics is required " + \
+ "but absent in " + input_file + "\n" + \
+ textwrap.fill(str(ss.metrics))
+ else:
+ print "unable to setup metrics"
+ sys.exit(1)
+
+ for ssx in subsys:
+ ssx.set_verbosity(opts.verbosity)
+
+ # brief headings for different subsystems are concatenated together
+ if opts.verbosity == "brief":
+ for ssx in subsys:
+ if ssx == 0:
+ continue
+ ssx.print_header1()
+ print
+ for ssx in subsys:
+ if ssx == 0:
+ continue
+ ssx.print_header2()
+ print
+
+ try:
+ i_samples = 0
+ while (i_samples < opts.n_samples) or (opts.n_samples == 0):
+ pm.pmtimevalSleep(delta)
+ if opts.verbosity != "brief" and len(subsys) > 1:
+ print "\n### RECORD %d >>> %s <<< %s ###" % \
+ (i_samples+1, host, time.strftime("%a %b %d %H:%M:%S %Y"))
+
+ try:
+ ss.get_stats(pm)
+ ss.get_total()
+ for ssx in subsys:
+ if ssx == 0:
+ continue
+ if opts.verbosity != "brief" and (len(subsys) > 1 or i_samples == 0):
+ print
+ ssx.print_header1()
+ ssx.print_header2()
+ ssx.print_line()
+ if opts.verbosity == "brief":
+ print
+ except pmapi.pmErr, e:
+ if str(e).find("PM_ERR_EOL") != -1:
+ print str(e)
+ break
+
+ i_samples += 1
+ except KeyboardInterrupt:
+ True # pylint: disable-msg=W0104