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
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']
31 soft_interrupts_list
= []
34 def Print(self
, args
):
37 class NamedInterrupts
:
38 def __init__(self
, context
, metric
):
39 self
.context
= context
40 self
.interrupt_list
= []
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
:
49 self
.context
.pmTraversePMNS(self
.metric
,self
.append_callback
)
50 except pmapi
.pmErr
as err
:
51 if err
.message() == "Unknown metric name":
55 self
.interrupt_list
.reverse()
56 return self
.interrupt_list
58 class MetricRepository
:
59 def __init__(self
,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
:
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)
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
:
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)
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:
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:
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
))
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
))
115 if self
.group
[metric
].netPrevValues
== []:
118 return self
.group
[metric
].netPrevValues
[0][2]
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
):
132 def cpu_online(self
):
133 return self
.metric_repository
.current_value('hinv.cpu.online', self
.instance
)
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()))
144 return float("%.2f"%(value))
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()))
158 return float("%.2f"%(value))
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()))
171 return float("%.2f"%(value))
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()))
184 return float("%.2f"%(value))
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()))
197 return float("%.2f"%(value))
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()))
210 return float("%.2f"%(value))
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()))
223 return float("%.2f"%(value))
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()))
236 return float("%.2f"%(value))
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()))
249 return float("%.2f"%(value))
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()))
262 return float("%.2f"%(value))
266 def __all_or_percpu(self
):
267 return 'all' if self
.instance
is None else 'percpu'
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
()))
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
):
290 def cpu_online(self
):
291 return self
.metric_repository
.current_value('hinv.cpu.online', self
.cpu_num
)
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
))
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
))
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
327 self
.delta_time
= delta_time
328 self
.__metric
_repository
= metric_repository
331 if self
.__name
.startswith("line"):
332 return self
.__name
[4:]
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
))
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
):
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
()))
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
()))
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
))
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':
396 elif self
.mpstat_options
.cpu_list
== 'ON':
397 if cpu
.cpu_online() == 1:
401 elif self
.mpstat_options
.cpu_list
is not None:
402 if cpu
.cpu_number() in self
.mpstat_options
.cpu_list
:
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
):
498 interrupts_filter
= False
499 interrupt_type
= None
502 def extraOptions(self
, opt
,optarg
, index
):
503 MpstatOptions
.no_options
= False
505 MpstatOptions
.no_options
= True
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
513 MpstatOptions
.interrupts_filter
= True
514 MpstatOptions
.interrupt_type
= optarg
516 if optarg
== 'ALL' or optarg
== 'ON':
517 MpstatOptions
.cpu_filter
= True
518 MpstatOptions
.cpu_list
= optarg
520 MpstatOptions
.cpu_filter
= True
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")
527 def override(self
, opt
):
528 """ Override standard PCP options to match mpstat(1) """
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())
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
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
)
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
)
650 except pmapi
.pmErr
as pmerror
:
651 sys
.stderr
.write('%s: %s\n' % (pmerror
.progname(),pmerror
.message()))
652 except pmapi
.pmUsageErr
as usage
:
655 except KeyboardInterrupt: