Commit 5c1954d2 authored by Stefan Raspl's avatar Stefan Raspl Committed by Paolo Bonzini

tools/kvm_stat: add new interactive command 'b'

Toggle display total number of events by guest (debugfs only).
When switching to display of events by guest, field filters remain
active. I.e. the number of events per guest reported considers only
events matching the filters. Likewise with pid/guest filtering.
Note that when switching to display of events by guest, DebugfsProvider
remains to collect data for events as it did before, but the read()
method summarizes the values by pid.
Signed-off-by: default avatarStefan Raspl <raspl@linux.vnet.ibm.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent ab7ef193
...@@ -662,7 +662,7 @@ class TracepointProvider(Provider): ...@@ -662,7 +662,7 @@ class TracepointProvider(Provider):
self.setup_traces() self.setup_traces()
self.fields = self._fields self.fields = self._fields
def read(self): def read(self, by_guest=0):
"""Returns 'event name: current value' for all enabled events.""" """Returns 'event name: current value' for all enabled events."""
ret = defaultdict(int) ret = defaultdict(int)
for group in self.group_leaders: for group in self.group_leaders:
...@@ -731,7 +731,7 @@ class DebugfsProvider(Provider): ...@@ -731,7 +731,7 @@ class DebugfsProvider(Provider):
self.do_read = True self.do_read = True
self.reset() self.reset()
def read(self, reset=0): def read(self, reset=0, by_guest=0):
"""Returns a dict with format:'file name / field -> current value'. """Returns a dict with format:'file name / field -> current value'.
Parameter 'reset': Parameter 'reset':
...@@ -762,8 +762,16 @@ class DebugfsProvider(Provider): ...@@ -762,8 +762,16 @@ class DebugfsProvider(Provider):
self._baseline[key] = 0 self._baseline[key] = 0
if self._baseline.get(key, -1) == -1: if self._baseline.get(key, -1) == -1:
self._baseline[key] = value self._baseline[key] = value
results[field] = (results.get(field, 0) + value - increment = (results.get(field, 0) + value -
self._baseline.get(key, 0)) self._baseline.get(key, 0))
if by_guest:
pid = key.split('-')[0]
if pid in results:
results[pid] += increment
else:
results[pid] = increment
else:
results[field] = increment
return results return results
...@@ -849,18 +857,44 @@ class Stats(object): ...@@ -849,18 +857,44 @@ class Stats(object):
for provider in self.providers: for provider in self.providers:
provider.pid = self._pid_filter provider.pid = self._pid_filter
def get(self): def get(self, by_guest=0):
"""Returns a dict with field -> (value, delta to last value) of all """Returns a dict with field -> (value, delta to last value) of all
provider data.""" provider data."""
for provider in self.providers: for provider in self.providers:
new = provider.read() new = provider.read(by_guest=by_guest)
for key in provider.fields: for key in new if by_guest else provider.fields:
oldval = self.values.get(key, (0, 0))[0] oldval = self.values.get(key, (0, 0))[0]
newval = new.get(key, 0) newval = new.get(key, 0)
newdelta = newval - oldval newdelta = newval - oldval
self.values[key] = (newval, newdelta) self.values[key] = (newval, newdelta)
return self.values return self.values
def toggle_display_guests(self, to_pid):
"""Toggle between collection of stats by individual event and by
guest pid
Events reported by DebugfsProvider change when switching to/from
reading by guest values. Hence we have to remove the excess event
names from self.values.
"""
if any(isinstance(ins, TracepointProvider) for ins in self.providers):
return 1
if to_pid:
for provider in self.providers:
if isinstance(provider, DebugfsProvider):
for key in provider.fields:
if key in self.values.keys():
del self.values[key]
else:
oldvals = self.values.copy()
for key in oldvals:
if key.isdigit():
del self.values[key]
# Update oldval (see get())
self.get(to_pid)
return 0
DELAY_DEFAULT = 3.0 DELAY_DEFAULT = 3.0
MAX_GUEST_NAME_LEN = 48 MAX_GUEST_NAME_LEN = 48
MAX_REGEX_LEN = 44 MAX_REGEX_LEN = 44
...@@ -876,6 +910,7 @@ class Tui(object): ...@@ -876,6 +910,7 @@ class Tui(object):
self._delay_initial = 0.25 self._delay_initial = 0.25
self._delay_regular = DELAY_DEFAULT self._delay_regular = DELAY_DEFAULT
self._sorting = SORT_DEFAULT self._sorting = SORT_DEFAULT
self._display_guests = 0
def __enter__(self): def __enter__(self):
"""Initialises curses for later use. Based on curses.wrapper """Initialises curses for later use. Based on curses.wrapper
...@@ -1024,8 +1059,12 @@ class Tui(object): ...@@ -1024,8 +1059,12 @@ class Tui(object):
if len(regex) > MAX_REGEX_LEN: if len(regex) > MAX_REGEX_LEN:
regex = regex[:MAX_REGEX_LEN] + '...' regex = regex[:MAX_REGEX_LEN] + '...'
self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex))
if self._display_guests:
col_name = 'Guest Name'
else:
col_name = 'Event'
self.screen.addstr(2, 1, '%-40s %10s%7s %8s' % self.screen.addstr(2, 1, '%-40s %10s%7s %8s' %
('Event', 'Total', '%Total', 'CurAvg/s'), (col_name, 'Total', '%Total', 'CurAvg/s'),
curses.A_STANDOUT) curses.A_STANDOUT)
self.screen.addstr(4, 1, 'Collecting data...') self.screen.addstr(4, 1, 'Collecting data...')
self.screen.refresh() self.screen.refresh()
...@@ -1034,7 +1073,7 @@ class Tui(object): ...@@ -1034,7 +1073,7 @@ class Tui(object):
row = 3 row = 3
self.screen.move(row, 0) self.screen.move(row, 0)
self.screen.clrtobot() self.screen.clrtobot()
stats = self.stats.get() stats = self.stats.get(self._display_guests)
def sortCurAvg(x): def sortCurAvg(x):
# sort by current events if available # sort by current events if available
...@@ -1062,6 +1101,8 @@ class Tui(object): ...@@ -1062,6 +1101,8 @@ class Tui(object):
break break
if values[0] is not None: if values[0] is not None:
cur = int(round(values[1] / sleeptime)) if values[1] else '' cur = int(round(values[1] / sleeptime)) if values[1] else ''
if self._display_guests:
key = self.get_gname_from_pid(key)
self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' %
(key, values[0], values[0] * 100 / total, (key, values[0], values[0] * 100 / total,
cur)) cur))
...@@ -1070,9 +1111,26 @@ class Tui(object): ...@@ -1070,9 +1111,26 @@ class Tui(object):
self.screen.addstr(4, 1, 'No matching events reported yet') self.screen.addstr(4, 1, 'No matching events reported yet')
self.screen.refresh() self.screen.refresh()
def show_msg(self, text):
"""Display message centered text and exit on key press"""
hint = 'Press any key to continue'
curses.cbreak()
self.screen.erase()
(x, term_width) = self.screen.getmaxyx()
row = 2
for line in text:
start = (term_width - len(line)) / 2
self.screen.addstr(row, start, line)
row += 1
self.screen.addstr(row + 1, (term_width - len(hint)) / 2, hint,
curses.A_STANDOUT)
self.screen.getkey()
def show_help_interactive(self): def show_help_interactive(self):
"""Display help with list of interactive commands""" """Display help with list of interactive commands"""
msg = (' c clear filter', msg = (' b toggle events by guests (debugfs only, honors'
' filters)',
' c clear filter',
' f filter by regular expression', ' f filter by regular expression',
' g filter by guest name', ' g filter by guest name',
' h display interactive commands reference', ' h display interactive commands reference',
...@@ -1253,6 +1311,14 @@ class Tui(object): ...@@ -1253,6 +1311,14 @@ class Tui(object):
sleeptime = self._delay_regular sleeptime = self._delay_regular
try: try:
char = self.screen.getkey() char = self.screen.getkey()
if char == 'b':
self._display_guests = not self._display_guests
if self.stats.toggle_display_guests(self._display_guests):
self.show_msg(['Command not available with tracepoints'
' enabled', 'Restart with debugfs only '
'(see option \'-d\') and try again!'])
self._display_guests = not self._display_guests
self.refresh_header()
if char == 'c': if char == 'c':
self.stats.fields_filter = DEFAULT_REGEX self.stats.fields_filter = DEFAULT_REGEX
self.refresh_header(0) self.refresh_header(0)
...@@ -1356,6 +1422,7 @@ Requirements: ...@@ -1356,6 +1422,7 @@ Requirements:
the large number of files that are possibly opened. the large number of files that are possibly opened.
Interactive Commands: Interactive Commands:
b toggle events by guests (debugfs only, honors filters)
c clear filter c clear filter
f filter by regular expression f filter by regular expression
g filter by guest name g filter by guest name
......
...@@ -29,6 +29,8 @@ meaning of events. ...@@ -29,6 +29,8 @@ meaning of events.
INTERACTIVE COMMANDS INTERACTIVE COMMANDS
-------------------- --------------------
[horizontal] [horizontal]
*b*:: toggle events by guests (debugfs only, honors filters)
*c*:: clear filter *c*:: clear filter
*f*:: filter by regular expression *f*:: filter by regular expression
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment