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

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