All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Raspl <raspl@linux.vnet.ibm.com>
To: kvm@vger.kernel.org
Cc: pbonzini@redhat.com, rkrcmar@redhat.com, frankja@linux.vnet.ibm.com
Subject: [PATCH v1 18/19] tools/kvm_stat: add new interactive command 'b'
Date: Wed,  7 Jun 2017 21:08:42 +0200	[thread overview]
Message-ID: <20170607190843.76869-19-raspl@linux.vnet.ibm.com> (raw)
In-Reply-To: <20170607190843.76869-1-raspl@linux.vnet.ibm.com>

Toggle display total number of events by guest (debugfs only).
If both, tracepoints and debugfs, are in use, a mixture of events (from
tracepoints) and guests (from debugfs) is displayed. Furthermore, 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: Stefan Raspl <raspl@linux.vnet.ibm.com>
---
 tools/kvm/kvm_stat/kvm_stat     | 72 ++++++++++++++++++++++++++++++++---------
 tools/kvm/kvm_stat/kvm_stat.txt |  2 ++
 2 files changed, 58 insertions(+), 16 deletions(-)

diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat
index c9f53832af2d..f1cec0103757 100755
--- a/tools/kvm/kvm_stat/kvm_stat
+++ b/tools/kvm/kvm_stat/kvm_stat
@@ -662,7 +662,7 @@ class TracepointProvider(Provider):
         self.setup_traces()
         self.fields = self._fields
 
-    def read(self):
+    def read(self, by_guest=0):
         """Returns 'event name: current value' for all enabled events."""
         ret = defaultdict(int)
         for group in self.group_leaders:
@@ -677,7 +677,7 @@ class TracepointProvider(Provider):
             for event in group.events:
                 event.reset()
 
-    def restore(self):
+    def restore(self, by_guest):
         """No historic data available that we could restore"""
         pass
 
@@ -733,7 +733,7 @@ class DebugfsProvider(Provider):
             self.do_read = True
         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'.
 
         Parameter 'reset':
@@ -764,8 +764,16 @@ class DebugfsProvider(Provider):
                     self._baseline[key] = 0
                 if self._baseline.get(key, -1) == -1:
                     self._baseline[key] = value
-                results[field] = (results.get(field, 0) + value -
-                                  self._baseline.get(key, 0))
+                increment = (results.get(field, 0) + value -
+                             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
 
@@ -784,10 +792,10 @@ class DebugfsProvider(Provider):
         self._baseline = {}
         self.read(1)
 
-    def restore(self):
+    def restore(self, by_guest):
         """Reset field counters"""
         self._baseline = {}
-        self.read(2)
+        self.read(2, by_guest)
 
 
 class Stats(object):
@@ -829,14 +837,14 @@ class Stats(object):
         for provider in self.providers:
             provider.reset()
 
-    def restore(self):
+    def restore(self, by_guests):
         """Restore providers' field counters"""
         self.values = {}
         for provider in self.providers:
-            provider.restore()
+            provider.restore(by_guests)
         # Updates oldval (see get()) for all fields to prevent the totals from
         # being displayed in the 'CurAvg/s' column on next refresh
-        self.get()
+        self.get(by_guests)
 
     @property
     def fields_filter(self):
@@ -860,18 +868,41 @@ class Stats(object):
             for provider in self.providers:
                 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
         provider data."""
         for provider in self.providers:
-            new = provider.read()
-            for key in provider.fields:
+            new = provider.read(by_guest=by_guest)
+            for key in new if by_guest else provider.fields:
                 oldval = self.values.get(key, (0, 0))[0]
                 newval = new.get(key, 0)
                 newdelta = newval - oldval
                 self.values[key] = (newval, newdelta)
         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 to_pid:
+            for provider in self.providers:
+                if isinstance(provider, DebugfsProvider):
+                    for key in provider.fields:
+                        if key in self.values:
+                            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)
+
 DELAY_DEFAULT = 3.0
 MAX_GUEST_NAME_LEN = 48
 MAX_REGEX_LEN = 44
@@ -887,6 +918,7 @@ class Tui(object):
         self._delay_initial = 0.25
         self._delay_regular = DELAY_DEFAULT
         self._sorting = SORT_DEFAULT
+        self._display_guests = 0
 
     def __enter__(self):
         """Initialises curses for later use.  Based on curses.wrapper
@@ -1022,7 +1054,7 @@ class Tui(object):
         row = 3
         self.screen.move(row, 0)
         self.screen.clrtobot()
-        stats = self.stats.get()
+        stats = self.stats.get(self._display_guests)
 
         def sortCurAvg(x):
             # sort by current events if available
@@ -1050,6 +1082,8 @@ class Tui(object):
                 break
             if values[0] is not None:
                 cur = int(round(values[1] / sleeptime)) if values[1] else ''
+                if self._display_guests and key.isdigit():
+                    key = self.get_gname_from_pid(key)
                 self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' %
                                    (key, values[0], values[0] * 100 / total,
                                     cur))
@@ -1060,7 +1094,9 @@ class Tui(object):
 
     def show_help_interactive(self):
         """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',
                '   g     filter by guest name',
                '   h     display interactive commands reference',
@@ -1240,6 +1276,9 @@ class Tui(object):
             sleeptime = self._delay_regular
             try:
                 char = self.screen.getkey()
+                if char == 'b':
+                    self._display_guests = not self._display_guests
+                    self.stats.toggle_display_guests(self._display_guests)
                 if char == 'c':
                     self.stats.fields_filter = DEFAULT_REGEX
                     self.refresh_header(0)
@@ -1273,7 +1312,7 @@ class Tui(object):
                     curses.curs_set(0)
                     sleeptime = self._delay_initial
                 if char == 't':
-                    self.stats.restore()
+                    self.stats.restore(self._display_guests)
                 if char == 'x':
                     self.update_drilldown()
                     # prevents display of current values on next refresh
@@ -1345,6 +1384,7 @@ Requirements:
   the large number of files that are possibly opened.
 
 Interactive Commands:
+   b     toggle events by guests (debugfs only, honors filters)
    c     clear filter
    f     filter by regular expression
    g     filter by guest name
diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt
index bea768ffbd0d..e8ec6147fc05 100644
--- a/tools/kvm/kvm_stat/kvm_stat.txt
+++ b/tools/kvm/kvm_stat/kvm_stat.txt
@@ -29,6 +29,8 @@ meaning of events.
 INTERACTIVE COMMANDS
 --------------------
 [horizontal]
+*b*::	toggle events by guests (debugfs only, honors filters)
+
 *c*::	clear filter
 
 *f*::	filter by regular expression
-- 
2.11.2

  parent reply	other threads:[~2017-06-07 19:09 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-07 19:08 [PATCH v1 00/19] tools/kvm_stat: More misc patches Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 01/19] tools/kvm_stat: fix typo Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 02/19] tools/kvm_stat: fix event counts display for interrupted intervals Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 03/19] tools/kvm_stat: fix undue use of initial sleeptime Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 04/19] tools/kvm_stat: remove unnecessary header redraws Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 05/19] tools/kvm_stat: simplify line print logic Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 06/19] tools/kvm_stat: removed unused function Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 07/19] tools/kvm_stat: remove extra statement Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 08/19] tools/kvm_stat: simplify initializers Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 09/19] tools/kvm_stat: move functions to corresponding classes Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 10/19] tools/kvm_stat: show cursor in selection screens Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 11/19] tools/kvm_stat: display message indicating lack of events Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 12/19] tools/kvm_stat: make heading look a bit more like 'top' Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 13/19] tools/kvm_stat: rename 'Current' column to 'CurAvg/s' Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 14/19] tools/kvm_stat: add new interactive command 'h' Stefan Raspl
2017-06-08 16:19   ` Paolo Bonzini
2017-06-20  9:10     ` Stefan Raspl
2017-06-20 12:34       ` Paolo Bonzini
2017-06-07 19:08 ` [PATCH v1 15/19] tools/kvm_stat: add new interactive command 's' Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 16/19] tools/kvm_stat: add new interactive command 't' Stefan Raspl
2017-06-08 16:21   ` Paolo Bonzini
2017-06-20  9:10     ` Stefan Raspl
2017-06-20 12:34       ` Paolo Bonzini
2017-06-20 13:09         ` Stefan Raspl
2017-06-20 13:17           ` Paolo Bonzini
2017-06-20 14:17             ` Stefan Raspl
2017-06-20 14:47               ` Paolo Bonzini
2017-06-21  6:54                 ` Stefan Raspl
2017-06-21 10:37                   ` Paolo Bonzini
2017-06-22  7:46                     ` Stefan Raspl
2017-06-22  7:52                       ` Paolo Bonzini
2017-06-22  8:51                         ` Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 17/19] tools/kvm_stat: add new interactive command 'o' Stefan Raspl
2017-06-07 19:08 ` Stefan Raspl [this message]
2017-06-08 16:24   ` [PATCH v1 18/19] tools/kvm_stat: add new interactive command 'b' Paolo Bonzini
2017-06-20  9:10     ` Stefan Raspl
2017-06-20 12:33       ` Paolo Bonzini
2017-06-20 13:07         ` Stefan Raspl
2017-06-20 13:10           ` Paolo Bonzini
2017-06-20 14:41             ` Stefan Raspl
2017-06-20 14:47               ` Paolo Bonzini
2017-06-21  4:51                 ` Stefan Raspl
2017-06-07 19:08 ` [PATCH v1 19/19] tools/kvm_stat: display guest list in pid/guest selection screens Stefan Raspl
2017-06-08 16:25 ` [PATCH v1 00/19] tools/kvm_stat: More misc patches Paolo Bonzini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170607190843.76869-19-raspl@linux.vnet.ibm.com \
    --to=raspl@linux.vnet.ibm.com \
    --cc=frankja@linux.vnet.ibm.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=rkrcmar@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.