#!/usr/bin/env pmpython # # Copyright (c) 2013-2016,2018 Red Hat. # Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. # # 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. # # pylint: disable=bare-except,missing-docstring,unnecessary-lambda,too-few-public-methods # get python3-compatible incremental line printing from __future__ import print_function import sys from pcp import pmapi import cpmapi as c_api class sampler(object): def __init__(self, fg): self.fg = fg self.load1 = fg.extend_item('kernel.all.load', instance='1 minute') self.load15 = fg.extend_item('kernel.all.load', instance='15 minute') self.cpu_user = fg.extend_indom('kernel.percpu.cpu.user', scale='second/second') self.cpu_sys = fg.extend_indom('kernel.percpu.cpu.sys', scale='second/second') self.freemem = fg.extend_item('mem.freemem', scale='Mbyte', mtype=c_api.PM_TYPE_DOUBLE) self.dkiops = fg.extend_item('disk.all.total', scale='count/second') self.timestamp = fg.extend_timestamp() self.ncpu = fg.extend_item('hinv.ncpu') def get_sample(self): self.fg.fetch() # compute overall cpu utilization; identify peak self.cpu_util = 0 self.peak_cpu_util = -1 self.peak_cpu = 0 for (ucode, _, uvalue), (scode, _, svalue) in zip(self.cpu_user(), self.cpu_sys()): assert ucode == scode # indoms should match try: util = uvalue() + svalue() # small errors are possible, so clip the utilization at 1.0 util = min(util, 1.0) except: # suspect PM_ERR_AGAIN from first-step rate-calculation util = 0 self.cpu_util += util if util > self.peak_cpu_util: self.peak_cpu_util = util self.peak_cpu = ucode self.cpu_util /= self.ncpu() class pmclient_fg(object): def option_override(self, opt): if opt == 'p': return 1 return 0 def option(self, opt, optarg, index): if opt == 'p': self.pause = True def __init__(self, argv): self.pause = False opts = pmapi.pmOptions() opts.pmSetShortOptions('A:a:D:gh:n:O:p:S:s:T:t:VZ:z?P') # PMAPI_OPTIONS + 'P' opts.pmSetOptionFlags(c_api.PM_OPTFLAG_STDOUT_TZ) opts.pmSetLongOptionText('Reporting options') opts.pmSetLongOption('pause', 0, 'p', '', 'pause between updates for archive replay') opts.pmSetLongOptionArchive() opts.pmSetLongOptionHost() opts.pmSetOptionCallback(lambda opt, optarg, index: self.option(opt, optarg, index)) opts.pmSetOverrideCallback(lambda opt: self.option_override(opt)) # .... etc; the python pmOptions should have a function for the PMAPI_OPTIONS common set self.opts = opts c_api.pmGetOptionsFromList(argv) self.typed = opts.pmGetOptionContext() if self.typed == c_api.PM_CONTEXT_ARCHIVE: target = opts.pmGetOptionArchives()[0] elif self.typed == c_api.PM_CONTEXT_HOST: if self.pause: raise pmapi.pmUsageErr target = opts.pmGetOptionHosts()[0] else: self.typed = c_api.PM_CONTEXT_HOST target = 'local:' self.fg = pmapi.fetchgroup(self.typed, target) self.ctx = self.fg.get_context() # for other pmOptions related to archive time offsets, etc.: # opts.pmSetContextOptions(ctx, ....) ? self.host = self.ctx.pmGetContextHostName() def run(self): info = sampler(self.fg) if self.opts.pmGetOptionSamples(): samples = self.opts.pmGetOptionSamples() else: samples = -1 if self.opts.pmGetOptionInterval(): interval = self.opts.pmGetOptionInterval() else: interval = pmapi.timeval(5, 0) if self.typed == c_api.PM_CONTEXT_ARCHIVE: info.get_sample() # fetch the separate early ncpu record info.get_sample() # fetch other rate metrics lines = 0 while True: if samples >= 0: if samples == 0: break samples -= 1 if lines % 15 == 0: if self.typed == c_api.PM_CONTEXT_ARCHIVE: print('Archive: %s, ' % self.opts.pmGetOptionArchives()[0], end='') print('Host: %s, %d cpu(s), %s' % (self.host, info.ncpu(), info.timestamp())) # - report format # CPU Busy Busy Free Mem Disk Load Average # Util CPU Util (Mbytes) IOPS 1 Min 15 Min #X.XXX XXX X.XXX XXXXX.XXX XXXXXX XXXX.XX XXXX.XX print(' CPU', end='') if info.ncpu() > 1: print(' Busy Busy', end='') print(' Free Mem Disk Load Average') print(' Util', end='') if info.ncpu() > 1: print(' CPU Util', end='') print(' (Mbytes) IOPS 1 Min 15 Min') if self.typed != c_api.PM_CONTEXT_ARCHIVE or self.pause: self.ctx.pmtimevalSleep(interval) info.get_sample() print('%5.2f' % info.cpu_util, end='') if info.ncpu() > 1: print(' %3d %5.2f' % (info.peak_cpu, info.peak_cpu_util), end='') print(' %9.3f' % info.freemem(), end='') print(' %6d' % info.dkiops(), end='') print(' %7.2f %7.2f' % (info.load1(), info.load15())) lines += 1 if __name__ == '__main__': try: pmclient = pmclient_fg(sys.argv) pmclient.run() except pmapi.pmErr as error: sys.stderr.write('%s: %s\n' % (error.progname(), error.message())) except KeyboardInterrupt: sys.exit(0)