Skip to content

Commit db101d5

Browse files
committed
Add pidstat -w option (context switches)
1 parent fddf1fa commit db101d5

File tree

1 file changed

+125
-25
lines changed

1 file changed

+125
-25
lines changed

src/pcp/pidstat/pcp-pidstat.py

Lines changed: 125 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@
4848
'proc.psinfo.guest_time',
4949
'proc.psinfo.maj_flt',
5050
'proc.psinfo.minflt',
51+
'proc.psinfo.nvctxsw',
5152
'proc.psinfo.pid',
5253
'proc.psinfo.policy',
5354
'proc.psinfo.processor',
5455
'proc.psinfo.rss',
5556
'proc.psinfo.rt_priority',
5657
'proc.psinfo.stime',
5758
'proc.psinfo.utime',
59+
'proc.psinfo.vctxsw',
5860
'proc.psinfo.vsize',
5961
]
6062

@@ -252,10 +254,10 @@ def __pids(self):
252254
return sorted(pid_dict.values())
253255

254256
class ProcessMemoryUtil:
255-
def __init__(self, instance, delta_time, metric_repository):
257+
def __init__(self, instance, delta_time, metric_repository):
256258
self.instance = instance
257-
self.__metric_repository = metric_repository
258259
self.delta_time = delta_time
260+
self.__metric_repository = metric_repository
259261

260262
def pid(self):
261263
return self.__metric_repository.current_value('proc.psinfo.pid', self.instance)
@@ -348,6 +350,54 @@ def __pids(self):
348350
pid_dict = self.__metric_repository.current_values('proc.psinfo.pid')
349351
return sorted(pid_dict.values())
350352

353+
354+
class ProcessCtxsw:
355+
def __init__(self, instance, delta_time, metric_repository):
356+
self.instance = instance
357+
self.delta_time = delta_time
358+
self.__metric_repository = metric_repository
359+
360+
def pid(self):
361+
return self.__metric_repository.current_value('proc.psinfo.pid', self.instance)
362+
363+
def user_id(self):
364+
return self.__metric_repository.current_value('proc.id.uid', self.instance)
365+
366+
def process_name(self):
367+
return self.__metric_repository.current_value('proc.psinfo.cmd', self.instance)
368+
369+
def process_name_with_args(self):
370+
return self.__metric_repository.current_value('proc.psinfo.psargs', self.instance)
371+
372+
def ctxsw(self):
373+
c_vctxsw = self.__metric_repository.current_value('proc.psinfo.vctxsw', self.instance)
374+
p_vctxsw = self.__metric_repository.previous_value('proc.psinfo.vctxsw', self.instance)
375+
if c_vctxsw is None or p_vctxsw is None:
376+
return None
377+
return float("%.2f" % ((c_vctxsw - p_vctxsw)/self.delta_time))
378+
379+
def nvctxsw(self):
380+
c_nvctxsw = self.__metric_repository.current_value('proc.psinfo.nvctxsw', self.instance)
381+
p_nvctxsw = self.__metric_repository.previous_value('proc.psinfo.nvctxsw', self.instance)
382+
if c_nvctxsw is None or p_nvctxsw is None:
383+
return None
384+
return float("%.2f" % ((c_nvctxsw - p_nvctxsw)/self.delta_time))
385+
386+
def user_name(self):
387+
return self.__metric_repository.current_value('proc.id.uid_nm', self.instance)
388+
389+
390+
class CpuProcessCtxsw:
391+
def __init__(self, metric_repository):
392+
self.__metric_repository = metric_repository
393+
394+
def get_processes(self, delta_time):
395+
return map((lambda pid: (ProcessCtxsw(pid, delta_time, self.__metric_repository))), self.__pids())
396+
397+
def __pids(self):
398+
pid_dict = self.__metric_repository.current_values('proc.psinfo.pid')
399+
return sorted(pid_dict.values())
400+
351401
# ==============================================================================
352402
# process state reporting
353403

@@ -701,8 +751,8 @@ class CpuProcessMemoryUtilReporter:
701751
def __init__(self, process_memory_util, process_filter, delta_time, printer, pidstat_options):
702752
self.process_memory_util = process_memory_util
703753
self.process_filter = process_filter
704-
self.printer = printer
705754
self.delta_time = delta_time
755+
self.printer = printer
706756
self.pidstat_options = pidstat_options
707757

708758
def print_report(self, timestamp, header_indentation, value_indentation):
@@ -771,6 +821,41 @@ def print_report(self, timestamp, header_indentation, value_indentation):
771821
process.pid(), process.stack_size(),
772822
process.process_name()))
773823

824+
class CpuProcessCtxswReporter:
825+
def __init__(self, process_ctxsw, process_filter, delta_time, printer, pidstat_options):
826+
self.process_ctxsw = process_ctxsw
827+
self.process_filter = process_filter
828+
self.delta_time = delta_time
829+
self.printer = printer
830+
self.pidstat_options = pidstat_options
831+
832+
def print_report(self, timestamp, header_indentation, value_indentation):
833+
self.printer ("Timestamp" + header_indentation + "UID\tPID\tcswch/s\tnvcswch/s\tCommand")
834+
processes = self.process_filter.filter_processes(self.process_ctxsw.get_processes(self.delta_time))
835+
for process in processes:
836+
if self.pidstat_options.show_process_user:
837+
if self.pidstat_options.process_name_with_args:
838+
self.printer("%s%s%s\t%s\t%s\t%s\t%s" %
839+
(timestamp, value_indentation, process.user_name(),
840+
process.pid(), process.ctxsw(), process.nvctxsw(),
841+
process.process_name_with_args()))
842+
else :
843+
self.printer("%s%s%s\t%s\t%s\t%s\t%s" %
844+
(timestamp, value_indentation, process.user_name(),
845+
process.pid(), process.ctxsw(), process.nvctxsw(),
846+
process.process_name()))
847+
else:
848+
if self.pidstat_options.process_name_with_args:
849+
self.printer("%s%s%s\t%s\t%s\t%s\t%s" %
850+
(timestamp, value_indentation, process.user_id(),
851+
process.pid(), process.ctxsw(), process.nvctxsw(),
852+
process.process_name_with_args()))
853+
else :
854+
self.printer("%s%s%s\t%s\t%s\t%s\t%s" %
855+
(timestamp, value_indentation, process.user_id(),
856+
process.pid(), process.ctxsw(), process.nvctxsw(),
857+
process.process_name()))
858+
774859

775860
class NoneHandlingPrinterDecorator:
776861
def __init__(self, printer):
@@ -786,7 +871,7 @@ class PidstatOptions(pmapi.pmOptions):
786871
#After reading in the provided command line options
787872
#initalize them by passing them in
788873
def __init__(self):
789-
pmapi.pmOptions.__init__(self,"a:s:t:G:IU::p:RrukVZ:z?:f:B:l")
874+
pmapi.pmOptions.__init__(self,"a:s:t:G:IU::p:RruwkVZ:z?:f:B:l")
790875
self.pmSetOptionCallback(self.extraOptions)
791876
self.pmSetOverrideCallback(self.override)
792877
self.pmSetLongOptionHeader("General options")
@@ -796,17 +881,18 @@ def __init__(self):
796881
self.pmSetLongOption("process-name", 1, "G", "NAME",
797882
"Select process names using regular expression.")
798883
self.pmSetLongOption("", 0, "I", "", "Show CPU usage per processor.")
799-
self.pmSetLongOption("user-name", 2, "U","[USERNAME]",
884+
self.pmSetLongOption("user-name", 2, "U", "[USERNAME]",
800885
"Show real user name of the tasks and optionally filter by user name.")
801886
self.pmSetLongOption("pid-list", 1, "p", "PID1,PID2.. ",
802887
"Show stats for specified pids; " +
803888
"use SELF for current process and ALL for all processes.")
804889
self.pmSetLongOption("", 0, "R", "",
805890
"Report realtime priority and scheduling policy information.")
806-
self.pmSetLongOption("", 0,"r","","Report page faults and memory utilization.")
807-
self.pmSetLongOption("", 0,"u","","Report CPU utilization.")
808-
self.pmSetLongOption("", 0,"k","","Report stack utilization.")
809-
self.pmSetLongOption("", 0,"f","","Format the timestamp output")
891+
self.pmSetLongOption("", 0, "r", "", "Report page faults and memory utilization.")
892+
self.pmSetLongOption("", 0, "u", "", "Report CPU utilization.")
893+
self.pmSetLongOption("", 0, "k", "", "Report stack utilization.")
894+
self.pmSetLongOption("", 0, "w", "", "Report task switching activity.")
895+
self.pmSetLongOption("", 0, "f", "", "Format the timestamp output (strftime format accepted)")
810896
self.pmSetLongOption("", 0, "B", "state1,state2,..",
811897
"Report process state information. " +
812898
"Use -B [all] or -B [comma separated states]. " +
@@ -821,6 +907,7 @@ def __init__(self):
821907
self.process_name_with_args = False
822908
self.ps_args_flag=False
823909
self.show_process_cpu_util = False
910+
self.show_process_ctxsw = False
824911
self.show_process_memory_util = False
825912
self.show_process_priority = False
826913
self.show_process_stack_util = False
@@ -837,7 +924,8 @@ def __init__(self):
837924

838925
def checkOptions(self):
839926
if ((self.show_process_memory_util or self.show_process_stack_util or
840-
self.show_process_priority or self.show_process_cpu_util) and
927+
self.show_process_priority or self.show_process_cpu_util or
928+
self.show_process_ctxsw) and
841929
self.show_process_state):
842930
print("Error: Incompatible flags provided")
843931
return False
@@ -851,12 +939,14 @@ def checkOptions(self):
851939
return True
852940
# Determine if we are defaulting to -u.
853941
if not any([self.show_process_memory_util, self.show_process_stack_util,
854-
self.show_process_priority]):
942+
self.show_process_priority, self.show_process_ctxsw]):
855943
self.show_process_cpu_util = True
856944
return True
857945

858946
def extraOptions(self, opt, optarg, index):
859-
if opt == 'u':
947+
if opt == 'w':
948+
self.show_process_ctxsw = True
949+
elif opt == 'u':
860950
self.show_process_cpu_util = True
861951
elif opt == 'k':
862952
self.show_process_stack_util = True
@@ -992,13 +1082,23 @@ def report(self,manager):
9921082
printdecorator.Print, self.opts)
9931083
report.print_report(timestamp, header_indentation, value_indentation)
9941084
else:
995-
if self.opts.show_process_stack_util:
996-
process_stack_util = CpuProcessStackUtil(metric_repository)
1085+
if self.opts.show_process_cpu_util:
1086+
cpu_usage = CpuUsage(metric_repository)
9971087
process_filter = ProcessFilter(self.opts)
9981088
stdout = StdoutPrinter()
9991089
printdecorator = NoneHandlingPrinterDecorator(stdout)
1000-
report = CpuProcessStackUtilReporter(process_stack_util, process_filter,
1001-
printdecorator.Print, self.opts)
1090+
report = CpuUsageReporter(cpu_usage, process_filter, interval_in_seconds,
1091+
printdecorator.Print, self.opts)
1092+
report.print_report(timestamp, ncpu, header_indentation, value_indentation)
1093+
1094+
if self.opts.show_process_ctxsw:
1095+
process_ctxsw = CpuProcessCtxsw(metric_repository)
1096+
process_filter = ProcessFilter(self.opts)
1097+
stdout = StdoutPrinter()
1098+
printdecorator = NoneHandlingPrinterDecorator(stdout)
1099+
report = CpuProcessCtxswReporter(process_ctxsw, process_filter,
1100+
interval_in_seconds,
1101+
printdecorator.Print, self.opts)
10021102
report.print_report(timestamp, header_indentation, value_indentation)
10031103

10041104
if self.opts.show_process_memory_util:
@@ -1011,23 +1111,23 @@ def report(self,manager):
10111111
printdecorator.Print, self.opts)
10121112
report.print_report(timestamp, header_indentation, value_indentation)
10131113

1014-
if self.opts.show_process_priority:
1015-
process_priority = CpuProcessPriorities(metric_repository)
1114+
if self.opts.show_process_stack_util:
1115+
process_stack_util = CpuProcessStackUtil(metric_repository)
10161116
process_filter = ProcessFilter(self.opts)
10171117
stdout = StdoutPrinter()
10181118
printdecorator = NoneHandlingPrinterDecorator(stdout)
1019-
report = CpuProcessPrioritiesReporter(process_priority, process_filter,
1020-
printdecorator.Print, self.opts)
1119+
report = CpuProcessStackUtilReporter(process_stack_util, process_filter,
1120+
printdecorator.Print, self.opts)
10211121
report.print_report(timestamp, header_indentation, value_indentation)
10221122

1023-
if self.opts.show_process_cpu_util:
1024-
cpu_usage = CpuUsage(metric_repository)
1123+
if self.opts.show_process_priority:
1124+
process_priority = CpuProcessPriorities(metric_repository)
10251125
process_filter = ProcessFilter(self.opts)
10261126
stdout = StdoutPrinter()
10271127
printdecorator = NoneHandlingPrinterDecorator(stdout)
1028-
report = CpuUsageReporter(cpu_usage, process_filter, interval_in_seconds,
1029-
printdecorator.Print, self.opts)
1030-
report.print_report(timestamp, ncpu, header_indentation, value_indentation)
1128+
report = CpuProcessPrioritiesReporter(process_priority, process_filter,
1129+
printdecorator.Print, self.opts)
1130+
report.print_report(timestamp, header_indentation, value_indentation)
10311131

10321132

10331133
if __name__ == "__main__":

0 commit comments

Comments
 (0)