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>
This commit is contained in:
parent
645c1728a9
commit
f9ff108735
|
@ -30,6 +30,7 @@ import fcntl
|
|||
import resource
|
||||
import struct
|
||||
import re
|
||||
import subprocess
|
||||
from collections import defaultdict
|
||||
|
||||
VMX_EXIT_REASONS = {
|
||||
|
@ -320,6 +321,30 @@ def parse_int_list(list_string):
|
|||
return integers
|
||||
|
||||
|
||||
def get_pid_from_gname(gname):
|
||||
"""Fuzzy function to convert guest name to QEMU process pid.
|
||||
|
||||
Returns a list of potential pids, can be empty if no match found.
|
||||
Throws an exception on processing errors.
|
||||
|
||||
"""
|
||||
pids = []
|
||||
try:
|
||||
child = subprocess.Popen(['ps', '-A', '--format', 'pid,args'],
|
||||
stdout=subprocess.PIPE)
|
||||
except:
|
||||
raise Exception
|
||||
for line in child.stdout:
|
||||
line = line.lstrip().split(' ', 1)
|
||||
# perform a sanity check before calling the more expensive
|
||||
# function to possibly extract the guest name
|
||||
if ' -name ' in line[1] and gname == get_gname_from_pid(line[0]):
|
||||
pids.append(int(line[0]))
|
||||
child.stdout.close()
|
||||
|
||||
return pids
|
||||
|
||||
|
||||
def get_gname_from_pid(pid):
|
||||
"""Returns the guest name for a QEMU process pid.
|
||||
|
||||
|
@ -977,7 +1002,7 @@ class Tui(object):
|
|||
except re.error:
|
||||
continue
|
||||
|
||||
def show_vm_selection(self):
|
||||
def show_vm_selection_by_pid(self):
|
||||
"""Draws PID selection mask.
|
||||
|
||||
Asks for a pid until a valid pid or 0 has been entered.
|
||||
|
@ -1016,6 +1041,50 @@ class Tui(object):
|
|||
msg = '"' + str(pid) + '": Not a valid pid'
|
||||
continue
|
||||
|
||||
def show_vm_selection_by_guest_name(self):
|
||||
"""Draws guest selection mask.
|
||||
|
||||
Asks for a guest name until a valid guest name or '' is entered.
|
||||
|
||||
"""
|
||||
msg = ''
|
||||
while True:
|
||||
self.screen.erase()
|
||||
self.screen.addstr(0, 0,
|
||||
'Show statistics for specific guest.',
|
||||
curses.A_BOLD)
|
||||
self.screen.addstr(1, 0,
|
||||
'This might limit the shown data to the trace '
|
||||
'statistics.')
|
||||
self.screen.addstr(5, 0, msg)
|
||||
curses.echo()
|
||||
self.screen.addstr(3, 0, "Guest [ENTER or guest]: ")
|
||||
gname = self.screen.getstr()
|
||||
curses.noecho()
|
||||
|
||||
if not gname:
|
||||
self.refresh_header(0)
|
||||
self.update_pid(0)
|
||||
break
|
||||
else:
|
||||
pids = []
|
||||
try:
|
||||
pids = get_pid_from_gname(gname)
|
||||
except:
|
||||
msg = '"' + gname + '": Internal error while searching, ' \
|
||||
'use pid filter instead'
|
||||
continue
|
||||
if len(pids) == 0:
|
||||
msg = '"' + gname + '": Not an active guest'
|
||||
continue
|
||||
if len(pids) > 1:
|
||||
msg = '"' + gname + '": Multiple matches found, use pid ' \
|
||||
'filter instead'
|
||||
continue
|
||||
self.refresh_header(pids[0])
|
||||
self.update_pid(pids[0])
|
||||
break
|
||||
|
||||
def show_stats(self):
|
||||
"""Refreshes the screen and processes user input."""
|
||||
sleeptime = DELAY_INITIAL
|
||||
|
@ -1035,8 +1104,11 @@ class Tui(object):
|
|||
if char == 'f':
|
||||
self.show_filter_selection()
|
||||
sleeptime = DELAY_INITIAL
|
||||
if char == 'g':
|
||||
self.show_vm_selection_by_guest_name()
|
||||
sleeptime = DELAY_INITIAL
|
||||
if char == 'p':
|
||||
self.show_vm_selection()
|
||||
self.show_vm_selection_by_pid()
|
||||
sleeptime = DELAY_INITIAL
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
@ -1106,6 +1178,7 @@ Requirements:
|
|||
|
||||
Interactive Commands:
|
||||
f filter by regular expression
|
||||
g filter by guest name
|
||||
p filter by PID
|
||||
q quit
|
||||
x toggle reporting of stats for individual child trace events
|
||||
|
@ -1119,6 +1192,22 @@ Press any other key to refresh statistics immediately.
|
|||
else:
|
||||
return ""
|
||||
|
||||
def cb_guest_to_pid(option, opt, val, parser):
|
||||
try:
|
||||
pids = get_pid_from_gname(val)
|
||||
except:
|
||||
raise optparse.OptionValueError('Error while searching for guest '
|
||||
'"{}", use "-p" to specify a pid '
|
||||
'instead'.format(val))
|
||||
if len(pids) == 0:
|
||||
raise optparse.OptionValueError('No guest by the name "{}" '
|
||||
'found'.format(val))
|
||||
if len(pids) > 1:
|
||||
raise optparse.OptionValueError('Multiple processes found (pids: '
|
||||
'{}) - use "-p" to specify a pid '
|
||||
'instead'.format(" ".join(pids)))
|
||||
parser.values.pid = pids[0]
|
||||
|
||||
optparser = optparse.OptionParser(description=description_text,
|
||||
formatter=PlainHelpFormatter())
|
||||
optparser.add_option('-1', '--once', '--batch',
|
||||
|
@ -1158,6 +1247,14 @@ Press any other key to refresh statistics immediately.
|
|||
dest='pid',
|
||||
help='restrict statistics to pid',
|
||||
)
|
||||
optparser.add_option('-g', '--guest',
|
||||
action='callback',
|
||||
type='string',
|
||||
dest='pid',
|
||||
metavar='GUEST',
|
||||
help='restrict statistics to guest by name',
|
||||
callback=cb_guest_to_pid,
|
||||
)
|
||||
(options, _) = optparser.parse_args(sys.argv)
|
||||
return options
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ INTERACTIVE COMMANDS
|
|||
[horizontal]
|
||||
*f*:: filter by regular expression
|
||||
|
||||
*g*:: filter by guest name
|
||||
|
||||
*p*:: filter by PID
|
||||
|
||||
*q*:: quit
|
||||
|
@ -62,6 +64,10 @@ OPTIONS
|
|||
--pid=<pid>::
|
||||
limit statistics to one virtual machine (pid)
|
||||
|
||||
-g<guest>::
|
||||
--guest=<guest_name>::
|
||||
limit statistics to one virtual machine (guest name)
|
||||
|
||||
-f<fields>::
|
||||
--fields=<fields>::
|
||||
fields to display (regex)
|
||||
|
|
Loading…
Reference in New Issue