diff --git a/src/pcp/pidstat/pcp-pidstat.py b/src/pcp/pidstat/pcp-pidstat.py index d29ee256fe..5383b1a148 100755 --- a/src/pcp/pidstat/pcp-pidstat.py +++ b/src/pcp/pidstat/pcp-pidstat.py @@ -18,6 +18,7 @@ # pylint: disable=redefined-outer-name,unnecessary-lambda # +import os import sys import re import time @@ -589,16 +590,22 @@ def __matches_process_name(self, process): return True # all match def __matches_process_priority(self, process): + if not isinstance(process, ProcessPriority): + return True if self.options.show_process_priority and process.priority() is not None: return process.priority() > 0 return True def __matches_process_memory_util(self, process): + if not isinstance(process, ProcessMemoryUtil): + return True if self.options.show_process_memory_util and process.vsize() is not None: return process.vsize() > 0 return True def __matches_process_stack_size(self, process): + if not isinstance(process, ProcessStackUtil): + return True if self.options.show_process_stack_util and process.stack_size() is not None: return process.stack_size() > 0 return True @@ -775,35 +782,63 @@ def Print(self, args): class PidstatOptions(pmapi.pmOptions): - process_name = None - process_name_with_args = False - ps_args_flag=False - show_process_memory_util = False - show_process_priority = False - show_process_stack_util = False - per_processor_usage = False - show_process_user = False - show_process_state = False - flag_error = False - filtered_process_user = None - state = "" - filterstate = [] - pid_filter = None - pid_list = [] - timefmt = "%H:%M:%S" + + #After reading in the provided command line options + #initalize them by passing them in + def __init__(self): + pmapi.pmOptions.__init__(self,"a:s:t:G:IU::p:RrukVZ:z?:f:B:l") + self.pmSetOptionCallback(self.extraOptions) + self.pmSetOverrideCallback(self.override) + self.pmSetLongOptionHeader("General options") + self.pmSetLongOptionArchive() + self.pmSetLongOptionSamples() + self.pmSetLongOptionInterval() + self.pmSetLongOption("process-name", 1, "G", "NAME", + "Select process names using regular expression.") + self.pmSetLongOption("", 0, "I", "", "Show CPU usage per processor.") + self.pmSetLongOption("user-name", 2, "U","[USERNAME]", + "Show real user name of the tasks and optionally filter by user name.") + self.pmSetLongOption("pid-list", 1, "p", "PID1,PID2.. ", + "Show stats for specified pids; " + + "use SELF for current process and ALL for all processes.") + self.pmSetLongOption("", 0, "R", "", + "Report realtime priority and scheduling policy information.") + self.pmSetLongOption("", 0,"r","","Report page faults and memory utilization.") + self.pmSetLongOption("", 0,"u","","Report CPU utilization.") + self.pmSetLongOption("", 0,"k","","Report stack utilization.") + self.pmSetLongOption("", 0,"f","","Format the timestamp output") + self.pmSetLongOption("", 0, "B", "state1,state2,..", + "Report process state information. " + + "Use -B [all] or -B [comma separated states]. " + + "Use -B detail for showing time spent in every state per process") + self.pmSetLongOptionVersion() + self.pmSetLongOptionTimeZone() + self.pmSetLongOptionHostZone() + self.pmSetLongOption("", 0, "l", "", "Display the process command name and all its arguments.") + self.pmSetLongOptionHelp() + + self.process_name = None + self.process_name_with_args = False + self.ps_args_flag=False + self.show_process_cpu_util = False + self.show_process_memory_util = False + self.show_process_priority = False + self.show_process_stack_util = False + self.per_processor_usage = False + self.show_process_user = False + self.show_process_state = False + self.flag_error = False + self.filtered_process_user = None + self.state = "" + self.filterstate = [] + self.pid_filter = None + self.pid_list = [] + self.timefmt = "%H:%M:%S" def checkOptions(self): - if self.show_process_priority and self.show_process_memory_util: - print("Error: -R is incompatible with -r") - return False - elif self.show_process_priority and self.show_process_stack_util: - print("Error: -R is incompatible with -k") - return False - elif self.show_process_memory_util and self.show_process_stack_util: - print("Error: -r is incompatible with -k") - return False - elif (self.show_process_memory_util or self.show_process_stack_util or - self.show_process_priority) and self.show_process_state: + if ((self.show_process_memory_util or self.show_process_stack_util or + self.show_process_priority or self.show_process_cpu_util) and + self.show_process_state): print("Error: Incompatible flags provided") return False elif self.flag_error: @@ -812,26 +847,33 @@ def checkOptions(self): elif self.ps_args_flag: print("Error: Incorrect usage of the -l flag") return False - else: + elif self.show_process_state or self.show_process_cpu_util: return True + # Determine if we are defaulting to -u. + if not any([self.show_process_memory_util, self.show_process_stack_util, + self.show_process_priority]): + self.show_process_cpu_util = True + return True - def extraOptions(self, opt,optarg, index): - if opt == 'k': - PidstatOptions.show_process_stack_util = True + def extraOptions(self, opt, optarg, index): + if opt == 'u': + self.show_process_cpu_util = True + elif opt == 'k': + self.show_process_stack_util = True elif opt == 'r': - PidstatOptions.show_process_memory_util = True + self.show_process_memory_util = True elif opt == 'R': - PidstatOptions.show_process_priority = True - #process state + self.show_process_priority = True elif opt == 'B': - if PidstatOptions.show_process_state: + #process state + if self.show_process_state: #print("Error: Cannot use -B multiple times") - PidstatOptions.flag_error = True - PidstatOptions.show_process_state = True + self.flag_error = True + self.show_process_state = True if optarg in ["All", "all"]: - PidstatOptions.filterstate = "all" + self.filterstate = "all" elif optarg in ["detail", "Detail"]: - PidstatOptions.filterstate = "detail" + self.filterstate = "detail" else: # tried to handle the error usage like pcp-pidstat.py -B all R,S # or pcp-pidstat.py -B detail all @@ -839,84 +881,58 @@ def extraOptions(self, opt,optarg, index): # we ignore the following ones. So pcp-pidstat.py -B detail all will treat it as # pcp.pidstat.py -B detail - #if not PidstatOptions.flag_error: - # if (PidstatOptions.filterstate == "all" or PidstatOptions.filterstate == "detail"): + #if not self.flag_error: + # if (self.filterstate == "all" or self.filterstate == "detail"): # print("Error: Use either all/detail or specific filters for states") - # PidstatOptions.flag_error = True + # self.flag_error = True # else: # need to put checks for correct states in this string like UN,TT # shouldnt be accepted because TT isnt a valid state # TODO: make sure only R,S,T,D,Z are part of this optarg so if # anything other than these exists in - # PidstatOptions.filterstate, we might want to flag error of usage ? + # self.filterstate, we might want to flag error of usage ? - PidstatOptions.filterstate += optarg.replace(',', ' ').split(' ') + self.filterstate += optarg.replace(',', ' ').split(' ') elif opt == 'G': - PidstatOptions.process_name = optarg + self.process_name = optarg elif opt == 'I': - PidstatOptions.per_processor_usage = True + self.per_processor_usage = True elif opt == 'U': - PidstatOptions.show_process_user = True - PidstatOptions.filtered_process_user = optarg + self.show_process_user = True + self.filtered_process_user = optarg elif opt == 'p': - if optarg in ["ALL", "SELF"]: - PidstatOptions.pid_filter = optarg + if optarg == "ALL": + self.pid_filter = None + elif optarg == "SELF": + self.pid_filter = "SELF" + self.pid_list = os.getpid() else: - PidstatOptions.pid_filter = "ALL" + self.pid_filter = "LIST" try: - PidstatOptions.pid_list = list(map(lambda x:int(x),optarg.split(','))) + self.pid_list = list(map(lambda x:int(x),optarg.split(','))) except ValueError: print("Invalid Process Id List: use comma separated pids without whitespaces") sys.exit(1) elif opt == 'f': - PidstatOptions.timefmt = optarg + self.timefmt = optarg elif opt == 'l': - if PidstatOptions.process_name_with_args: - PidstatOptions.ps_args_flag=True - PidstatOptions.process_name_with_args = True + if self.process_name_with_args: + self.ps_args_flag=True + self.process_name_with_args = True def override(self, opt): """ Override standard PCP options to match pidstat(1) """ return bool(opt == 'p') - #After reading in the provided command line options - #initalize them by passing them in - def __init__(self): - pmapi.pmOptions.__init__(self,"a:s:t:G:IU::p:RrkVZ:z?:f:B:l") - self.pmSetOptionCallback(self.extraOptions) - self.pmSetOverrideCallback(self.override) - self.pmSetLongOptionHeader("General options") - self.pmSetLongOptionArchive() - self.pmSetLongOptionSamples() - self.pmSetLongOptionInterval() - self.pmSetLongOption("process-name", 1, "G", "NAME", - "Select process names using regular expression.") - self.pmSetLongOption("", 0, "I", "", "Show CPU usage per processor.") - self.pmSetLongOption("user-name", 2, "U","[USERNAME]", - "Show real user name of the tasks and optionally filter by user name.") - self.pmSetLongOption("pid-list", 1, "p", "PID1,PID2.. ", - "Show stats for specified pids; " + - "use SELF for current process and ALL for all processes.") - self.pmSetLongOption("", 0, "R", "", - "Report realtime priority and scheduling policy information.") - self.pmSetLongOption("", 0,"r","","Report page faults and memory utilization.") - self.pmSetLongOption("", 0,"k","","Report stack utilization.") - self.pmSetLongOption("", 0,"f","","Format the timestamp output") - self.pmSetLongOption("", 0, "B", "state1,state2,..", - "Report process state information. " + - "Use -B [all] or -B [comma separated states]. " + - "Use -B detail for showing time spent in every state per process") - self.pmSetLongOptionVersion() - self.pmSetLongOptionTimeZone() - self.pmSetLongOptionHostZone() - self.pmSetLongOption("", 0, "l", "", "Display the process command name and all its arguments.") - self.pmSetLongOptionHelp() - class PidstatReport(pmcc.MetricGroupPrinter): Machine_info_count = 0 + def __init__(self, opts): + pmcc.MetricGroupPrinter.__init__(self) + self.opts = opts + def timeStampDelta(self, group): s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec @@ -959,86 +975,79 @@ def report(self,manager): return ts = group.contextCache.pmLocaltime(int(group.timestamp)) - timestamp = time.strftime(PidstatOptions.timefmt, ts.struct_time()) + timestamp = time.strftime(self.opts.timefmt, ts.struct_time()) interval_in_seconds = self.timeStampDelta(group) header_indentation = " " if len(timestamp)<9 else (len(timestamp)-7)*" " value_indentation = ((len(header_indentation)+9)-len(timestamp))*" " metric_repository = ReportingMetricRepository(group) - if PidstatOptions.show_process_stack_util: - process_stack_util = CpuProcessStackUtil(metric_repository) - process_filter = ProcessFilter(PidstatOptions) - stdout = StdoutPrinter() - printdecorator = NoneHandlingPrinterDecorator(stdout) - report = CpuProcessStackUtilReporter(process_stack_util, process_filter, - printdecorator.Print, PidstatOptions) - - report.print_report(timestamp, header_indentation, value_indentation) - elif PidstatOptions.show_process_memory_util: - process_memory_util = CpuProcessMemoryUtil(metric_repository) - process_filter = ProcessFilter(PidstatOptions) - stdout = StdoutPrinter() - printdecorator = NoneHandlingPrinterDecorator(stdout) - report = CpuProcessMemoryUtilReporter(process_memory_util, process_filter, - interval_in_seconds, - printdecorator.Print, PidstatOptions) - - report.print_report(timestamp, header_indentation, value_indentation) - elif PidstatOptions.show_process_priority: - process_priority = CpuProcessPriorities(metric_repository) - process_filter = ProcessFilter(PidstatOptions) - stdout = StdoutPrinter() - printdecorator = NoneHandlingPrinterDecorator(stdout) - report = CpuProcessPrioritiesReporter(process_priority, process_filter, - printdecorator.Print, PidstatOptions) - - report.print_report(timestamp, header_indentation, value_indentation) - - #=========================================================================================================== - elif PidstatOptions.show_process_state: + if self.opts.show_process_state: process_state = CpuProcessState(metric_repository) - process_filter = ProcessFilter(PidstatOptions) + process_filter = ProcessFilter(self.opts) stdout = StdoutPrinter() printdecorator = NoneHandlingPrinterDecorator(stdout) report = CpuProcessStateReporter(process_state, process_filter, interval_in_seconds, - printdecorator.Print, PidstatOptions) - + printdecorator.Print, self.opts) report.print_report(timestamp, header_indentation, value_indentation) - #=========================================================================================================== else: - cpu_usage = CpuUsage(metric_repository) - process_filter = ProcessFilter(PidstatOptions) - stdout = StdoutPrinter() - printdecorator = NoneHandlingPrinterDecorator(stdout) - report = CpuUsageReporter(cpu_usage, process_filter, interval_in_seconds, - printdecorator.Print, PidstatOptions) - report.print_report(timestamp, ncpu, header_indentation, value_indentation) + if self.opts.show_process_stack_util: + process_stack_util = CpuProcessStackUtil(metric_repository) + process_filter = ProcessFilter(self.opts) + stdout = StdoutPrinter() + printdecorator = NoneHandlingPrinterDecorator(stdout) + report = CpuProcessStackUtilReporter(process_stack_util, process_filter, + printdecorator.Print, self.opts) + report.print_report(timestamp, header_indentation, value_indentation) + + if self.opts.show_process_memory_util: + process_memory_util = CpuProcessMemoryUtil(metric_repository) + process_filter = ProcessFilter(self.opts) + stdout = StdoutPrinter() + printdecorator = NoneHandlingPrinterDecorator(stdout) + report = CpuProcessMemoryUtilReporter(process_memory_util, process_filter, + interval_in_seconds, + printdecorator.Print, self.opts) + report.print_report(timestamp, header_indentation, value_indentation) + + if self.opts.show_process_priority: + process_priority = CpuProcessPriorities(metric_repository) + process_filter = ProcessFilter(self.opts) + stdout = StdoutPrinter() + printdecorator = NoneHandlingPrinterDecorator(stdout) + report = CpuProcessPrioritiesReporter(process_priority, process_filter, + printdecorator.Print, self.opts) + report.print_report(timestamp, header_indentation, value_indentation) + + if self.opts.show_process_cpu_util: + cpu_usage = CpuUsage(metric_repository) + process_filter = ProcessFilter(self.opts) + stdout = StdoutPrinter() + printdecorator = NoneHandlingPrinterDecorator(stdout) + report = CpuUsageReporter(cpu_usage, process_filter, interval_in_seconds, + printdecorator.Print, self.opts) + report.print_report(timestamp, ncpu, header_indentation, value_indentation) if __name__ == "__main__": try: opts = PidstatOptions() - manager = pmcc.MetricGroupManager.builder(opts,sys.argv) + manager = pmcc.MetricGroupManager.builder(opts, sys.argv) if not opts.checkOptions(): raise pmapi.pmUsageErr if opts.show_process_state: - missing = manager.checkMissingMetrics(PIDSTAT_METRICS_B) + metrics_list = PIDSTAT_METRICS_B elif opts.process_name_with_args: - missing = manager.checkMissingMetrics(PIDSTAT_METRICS_L) + metrics_list = PIDSTAT_METRICS_L else: - missing = manager.checkMissingMetrics(PIDSTAT_METRICS) + metrics_list = PIDSTAT_METRICS + missing = manager.checkMissingMetrics(metrics_list) if missing is not None: sys.stderr.write('Error: not all required metrics are available\nMissing %s\n' % (missing)) sys.exit(1) - if opts.process_name_with_args: - manager['pidstat'] = PIDSTAT_METRICS_L - elif opts.show_process_state: - manager['pidstat'] = PIDSTAT_METRICS_B - else: - manager['pidstat'] = PIDSTAT_METRICS - manager.printer = PidstatReport() + manager['pidstat'] = metrics_list + manager.printer = PidstatReport(opts) sts = manager.run() sys.exit(sts) except pmapi.pmErr as pmerror: