pcp-mpstat: gracefully handle the absence of interrupt metrics
[pcp.git] / src / pcp / mpstat / pcp-mpstat.py
blob41ebbaec1d9eeeb0dabfca668e9e3977427a121b
1 #!/usr/bin/env pmpython
3 # Copyright (C) 2016 Sitaram Shelke.
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 # for more details.
16 from pcp import pmapi
17 from pcp import pmcc
18 import sys
19 import time
20 MPSTAT_METRICS = ['kernel.uname.nodename', 'kernel.uname.release', 'kernel.uname.sysname',
21 'kernel.uname.machine', 'hinv.map.cpu_num', 'hinv.ncpu', 'hinv.cpu.online',
22 'kernel.all.cpu.user',
23 'kernel.all.cpu.nice', 'kernel.all.cpu.sys', 'kernel.all.cpu.wait.total',
24 'kernel.all.cpu.irq.hard', 'kernel.all.cpu.irq.soft', 'kernel.all.cpu.steal',
25 'kernel.all.cpu.guest', 'kernel.all.cpu.guest_nice', 'kernel.all.cpu.idle',
26 'kernel.percpu.cpu.user', 'kernel.percpu.cpu.nice', 'kernel.percpu.cpu.sys',
27 'kernel.percpu.cpu.wait.total', 'kernel.percpu.cpu.irq.hard', 'kernel.percpu.cpu.irq.soft',
28 'kernel.percpu.cpu.steal', 'kernel.percpu.cpu.guest','kernel.percpu.cpu.guest_nice',
29 'kernel.percpu.cpu.idle', 'kernel.all.intr', 'kernel.percpu.intr']
30 interrupts_list = []
31 soft_interrupts_list = []
33 class StdoutPrinter:
34 def Print(self, args):
35 print(args)
37 class NamedInterrupts:
38 def __init__(self, context, metric):
39 self.context = context
40 self.interrupt_list = []
41 self.metric = metric
43 def append_callback(self, args):
44 self.interrupt_list.append(args)
46 def get_all_named_interrupt_metrics(self):
47 if not self.interrupt_list:
48 try:
49 self.context.pmTraversePMNS(self.metric,self.append_callback)
50 except pmapi.pmErr as err:
51 if err.message() == "Unknown metric name":
52 pass
53 else:
54 raise
55 self.interrupt_list.reverse()
56 return self.interrupt_list
58 class MetricRepository:
59 def __init__(self,group):
60 self.group = group
61 self.current_cached_values = {}
62 self.previous_cached_values = {}
64 def current_value(self, metric, instance):
65 if not metric in self.group:
66 return None
67 if instance is not None:
68 if self.current_cached_values.get(metric, None) is None:
69 lst = self.__fetch_current_values(metric,instance)
70 self.current_cached_values[metric] = lst
72 return self.current_cached_values[metric].get(instance,None)
73 else:
74 if self.current_cached_values.get(metric, None) is None:
75 self.current_cached_values[metric] = self.__fetch_current_values(metric,instance)
76 return self.current_cached_values.get(metric, None)
78 def previous_value(self, metric, instance):
79 if not metric in self.group:
80 return None
81 if instance is not None:
82 if self.previous_cached_values.get(metric, None) is None:
83 lst = self.__fetch_previous_values(metric,instance)
84 self.previous_cached_values[metric] = lst
85 return self.previous_cached_values[metric].get(instance,None)
86 else:
87 if self.previous_cached_values.get(metric, None) is None:
88 self.previous_cached_values[metric] = self.__fetch_previous_values(metric,instance)
89 return self.previous_cached_values.get(metric, None)
91 def current_values(self, metric_name):
92 if self.group.get(metric_name, None) is None:
93 return None
94 if self.current_cached_values.get(metric_name, None) is None:
95 self.current_cached_values[metric_name] = self.__fetch_current_values(metric_name,True)
96 return self.current_cached_values.get(metric_name, None)
98 def previous_values(self, metric_name):
99 if self.group.get(metric_name, None) is None:
100 return None
101 if self.previous_cached_values.get(metric_name, None) is None:
102 self.previous_cached_values[metric_name] = self.__fetch_previous_values(metric_name,True)
103 return self.previous_cached_values.get(metric_name, None)
105 def __fetch_current_values(self,metric,instance):
106 if instance is not None:
107 return dict(map(lambda x: (x[0].inst, x[2]), self.group[metric].netValues))
108 else:
109 return self.group[metric].netValues[0][2]
111 def __fetch_previous_values(self,metric,instance):
112 if instance is not None:
113 return dict(map(lambda x: (x[0].inst, x[2]), self.group[metric].netPrevValues))
114 else:
115 if self.group[metric].netPrevValues == []:
116 return None
117 else:
118 return self.group[metric].netPrevValues[0][2]
121 class CoreCpuUtil:
122 def __init__(self, instance, delta_time, metric_repository):
123 self.delta_time = delta_time
124 self.instance = instance
125 self.metric_repository = metric_repository
127 def total_cpus(self):
128 return self.metric_repository.current_value('hinv.ncpu', None)
129 def cpu_number(self):
130 return self.instance
132 def cpu_online(self):
133 return self.metric_repository.current_value('hinv.cpu.online', self.instance)
135 def user_time(self):
136 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.user'
137 p_time = self.metric_repository.previous_value(metric, self.instance)
138 c_time = self.metric_repository.current_value(metric, self.instance)
139 if p_time is not None and c_time is not None:
140 value = (100*(c_time - p_time))/(1000*self.delta_time)
141 if self.instance is None:
142 return float("%.2f"%(value/self.total_cpus()))
143 else:
144 return float("%.2f"%(value))
146 else:
147 return None
149 def nice_time(self):
150 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.nice'
151 p_time = self.metric_repository.previous_value(metric, self.instance)
152 c_time = self.metric_repository.current_value(metric, self.instance)
153 if p_time is not None and c_time is not None:
154 value = (100*(c_time - p_time))/(1000*self.delta_time)
155 if self.instance is None:
156 return float("%.2f"%(value/self.total_cpus()))
157 else:
158 return float("%.2f"%(value))
159 else:
160 return None
162 def sys_time(self):
163 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.sys'
164 p_time = self.metric_repository.previous_value(metric, self.instance)
165 c_time = self.metric_repository.current_value(metric, self.instance)
166 if p_time is not None and c_time is not None:
167 value = (100*(c_time - p_time))/(1000*self.delta_time)
168 if self.instance is None:
169 return float("%.2f"%(value/self.total_cpus()))
170 else:
171 return float("%.2f"%(value))
172 else:
173 return None
175 def iowait_time(self):
176 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.wait.total'
177 p_time = self.metric_repository.previous_value(metric, self.instance)
178 c_time = self.metric_repository.current_value(metric, self.instance)
179 if p_time is not None and c_time is not None:
180 value = (100*(c_time - p_time))/(1000*self.delta_time)
181 if self.instance is None:
182 return float("%.2f"%(value/self.total_cpus()))
183 else:
184 return float("%.2f"%(value))
185 else:
186 return None
188 def irq_hard(self):
189 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.irq.hard'
190 p_time = self.metric_repository.previous_value(metric, self.instance)
191 c_time = self.metric_repository.current_value(metric, self.instance)
192 if p_time is not None and c_time is not None:
193 value = (100*(c_time - p_time))/(1000*self.delta_time)
194 if self.instance is None:
195 return float("%.2f"%(value/self.total_cpus()))
196 else:
197 return float("%.2f"%(value))
198 else:
199 return None
201 def irq_soft(self):
202 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.irq.soft'
203 p_time = self.metric_repository.previous_value(metric, self.instance)
204 c_time = self.metric_repository.current_value(metric, self.instance)
205 if p_time is not None and c_time is not None:
206 value = (100*(c_time - p_time))/(1000*self.delta_time)
207 if self.instance is None:
208 return float("%.2f"%(value/self.total_cpus()))
209 else:
210 return float("%.2f"%(value))
211 else:
212 return None
214 def steal(self):
215 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.steal'
216 p_time = self.metric_repository.previous_value(metric, self.instance)
217 c_time = self.metric_repository.current_value(metric, self.instance)
218 if p_time is not None and c_time is not None:
219 value = (100*(c_time - p_time))/(1000*self.delta_time)
220 if self.instance is None:
221 return float("%.2f"%(value/self.total_cpus()))
222 else:
223 return float("%.2f"%(value))
224 else:
225 return None
227 def guest_time(self):
228 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.guest'
229 p_time = self.metric_repository.previous_value(metric, self.instance)
230 c_time = self.metric_repository.current_value(metric, self.instance)
231 if p_time is not None and c_time is not None:
232 value = (100*(c_time - p_time))/(1000*self.delta_time)
233 if self.instance is None:
234 return float("%.2f"%(value/self.total_cpus()))
235 else:
236 return float("%.2f"%(value))
237 else:
238 return None
240 def guest_nice(self):
241 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.guest_nice'
242 p_time = self.metric_repository.previous_value(metric, self.instance)
243 c_time = self.metric_repository.current_value(metric, self.instance)
244 if p_time is not None and c_time is not None:
245 value = (100*(c_time - p_time))/(1000*self.delta_time)
246 if self.instance is None:
247 return float("%.2f"%(value/self.total_cpus()))
248 else:
249 return float("%.2f"%(value))
250 else:
251 return None
253 def idle_time(self):
254 metric = 'kernel.' + self.__all_or_percpu() + '.cpu.idle'
255 p_time = self.metric_repository.previous_value(metric, self.instance)
256 c_time = self.metric_repository.current_value(metric, self.instance)
257 if p_time is not None and c_time is not None:
258 value = (100*(c_time - p_time))/(1000*self.delta_time)
259 if self.instance is None:
260 return float("%.2f"%(value/self.total_cpus()))
261 else:
262 return float("%.2f"%(value))
263 else:
264 return None
266 def __all_or_percpu(self):
267 return 'all' if self.instance is None else 'percpu'
269 class CpuUtil:
270 def __init__(self, delta_time, metric_repository):
271 self.__metric_repository = metric_repository
272 self.delta_time = delta_time
274 def get_totalcpu_util(self):
275 return CoreCpuUtil(None, self.delta_time, self.__metric_repository)
277 def get_percpu_util(self):
278 return list(map((lambda cpuid: (CoreCpuUtil(cpuid, self.delta_time, self.__metric_repository))), self.__cpus()))
280 def __cpus(self):
281 cpu_dict = self.__metric_repository.current_values('hinv.map.cpu_num')
282 return sorted(cpu_dict.values())
283 class TotalCpuInterrupt:
284 def __init__(self, cpu_num, intr_value, metric_repository):
285 self.cpu_num = cpu_num
286 self.intr_value = intr_value
287 self.metric_repository = metric_repository
288 def cpu_number(self):
289 return self.cpu_num
290 def cpu_online(self):
291 return self.metric_repository.current_value('hinv.cpu.online', self.cpu_num)
292 def value(self):
293 return self.intr_value
295 class TotalInterruptUsage:
296 def __init__(self, delta_time, metric_repository):
297 self.delta_time = delta_time
298 self.__metric_repository = metric_repository
300 def total_interrupt_per_delta_time(self):
301 c_value = self.__metric_repository.current_value('kernel.all.intr', None)
302 p_value = self.__metric_repository.previous_value('kernel.all.intr', None)
303 if c_value is not None and p_value is not None:
304 return float("%.2f"%(float(c_value - p_value)/self.delta_time))
305 else:
306 return None
307 def total_interrupt_percpu_per_delta_time(self):
308 return list(map((lambda cpuid: TotalCpuInterrupt(cpuid, self.__get_cpu_total_interrupt(cpuid), self.__metric_repository)), self.__cpus()))
310 def __get_cpu_total_interrupt(self, instance):
311 c_value = self.__metric_repository.current_value('kernel.percpu.intr', instance)
312 p_value = self.__metric_repository.previous_value('kernel.percpu.intr', instance)
313 if c_value is not None and p_value is not None:
314 return float("%.2f"%(float(c_value - p_value)/self.delta_time))
315 else:
316 return None
318 def __cpus(self):
319 cpu_dict = self.__metric_repository.current_values('hinv.map.cpu_num')
320 return sorted(cpu_dict.values())
322 class InterruptUsage:
323 def __init__(self, delta_time, metric_repository, metric, instance):
324 self.__name = metric.split('.')[-1]
325 self.instance = instance
326 self.metric = metric
327 self.delta_time = delta_time
328 self.__metric_repository = metric_repository
330 def name(self):
331 if self.__name.startswith("line"):
332 return self.__name[4:]
333 return self.__name
335 def value(self):
336 c_value = self.__metric_repository.current_value(self.metric, self.instance)
337 p_value = self.__metric_repository.previous_value(self.metric, self.instance)
338 if c_value is not None and p_value is not None:
339 return float("%.2f"%((c_value - p_value)/self.delta_time))
340 else:
341 return None
343 class CpuInterrupts:
344 def __init__(self, metric_repository, cpu_number, interrupts):
345 self.metric_repository = metric_repository
346 self.cpu_num = cpu_number
347 self.interrupts = interrupts
348 def cpu_number(self):
349 return self.cpu_num
350 def cpu_online(self):
351 return self.metric_repository.current_value('hinv.cpu.online', self.cpu_num)
353 class HardInterruptUsage:
354 def __init__(self, delta_time, metric_repository, interrupt_metrics):
355 self.delta_time = delta_time
356 self.metric_repository = metric_repository
357 self.interrupt_metrics = interrupt_metrics
359 def get_percpu_interrupts(self):
360 return list(map((lambda cpuid: CpuInterrupts(self.metric_repository, cpuid, self.__get_all_interrupts_for_cpu(cpuid))), self.__cpus()))
362 def __cpus(self):
363 cpu_dict = self.metric_repository.current_values('hinv.map.cpu_num')
364 return sorted(cpu_dict.values())
366 def __get_all_interrupts_for_cpu(self, cpuid):
367 return list(map((lambda metric: InterruptUsage(self.delta_time, self.metric_repository, metric, cpuid)), self.interrupt_metrics))
369 class SoftInterruptUsage:
370 def __init__(self, delta_time, metric_repository, interrupt_metrics):
371 self.delta_time = delta_time
372 self.metric_repository = metric_repository
373 self.interrupt_metrics = interrupt_metrics
375 def get_percpu_interrupts(self):
376 return list(map((lambda cpuid: CpuInterrupts(self.metric_repository, cpuid, self.__get_all_interrupts_for_cpu(cpuid))), self.__cpus()))
378 def __cpus(self):
379 cpu_dict = self.metric_repository.current_values('hinv.map.cpu_num')
380 return sorted(cpu_dict.values())
382 def __get_all_interrupts_for_cpu(self, cpuid):
383 return list(map((lambda metric: InterruptUsage(self.delta_time, self.metric_repository, metric, cpuid)), self.interrupt_metrics))
386 class CpuFilter:
387 def __init__(self, mpstat_options):
388 self.mpstat_options = mpstat_options
390 def filter_cpus(self, cpus):
391 return list(filter(lambda c: self.__matches_cpu(c), cpus))
393 def __matches_cpu(self, cpu):
394 if self.mpstat_options.cpu_list == 'ALL':
395 return True
396 elif self.mpstat_options.cpu_list == 'ON':
397 if cpu.cpu_online() == 1:
398 return True
399 else:
400 return False
401 elif self.mpstat_options.cpu_list is not None:
402 if cpu.cpu_number() in self.mpstat_options.cpu_list:
403 return True
404 else:
405 return False
406 else:
407 return True
409 class CpuUtilReporter:
410 def __init__(self, cpu_filter, printer, mpstat_options):
411 self.cpu_filter = cpu_filter
412 self.printer = printer
413 self.mpstat_options = mpstat_options
414 self.header_print = True
416 def print_report(self, cpu_utils, timestamp):
417 if self.header_print:
418 self.printer("\n%-10s\t%-3s\t%-5s\t%-6s\t%-5s\t%-8s\t%-5s\t%-6s\t%-7s\t%-7s\t%-6s\t%-6s"%("Timestamp","CPU","%usr","%nice","%sys","%iowait","%irq","%soft","%steal","%guest","%nice","%idle"))
419 self.header_print = False
420 if self.mpstat_options.cpu_list == "ALL" or self.mpstat_options.cpu_list == "ON":
421 self.header_print = True
422 if type(self.mpstat_options.cpu_list) != type([]):
423 cpu_util = cpu_utils.get_totalcpu_util()
424 self.printer("%-10s\t%-3s\t%-5s\t%-6s\t%-5s\t%-8s\t%-5s\t%-6s\t%-7s\t%-7s\t%-6s\t%-6s"%(timestamp,"all",
425 cpu_util.user_time(), cpu_util.nice_time(), cpu_util.sys_time(), cpu_util.iowait_time(),
426 cpu_util.irq_hard(), cpu_util.irq_soft(), cpu_util.steal(), cpu_util.guest_time(),
427 cpu_util.guest_nice(), cpu_util.idle_time()))
428 if self.mpstat_options.cpu_filter == True:
429 cpu_util_list = self.cpu_filter.filter_cpus(cpu_utils.get_percpu_util())
430 for cpu_util in cpu_util_list:
431 self.printer("%-10s\t%-3s\t%-5s\t%-6s\t%-5s\t%-8s\t%-5s\t%-6s\t%-7s\t%-7s\t%-6s\t%-6s"%(timestamp,
432 cpu_util.cpu_number(), cpu_util.user_time(), cpu_util.nice_time(), cpu_util.sys_time(),
433 cpu_util.iowait_time(), cpu_util.irq_hard(), cpu_util.irq_soft(), cpu_util.steal(),
434 cpu_util.guest_time(), cpu_util.guest_nice(), cpu_util.idle_time()))
436 class TotalInterruptUsageReporter:
437 def __init__(self, cpu_filter, printer, mpstat_options):
438 self.cpu_filter = cpu_filter
439 self.printer = printer
440 self.mpstat_options = mpstat_options
441 self.print_header = True
443 def print_report(self, total_interrupt_usage, timestamp):
444 self.total_interrupt_usage = total_interrupt_usage
445 if self.print_header:
446 self.printer("%-10s\t%-5s\t%-5s"%("\nTimestamp","CPU","intr/s"))
447 self.print_header = False
448 if self.mpstat_options.cpu_list == "ALL" or self.mpstat_options.cpu_list == "ON" or self.mpstat_options.interrupt_type == "ALL":
449 self.print_header = True
450 if type(self.mpstat_options.cpu_list) != type([]):
451 self.printer("%-10s\t%-5s\t%-5s"%(timestamp,'all',self.total_interrupt_usage.total_interrupt_per_delta_time()))
453 if self.mpstat_options.cpu_filter == True:
454 percpu_total_interrupt_list = self.cpu_filter.filter_cpus(self.total_interrupt_usage.total_interrupt_percpu_per_delta_time())
455 for total_cpu_interrupt in percpu_total_interrupt_list:
456 self.printer("%-10s\t%-5s\t%-5s"%(timestamp, total_cpu_interrupt.cpu_number(), total_cpu_interrupt.value()))
458 class InterruptUsageReporter:
459 def __init__(self, cpu_filter, printer, mpstat_options):
460 self.cpu_filter = cpu_filter
461 self.printer = printer
462 self. mpstat_options = mpstat_options
463 self.print_header = True
465 def print_report(self, interrupt_usage, timestamp):
466 self.interrupt_usage = interrupt_usage
467 cpu_interrupts = self.interrupt_usage.get_percpu_interrupts()
468 header_values = ("\nTimestamp","CPU")
469 format_str = "%-10s\t%-4s\t"
471 # use the first CPU in cpu_interrupts to get the interrupt names
472 for interrupt in cpu_interrupts[0].interrupts:
473 format_str += "%-"+str(len(interrupt.name())+2)+"s\t"
474 header_values += (interrupt.name() + "/s",)
475 if self.print_header:
476 self.printer(format_str % header_values)
477 self.print_header = False
478 if self.mpstat_options.cpu_list == "ALL" or self.mpstat_options.cpu_list == "ON" or self.mpstat_options.interrupt_type == "ALL":
479 self.print_header = True
481 cpu_interrupts_list = self.cpu_filter.filter_cpus(cpu_interrupts)
482 for cpu_interrupt in cpu_interrupts_list:
483 values = (timestamp, cpu_interrupt.cpu_number()) + tuple(map((lambda interrupt: interrupt.value()), cpu_interrupt.interrupts))
484 self.printer(format_str % values)
486 class NoneHandlingPrinterDecorator:
487 def __init__(self, printer):
488 self.printer = printer
490 def Print(self, args):
491 new_args = args.replace('None','?')
492 self.printer(new_args)
494 class MpstatOptions(pmapi.pmOptions):
495 cpu_list = None
496 cpu_filter = False
497 options_all = False
498 interrupts_filter = False
499 interrupt_type = None
500 no_options = True
502 def extraOptions(self, opt,optarg, index):
503 MpstatOptions.no_options = False
504 if opt == 'u':
505 MpstatOptions.no_options = True
506 elif opt == 'A':
507 MpstatOptions.interrupts_filter = True
508 MpstatOptions.interrupt_type = 'ALL'
509 MpstatOptions.cpu_filter = True
510 MpstatOptions.cpu_list = 'ALL'
511 MpstatOptions.no_options = True
512 elif opt == "I":
513 MpstatOptions.interrupts_filter = True
514 MpstatOptions.interrupt_type = optarg
515 elif opt == 'P':
516 if optarg == 'ALL' or optarg == 'ON':
517 MpstatOptions.cpu_filter = True
518 MpstatOptions.cpu_list = optarg
519 else:
520 MpstatOptions.cpu_filter = True
521 try:
522 MpstatOptions.cpu_list = list(map(lambda x:int(x),optarg.split(',')))
523 except ValueError as e:
524 print ("Invalid CPU List: use comma separated cpu nos without whitespaces")
525 sys.exit(1)
527 def override(self, opt):
528 """ Override standard PCP options to match mpstat(1) """
529 if (opt == 'A'):
530 return 1
531 return 0
533 def __init__(self):
534 pmapi.pmOptions.__init__(self,"a:s:t:uAP:I:V?")
535 self.pmSetOptionCallback(self.extraOptions)
536 self.pmSetOverrideCallback(self.override)
537 self.pmSetLongOptionHeader("General options")
538 self.pmSetLongOptionArchive()
539 self.pmSetLongOptionSamples()
540 self.pmSetLongOptionInterval()
541 self.pmSetLongOptionVersion()
542 self.pmSetLongOptionHelp()
543 self.pmSetLongOption("",0,"u","","Similar to no options")
544 self.pmSetLongOption("",0,"A","","Similar to -P ALL -I ALL")
545 self.pmSetLongOption("",1,"P","[1,3..|ON|ALL]","Filter or Show All/Online CPUs")
546 self.pmSetLongOption("",1,"I","[SUM|CPU|SCPU|ALL]","Report Interrupt statistics")
548 class DisplayOptions:
549 def __init__(self, mpstatoptions):
550 self.mpstatoptions = mpstatoptions
552 def display_cpu_usage_summary(self):
553 return self.mpstatoptions.no_options or (self.mpstatoptions.cpu_filter and not self.mpstatoptions.interrupts_filter)
555 def display_total_cpu_usage(self):
556 return self.mpstatoptions.interrupts_filter and (self.mpstatoptions.interrupt_type == "SUM" or self.mpstatoptions.interrupt_type == "ALL")
558 def display_hard_interrupt_usage(self):
559 return self.mpstatoptions.interrupts_filter and (self.mpstatoptions.interrupt_type == "CPU" or self.mpstatoptions.interrupt_type == "ALL")
561 def display_soft_interrupt_usage(self):
562 return self.mpstatoptions.interrupts_filter and (self.mpstatoptions.interrupt_type == "SCPU" or self.mpstatoptions.interrupt_type == "ALL")
564 class MpstatReport(pmcc.MetricGroupPrinter):
565 Machine_info_count = 0
567 def __init__(self, cpu_util_reporter, total_interrupt_usage_reporter, soft_interrupt_usage_reporter, hard_interrupt_usage_reporter):
568 self.cpu_util_reporter = cpu_util_reporter
569 self.total_interrupt_usage_reporter = total_interrupt_usage_reporter
570 self.soft_interrupt_usage_reporter = soft_interrupt_usage_reporter
571 self.hard_interrupt_usage_reporter = hard_interrupt_usage_reporter
573 def timeStampDelta(self, group):
574 s = group.timestamp.tv_sec - group.prevTimestamp.tv_sec
575 u = group.timestamp.tv_usec - group.prevTimestamp.tv_usec
576 return (s + u / 1000000.0)
578 def print_machine_info(self,group, context):
579 timestamp = context.pmLocaltime(group.timestamp.tv_sec)
581 Please check strftime(3) for different formatting options.
582 Also check TZ and LC_TIME environment variables for more information
583 on how to override the default formatting of the date display in the header
585 time_string = time.strftime("%x", timestamp.struct_time())
586 header_string = ''
587 header_string += group['kernel.uname.sysname'].netValues[0][2] + ' '
588 header_string += group['kernel.uname.release'].netValues[0][2] + ' '
589 header_string += '(' + group['kernel.uname.nodename'].netValues[0][2] + ') '
590 header_string += time_string + ' '
591 header_string += group['kernel.uname.machine'].netValues[0][2] + ' '
592 no_cpu =self.get_ncpu(group)
593 print("%s (%s CPU)" % (header_string,no_cpu))
595 def get_ncpu(self,group):
596 return group['hinv.ncpu'].netValues[0][2]
598 def report(self,manager):
599 group = manager['mpstat']
600 if group['kernel.all.cpu.user'].netPrevValues == None:
601 # need two fetches to report rate converted counter metrics
602 return
604 if self.Machine_info_count == 0:
605 self.print_machine_info(group, manager)
606 self.Machine_info_count = 1
608 timestamp = group.contextCache.pmCtime(int(group.timestamp)).rstrip().split()
609 interval_in_seconds = self.timeStampDelta(group)
610 metric_repository = MetricRepository(group)
611 display_options = DisplayOptions(MpstatOptions)
613 if display_options.display_cpu_usage_summary():
614 cpu_util = CpuUtil(interval_in_seconds, metric_repository)
615 self.cpu_util_reporter.print_report(cpu_util, timestamp[3])
616 if display_options.display_total_cpu_usage():
617 total_interrupt_usage = TotalInterruptUsage(interval_in_seconds, metric_repository)
618 self.total_interrupt_usage_reporter.print_report(total_interrupt_usage, timestamp[3])
619 if display_options.display_hard_interrupt_usage():
620 hard_interrupt_usage = HardInterruptUsage(interval_in_seconds, metric_repository, interrupts_list)
621 self.hard_interrupt_usage_reporter.print_report(hard_interrupt_usage,timestamp[3])
622 if display_options.display_soft_interrupt_usage():
623 soft_interrupt_usage = SoftInterruptUsage(interval_in_seconds, metric_repository, soft_interrupts_list)
624 self.soft_interrupt_usage_reporter.print_report(soft_interrupt_usage, timestamp[3])
629 if __name__ == '__main__':
631 stdout = StdoutPrinter()
632 none_handler_printer = NoneHandlingPrinterDecorator(stdout.Print)
633 cpu_filter = CpuFilter(MpstatOptions)
634 cpu_util_reporter = CpuUtilReporter(cpu_filter, none_handler_printer.Print, MpstatOptions)
635 total_interrupt_usage_reporter = TotalInterruptUsageReporter(cpu_filter, none_handler_printer.Print, MpstatOptions)
636 soft_interrupt_usage_reporter = InterruptUsageReporter(cpu_filter, none_handler_printer.Print, MpstatOptions)
637 hard_interrupt_usage_reporter = InterruptUsageReporter(cpu_filter, none_handler_printer.Print, MpstatOptions)
639 try:
640 opts = MpstatOptions()
641 manager = pmcc.MetricGroupManager.builder(opts,sys.argv)
642 interrupts_list = NamedInterrupts(manager, 'kernel.percpu.interrupts').get_all_named_interrupt_metrics()
643 soft_interrupts_list = NamedInterrupts(manager, 'kernel.percpu.softirqs').get_all_named_interrupt_metrics()
644 MPSTAT_METRICS += interrupts_list
645 MPSTAT_METRICS += soft_interrupts_list
646 manager['mpstat'] = MPSTAT_METRICS
647 manager.printer = MpstatReport(cpu_util_reporter, total_interrupt_usage_reporter, soft_interrupt_usage_reporter, hard_interrupt_usage_reporter)
648 sts = manager.run()
649 sys.exit(sts)
650 except pmapi.pmErr as pmerror:
651 sys.stderr.write('%s: %s\n' % (pmerror.progname(),pmerror.message()))
652 except pmapi.pmUsageErr as usage:
653 usage.message()
654 sys.exit(1)
655 except KeyboardInterrupt:
656 pass