summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorStefan Raspl <raspl@linux.vnet.ibm.com>2017-03-10 07:40:13 -0500
committerPaolo Bonzini <pbonzini@redhat.com>2017-03-29 06:01:31 -0400
commitf9ff1087354e5e063b96a291360a8de84bea0bed (patch)
tree906750a31a22bac0619fa4ecd57d2516860c5276 /tools
parent645c1728a9d33d78028d93a2ed770f51df0a92c6 (diff)
tools/kvm_stat: add option '--guest'
Add a new option '-g'/'--guest' to select a particular process by providing the QEMU guest name. Notes: - The logic to figure out the pid corresponding to the guest name might look scary, but works pretty reliably in practice; in the unlikely event that it returns add'l flukes, it will bail out and hint at using '-p' instead, no harm done. - Mixing '-g' and '-p' is possible, and the final instance specified on the command line is the significant one. This is consistent with current behavior for '-p' which, if specified multiple times, also regards the final instance as the significant one. Signed-off-by: Stefan Raspl <raspl@linux.vnet.ibm.com> Reviewed-by: Janosch Frank <frankja@linux.vnet.ibm.com> Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
Diffstat (limited to 'tools')
-rwxr-xr-xtools/kvm/kvm_stat/kvm_stat101
-rw-r--r--tools/kvm/kvm_stat/kvm_stat.txt6
2 files changed, 105 insertions, 2 deletions
diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat
index f2a868b696a8..f263312c9a29 100755
--- a/tools/kvm/kvm_stat/kvm_stat
+++ b/tools/kvm/kvm_stat/kvm_stat
@@ -30,6 +30,7 @@ import fcntl
30import resource 30import resource
31import struct 31import struct
32import re 32import re
33import subprocess
33from collections import defaultdict 34from collections import defaultdict
34 35
35VMX_EXIT_REASONS = { 36VMX_EXIT_REASONS = {
@@ -320,6 +321,30 @@ def parse_int_list(list_string):
320 return integers 321 return integers
321 322
322 323
324def get_pid_from_gname(gname):
325 """Fuzzy function to convert guest name to QEMU process pid.
326
327 Returns a list of potential pids, can be empty if no match found.
328 Throws an exception on processing errors.
329
330 """
331 pids = []
332 try:
333 child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'],
334 stdout=subprocess.PIPE)
335 except:
336 raise Exception
337 for line in child.stdout:
338 line = line.lstrip().split(' ', 1)
339 # perform a sanity check before calling the more expensive
340 # function to possibly extract the guest name
341 if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]):
342 pids.append(int(line[0]))
343 child.stdout.close()
344
345 return pids
346
347
323def get_gname_from_pid(pid): 348def get_gname_from_pid(pid):
324 """Returns the guest name for a QEMU process pid. 349 """Returns the guest name for a QEMU process pid.
325 350
@@ -977,7 +1002,7 @@ class Tui(object):
977 except re.error: 1002 except re.error:
978 continue 1003 continue
979 1004
980 def show_vm_selection(self): 1005 def show_vm_selection_by_pid(self):
981 """Draws PID selection mask. 1006 """Draws PID selection mask.
982 1007
983 Asks for a pid until a valid pid or 0 has been entered. 1008 Asks for a pid until a valid pid or 0 has been entered.
@@ -1016,6 +1041,50 @@ class Tui(object):
1016 msg = '"' + str(pid) + '": Not a valid pid' 1041 msg = '"' + str(pid) + '": Not a valid pid'
1017 continue 1042 continue
1018 1043
1044 def show_vm_selection_by_guest_name(self):
1045 """Draws guest selection mask.
1046
1047 Asks for a guest name until a valid guest name or '' is entered.
1048
1049 """
1050 msg = ''
1051 while True:
1052 self.screen.erase()
1053 self.screen.addstr(0, 0,
1054 'Show statistics for specific guest.',
1055 curses.A_BOLD)
1056 self.screen.addstr(1, 0,
1057 'This might limit the shown data to the trace '
1058 'statistics.')
1059 self.screen.addstr(5, 0, msg)
1060 curses.echo()
1061 self.screen.addstr(3, 0, "Guest [ENTER or guest]: ")
1062 gname = self.screen.getstr()
1063 curses.noecho()
1064
1065 if not gname:
1066 self.refresh_header(0)
1067 self.update_pid(0)
1068 break
1069 else:
1070 pids = []
1071 try:
1072 pids = get_pid_from_gname(gname)
1073 except:
1074 msg = '"' + gname + '": Internal error while searching, ' \
1075 'use pid filter instead'
1076 continue
1077 if len(pids) == 0:
1078 msg = '"' + gname + '": Not an active guest'
1079 continue
1080 if len(pids) > 1:
1081 msg = '"' + gname + '": Multiple matches found, use pid ' \
1082 'filter instead'
1083 continue
1084 self.refresh_header(pids[0])
1085 self.update_pid(pids[0])
1086 break
1087
1019 def show_stats(self): 1088 def show_stats(self):
1020 """Refreshes the screen and processes user input.""" 1089 """Refreshes the screen and processes user input."""
1021 sleeptime = DELAY_INITIAL 1090 sleeptime = DELAY_INITIAL
@@ -1035,8 +1104,11 @@ class Tui(object):
1035 if char == 'f': 1104 if char == 'f':
1036 self.show_filter_selection() 1105 self.show_filter_selection()
1037 sleeptime = DELAY_INITIAL 1106 sleeptime = DELAY_INITIAL
1107 if char == 'g':
1108 self.show_vm_selection_by_guest_name()
1109 sleeptime = DELAY_INITIAL
1038 if char == 'p': 1110 if char == 'p':
1039 self.show_vm_selection() 1111 self.show_vm_selection_by_pid()
1040 sleeptime = DELAY_INITIAL 1112 sleeptime = DELAY_INITIAL
1041 except KeyboardInterrupt: 1113 except KeyboardInterrupt:
1042 break 1114 break
@@ -1106,6 +1178,7 @@ Requirements:
1106 1178
1107Interactive Commands: 1179Interactive Commands:
1108 f filter by regular expression 1180 f filter by regular expression
1181 g filter by guest name
1109 p filter by PID 1182 p filter by PID
1110 q quit 1183 q quit
1111 x toggle reporting of stats for individual child trace events 1184 x toggle reporting of stats for individual child trace events
@@ -1119,6 +1192,22 @@ Press any other key to refresh statistics immediately.
1119 else: 1192 else:
1120 return "" 1193 return ""
1121 1194
1195 def cb_guest_to_pid(option, opt, val, parser):
1196 try:
1197 pids = get_pid_from_gname(val)
1198 except:
1199 raise optparse.OptionValueError('Error while searching for guest '
1200 '"{}", use "-p" to specify a pid '
1201 'instead'.format(val))
1202 if len(pids) == 0:
1203 raise optparse.OptionValueError('No guest by the name "{}" '
1204 'found'.format(val))
1205 if len(pids) > 1:
1206 raise optparse.OptionValueError('Multiple processes found (pids: '
1207 '{}) - use "-p" to specify a pid '
1208 'instead'.format(" ".join(pids)))
1209 parser.values.pid = pids[0]
1210
1122 optparser = optparse.OptionParser(description=description_text, 1211 optparser = optparse.OptionParser(description=description_text,
1123 formatter=PlainHelpFormatter()) 1212 formatter=PlainHelpFormatter())
1124 optparser.add_option('-1', '--once', '--batch', 1213 optparser.add_option('-1', '--once', '--batch',
@@ -1158,6 +1247,14 @@ Press any other key to refresh statistics immediately.
1158 dest='pid', 1247 dest='pid',
1159 help='restrict statistics to pid', 1248 help='restrict statistics to pid',
1160 ) 1249 )
1250 optparser.add_option('-g', '--guest',
1251 action='callback',
1252 type='string',
1253 dest='pid',
1254 metavar='GUEST',
1255 help='restrict statistics to guest by name',
1256 callback=cb_guest_to_pid,
1257 )
1161 (options, _) = optparser.parse_args(sys.argv) 1258 (options, _) = optparser.parse_args(sys.argv)
1162 return options 1259 return options
1163 1260
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt
index 077bcc7e20dc..35587c3c2610 100644
--- a/tools/kvm/kvm_stat/kvm_stat.txt
+++ b/tools/kvm/kvm_stat/kvm_stat.txt
@@ -31,6 +31,8 @@ INTERACTIVE COMMANDS
31[horizontal] 31[horizontal]
32*f*:: filter by regular expression 32*f*:: filter by regular expression
33 33
34*g*:: filter by guest name
35
34*p*:: filter by PID 36*p*:: filter by PID
35 37
36*q*:: quit 38*q*:: quit
@@ -62,6 +64,10 @@ OPTIONS
62--pid=<pid>:: 64--pid=<pid>::
63 limit statistics to one virtual machine (pid) 65 limit statistics to one virtual machine (pid)
64 66
67-g<guest>::
68--guest=<guest_name>::
69 limit statistics to one virtual machine (guest name)
70
65-f<fields>:: 71-f<fields>::
66--fields=<fields>:: 72--fields=<fields>::
67 fields to display (regex) 73 fields to display (regex)