Blame SOURCES/kvm-tools-kvm_stat-add-new-interactive-command-b.patch

4a2fec
From 17165a0bc8b8496f52f9273fe4466797f3a6726e Mon Sep 17 00:00:00 2001
4a2fec
From: David Hildenbrand <david@redhat.com>
4a2fec
Date: Tue, 17 Oct 2017 19:16:03 +0200
4a2fec
Subject: [PATCH 58/69] tools/kvm_stat: add new interactive command 'b'
4a2fec
4a2fec
RH-Author: David Hildenbrand <david@redhat.com>
4a2fec
Message-id: <20171017191605.2378-38-david@redhat.com>
4a2fec
Patchwork-id: 77344
4a2fec
O-Subject: [RHEL-7.5 qemu-kvm-rhev PATCH 37/39] tools/kvm_stat: add new interactive command 'b'
4a2fec
Bugzilla: 1497137
4a2fec
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
4a2fec
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
4a2fec
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
4a2fec
RH-Acked-by: Thomas Huth <thuth@redhat.com>
4a2fec
4a2fec
Upstream-status: linux.git 5c1954d25d1b9e857be2a4c77437312075875589
4a2fec
4a2fec
Convertion of documentation (for man page generation) to texi.
4a2fec
4a2fec
commit 5c1954d25d1b9e857be2a4c77437312075875589
4a2fec
Author: Stefan Raspl <raspl@linux.vnet.ibm.com>
4a2fec
Date:   Sun Jun 25 21:34:16 2017 +0200
4a2fec
4a2fec
    tools/kvm_stat: add new interactive command 'b'
4a2fec
4a2fec
    Toggle display total number of events by guest (debugfs only).
4a2fec
    When switching to display of events by guest, field filters remain
4a2fec
    active. I.e. the number of events per guest reported considers only
4a2fec
    events matching the filters. Likewise with pid/guest filtering.
4a2fec
    Note that when switching to display of events by guest, DebugfsProvider
4a2fec
    remains to collect data for events as it did before, but the read()
4a2fec
    method summarizes the values by pid.
4a2fec
4a2fec
    Signed-off-by: Stefan Raspl <raspl@linux.vnet.ibm.com>
4a2fec
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
4a2fec
4a2fec
Signed-off-by: David Hildenbrand <david@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 scripts/kvm/kvm_stat      | 87 +++++++++++++++++++++++++++++++++++++++++------
4a2fec
 scripts/kvm/kvm_stat.texi |  3 ++
4a2fec
 2 files changed, 80 insertions(+), 10 deletions(-)
4a2fec
4a2fec
diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
4a2fec
index 4065b29..dd8f00c 100755
4a2fec
--- a/scripts/kvm/kvm_stat
4a2fec
+++ b/scripts/kvm/kvm_stat
4a2fec
@@ -662,7 +662,7 @@ class TracepointProvider(Provider):
4a2fec
         self.setup_traces()
4a2fec
         self.fields = self._fields
4a2fec
 
4a2fec
-    def read(self):
4a2fec
+    def read(self, by_guest=0):
4a2fec
         """Returns 'event name: current value' for all enabled events."""
4a2fec
         ret = defaultdict(int)
4a2fec
         for group in self.group_leaders:
4a2fec
@@ -731,7 +731,7 @@ class DebugfsProvider(Provider):
4a2fec
             self.do_read = True
4a2fec
         self.reset()
4a2fec
 
4a2fec
-    def read(self, reset=0):
4a2fec
+    def read(self, reset=0, by_guest=0):
4a2fec
         """Returns a dict with format:'file name / field -> current value'.
4a2fec
 
4a2fec
         Parameter 'reset':
4a2fec
@@ -762,8 +762,16 @@ class DebugfsProvider(Provider):
4a2fec
                     self._baseline[key] = 0
4a2fec
                 if self._baseline.get(key, -1) == -1:
4a2fec
                     self._baseline[key] = value
4a2fec
-                results[field] = (results.get(field, 0) + value -
4a2fec
-                                  self._baseline.get(key, 0))
4a2fec
+                increment = (results.get(field, 0) + value -
4a2fec
+                             self._baseline.get(key, 0))
4a2fec
+                if by_guest:
4a2fec
+                    pid = key.split('-')[0]
4a2fec
+                    if pid in results:
4a2fec
+                        results[pid] += increment
4a2fec
+                    else:
4a2fec
+                        results[pid] = increment
4a2fec
+                else:
4a2fec
+                    results[field] = increment
4a2fec
 
4a2fec
         return results
4a2fec
 
4a2fec
@@ -849,18 +857,44 @@ class Stats(object):
4a2fec
             for provider in self.providers:
4a2fec
                 provider.pid = self._pid_filter
4a2fec
 
4a2fec
-    def get(self):
4a2fec
+    def get(self, by_guest=0):
4a2fec
         """Returns a dict with field -> (value, delta to last value) of all
4a2fec
         provider data."""
4a2fec
         for provider in self.providers:
4a2fec
-            new = provider.read()
4a2fec
-            for key in provider.fields:
4a2fec
+            new = provider.read(by_guest=by_guest)
4a2fec
+            for key in new if by_guest else provider.fields:
4a2fec
                 oldval = self.values.get(key, (0, 0))[0]
4a2fec
                 newval = new.get(key, 0)
4a2fec
                 newdelta = newval - oldval
4a2fec
                 self.values[key] = (newval, newdelta)
4a2fec
         return self.values
4a2fec
 
4a2fec
+    def toggle_display_guests(self, to_pid):
4a2fec
+        """Toggle between collection of stats by individual event and by
4a2fec
+        guest pid
4a2fec
+
4a2fec
+        Events reported by DebugfsProvider change when switching to/from
4a2fec
+        reading by guest values. Hence we have to remove the excess event
4a2fec
+        names from self.values.
4a2fec
+
4a2fec
+        """
4a2fec
+        if any(isinstance(ins, TracepointProvider) for ins in self.providers):
4a2fec
+            return 1
4a2fec
+        if to_pid:
4a2fec
+            for provider in self.providers:
4a2fec
+                if isinstance(provider, DebugfsProvider):
4a2fec
+                    for key in provider.fields:
4a2fec
+                        if key in self.values.keys():
4a2fec
+                            del self.values[key]
4a2fec
+        else:
4a2fec
+            oldvals = self.values.copy()
4a2fec
+            for key in oldvals:
4a2fec
+                if key.isdigit():
4a2fec
+                    del self.values[key]
4a2fec
+        # Update oldval (see get())
4a2fec
+        self.get(to_pid)
4a2fec
+        return 0
4a2fec
+
4a2fec
 DELAY_DEFAULT = 3.0
4a2fec
 MAX_GUEST_NAME_LEN = 48
4a2fec
 MAX_REGEX_LEN = 44
4a2fec
@@ -876,6 +910,7 @@ class Tui(object):
4a2fec
         self._delay_initial = 0.25
4a2fec
         self._delay_regular = DELAY_DEFAULT
4a2fec
         self._sorting = SORT_DEFAULT
4a2fec
+        self._display_guests = 0
4a2fec
 
4a2fec
     def __enter__(self):
4a2fec
         """Initialises curses for later use.  Based on curses.wrapper
4a2fec
@@ -1024,8 +1059,12 @@ class Tui(object):
4a2fec
             if len(regex) > MAX_REGEX_LEN:
4a2fec
                 regex = regex[:MAX_REGEX_LEN] + '...'
4a2fec
             self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex))
4a2fec
+        if self._display_guests:
4a2fec
+            col_name = 'Guest Name'
4a2fec
+        else:
4a2fec
+            col_name = 'Event'
4a2fec
         self.screen.addstr(2, 1, '%-40s %10s%7s %8s' %
4a2fec
-                           ('Event', 'Total', '%Total', 'CurAvg/s'),
4a2fec
+                           (col_name, 'Total', '%Total', 'CurAvg/s'),
4a2fec
                            curses.A_STANDOUT)
4a2fec
         self.screen.addstr(4, 1, 'Collecting data...')
4a2fec
         self.screen.refresh()
4a2fec
@@ -1034,7 +1073,7 @@ class Tui(object):
4a2fec
         row = 3
4a2fec
         self.screen.move(row, 0)
4a2fec
         self.screen.clrtobot()
4a2fec
-        stats = self.stats.get()
4a2fec
+        stats = self.stats.get(self._display_guests)
4a2fec
 
4a2fec
         def sortCurAvg(x):
4a2fec
             # sort by current events if available
4a2fec
@@ -1062,6 +1101,8 @@ class Tui(object):
4a2fec
                 break
4a2fec
             if values[0] is not None:
4a2fec
                 cur = int(round(values[1] / sleeptime)) if values[1] else ''
4a2fec
+                if self._display_guests:
4a2fec
+                    key = self.get_gname_from_pid(key)
4a2fec
                 self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' %
4a2fec
                                    (key, values[0], values[0] * 100 / total,
4a2fec
                                     cur))
4a2fec
@@ -1070,9 +1111,26 @@ class Tui(object):
4a2fec
             self.screen.addstr(4, 1, 'No matching events reported yet')
4a2fec
         self.screen.refresh()
4a2fec
 
4a2fec
+    def show_msg(self, text):
4a2fec
+        """Display message centered text and exit on key press"""
4a2fec
+        hint = 'Press any key to continue'
4a2fec
+        curses.cbreak()
4a2fec
+        self.screen.erase()
4a2fec
+        (x, term_width) = self.screen.getmaxyx()
4a2fec
+        row = 2
4a2fec
+        for line in text:
4a2fec
+            start = (term_width - len(line)) / 2
4a2fec
+            self.screen.addstr(row, start, line)
4a2fec
+            row += 1
4a2fec
+        self.screen.addstr(row + 1, (term_width - len(hint)) / 2, hint,
4a2fec
+                           curses.A_STANDOUT)
4a2fec
+        self.screen.getkey()
4a2fec
+
4a2fec
     def show_help_interactive(self):
4a2fec
         """Display help with list of interactive commands"""
4a2fec
-        msg = ('   c     clear filter',
4a2fec
+        msg = ('   b     toggle events by guests (debugfs only, honors'
4a2fec
+               ' filters)',
4a2fec
+               '   c     clear filter',
4a2fec
                '   f     filter by regular expression',
4a2fec
                '   g     filter by guest name',
4a2fec
                '   h     display interactive commands reference',
4a2fec
@@ -1253,6 +1311,14 @@ class Tui(object):
4a2fec
             sleeptime = self._delay_regular
4a2fec
             try:
4a2fec
                 char = self.screen.getkey()
4a2fec
+                if char == 'b':
4a2fec
+                    self._display_guests = not self._display_guests
4a2fec
+                    if self.stats.toggle_display_guests(self._display_guests):
4a2fec
+                        self.show_msg(['Command not available with tracepoints'
4a2fec
+                                       ' enabled', 'Restart with debugfs only '
4a2fec
+                                       '(see option \'-d\') and try again!'])
4a2fec
+                        self._display_guests = not self._display_guests
4a2fec
+                    self.refresh_header()
4a2fec
                 if char == 'c':
4a2fec
                     self.stats.fields_filter = DEFAULT_REGEX
4a2fec
                     self.refresh_header(0)
4a2fec
@@ -1356,6 +1422,7 @@ Requirements:
4a2fec
   the large number of files that are possibly opened.
4a2fec
 
4a2fec
 Interactive Commands:
4a2fec
+   b     toggle events by guests (debugfs only, honors filters)
4a2fec
    c     clear filter
4a2fec
    f     filter by regular expression
4a2fec
    g     filter by guest name
4a2fec
diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi
4a2fec
index b0e282a..5d964f6 100644
4a2fec
--- a/scripts/kvm/kvm_stat.texi
4a2fec
+++ b/scripts/kvm/kvm_stat.texi
4a2fec
@@ -24,6 +24,9 @@ Use batch and logging modes for scripting purposes.
4a2fec
 While running in regular (interactive) mode, use any of the following keys:
4a2fec
 
4a2fec
 @table @key
4a2fec
+@item b
4a2fec
+@kindex b
4a2fec
+toggle events by guests (debugfs only, honors filters)
4a2fec
 @item c
4a2fec
 @kindex c
4a2fec
 clear filter
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec