From a0b4e6a0325e325d91901342dd436d917da0ddd6 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:00 +0100 Subject: tools/kvm_stat: hide cursor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running kvm_stat in interactive mode, the cursor appears at the lower left corner, which looks a bit distracting. This patch hides the cursor by turning it invisible. Signed-off-by: Stefan Raspl Reviewed-By: Sascha Silbe Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 581278c58488..8cc83a309e65 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -812,6 +812,13 @@ class Tui(object): except: pass + # Hide cursor in extra statement as some monochrome terminals + # might support hiding but not colors. + try: + curses.curs_set(0) + except curses.error: + pass + curses.use_default_colors() return self -- cgit v1.2.3 From 9fc0adfc427a5e3f95f8db8dafabe1eaa3720f4a Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:01 +0100 Subject: tools/kvm_stat: catch curses exceptions only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous version was catching all exceptions, including SIGINT. We only want to catch the curses exceptions here. Signed-off-by: Stefan Raspl Reviewed-by: Janosch Frank Reviewed-by: Sascha Silbe Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 8cc83a309e65..ef47ad749f8a 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -809,7 +809,7 @@ class Tui(object): # return from C start_color() is ignorable. try: curses.start_color() - except: + except curses.error: pass # Hide cursor in extra statement as some monochrome terminals -- cgit v1.2.3 From dadf1e7839243474b691ca4258bfd2a59e628a5e Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:02 +0100 Subject: tools/kvm_stat: handle SIGINT in log and batch modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SIGINT causes ugly unhandled exceptions in log and batch mode, which we prevent by catching the exceptions accordingly. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index ef47ad749f8a..14536c059fd7 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -969,12 +969,15 @@ class Tui(object): def batch(stats): """Prints statistics in a key, value format.""" - s = stats.get() - time.sleep(1) - s = stats.get() - for key in sorted(s.keys()): - values = s[key] - print '%-42s%10d%10d' % (key, values[0], values[1]) + try: + s = stats.get() + time.sleep(1) + s = stats.get() + for key in sorted(s.keys()): + values = s[key] + print '%-42s%10d%10d' % (key, values[0], values[1]) + except KeyboardInterrupt: + pass def log(stats): """Prints statistics as reiterating key block, multiple value blocks.""" @@ -991,11 +994,14 @@ def log(stats): line = 0 banner_repeat = 20 while True: - time.sleep(1) - if line % banner_repeat == 0: - banner() - statline() - line += 1 + try: + time.sleep(1) + if line % banner_repeat == 0: + banner() + statline() + line += 1 + except KeyboardInterrupt: + break def get_options(): """Returns processed program arguments.""" -- cgit v1.2.3 From e0ba38765c1d1d670246d6f6c518594aa8e62587 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:03 +0100 Subject: tools/kvm_stat: fix misc glitches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses - eliminate extra import - missing variable initialization - type redefinition from int to float - passing of int type argument instead of string - a couple of PEP8-reported indentation/formatting glitches - remove unused variable drilldown in class Tui Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 14536c059fd7..231186a773aa 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -31,7 +31,6 @@ import resource import struct import re from collections import defaultdict -from time import sleep VMX_EXIT_REASONS = { 'EXCEPTION_NMI': 0, @@ -657,6 +656,7 @@ class DebugfsProvider(object): self._fields = self.get_available_fields() self._pid = 0 self.do_read = True + self.paths = [] def get_available_fields(self): """"Returns a list of available fields. @@ -794,7 +794,6 @@ class Tui(object): def __init__(self, stats): self.stats = stats self.screen = None - self.drilldown = False self.update_drilldown() def __enter__(self): @@ -950,11 +949,10 @@ class Tui(object): while True: self.refresh(sleeptime) curses.halfdelay(int(sleeptime * 10)) - sleeptime = 3 + sleeptime = 3.0 try: char = self.screen.getkey() if char == 'x': - self.drilldown = not self.drilldown self.update_drilldown() if char == 'q': break @@ -1064,12 +1062,12 @@ Requirements: help='fields to display (regex)', ) optparser.add_option('-p', '--pid', - action='store', - default=0, - type=int, - dest='pid', - help='restrict statistics to pid', - ) + action='store', + default=0, + type='int', + dest='pid', + help='restrict statistics to pid', + ) (options, _) = optparser.parse_args(sys.argv) return options @@ -1099,8 +1097,8 @@ def check_access(options): "Also ensure, that the kvm modules are loaded.\n") sys.exit(1) - if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints - or not options.debugfs): + if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or + not options.debugfs): sys.stderr.write("Please enable CONFIG_TRACING in your kernel " "when using the option -t (default).\n" "If it is enabled, make {0} readable by the " @@ -1111,7 +1109,7 @@ def check_access(options): sys.stderr.write("Falling back to debugfs statistics!\n") options.debugfs = True - sleep(5) + time.sleep(5) return options -- cgit v1.2.3 From a183606937489ab5ada2215aa8211374a6b26bd3 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:04 +0100 Subject: tools/kvm_stat: fix trace setup glitch on field updates in TracepointProvider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updating the fields of the TracepointProvider does not propagate changes to the tracepoints. This shows when a pid filter is enabled, whereby subsequent extensions of the fields of the Tracepoint provider (e.g. by toggling drilldown) will not modify the tracepoints as required. To reproduce, select a specific process via interactive command 'p', and enable drilldown via 'x' - none of the fields with the braces will appear although they should. The fix will always leave all available fields in the TracepointProvider enabled. Signed-off-by: Stefan Raspl Based-on-text-by: Janosch Frank Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 231186a773aa..6207843b9199 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -550,6 +550,7 @@ class TracepointProvider(object): def setup_traces(self): """Creates all event and group objects needed to be able to retrieve data.""" + fields = self.get_available_fields() if self._pid > 0: # Fetch list of all threads of the monitored pid, as qemu # starts a thread for each vcpu. @@ -560,7 +561,7 @@ class TracepointProvider(object): # The constant is needed as a buffer for python libs, std # streams and other files that the script opens. - newlim = len(groupids) * len(self._fields) + 50 + newlim = len(groupids) * len(fields) + 50 try: softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE) @@ -576,7 +577,7 @@ class TracepointProvider(object): for groupid in groupids: group = Group() - for name in self._fields: + for name in fields: tracepoint = name tracefilter = None match = re.match(r'(.*)\((.*)\)', name) -- cgit v1.2.3 From 692c7f6deb553dde2531102cd10ac17ab61438e4 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:05 +0100 Subject: tools/kvm_stat: full PEP8 compliance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides all missing empty lines as required for full PEP compliance. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 6207843b9199..5c4f24879dc4 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -224,6 +224,7 @@ IOCTL_NUMBERS = { 'RESET': 0x00002403, } + class Arch(object): """Encapsulates global architecture specific data. @@ -254,12 +255,14 @@ class Arch(object): return ArchX86(SVM_EXIT_REASONS) return + class ArchX86(Arch): def __init__(self, exit_reasons): self.sc_perf_evt_open = 298 self.ioctl_numbers = IOCTL_NUMBERS self.exit_reasons = exit_reasons + class ArchPPC(Arch): def __init__(self): self.sc_perf_evt_open = 319 @@ -274,12 +277,14 @@ class ArchPPC(Arch): self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 self.exit_reasons = {} + class ArchA64(Arch): def __init__(self): self.sc_perf_evt_open = 241 self.ioctl_numbers = IOCTL_NUMBERS self.exit_reasons = AARCH64_EXIT_REASONS + class ArchS390(Arch): def __init__(self): self.sc_perf_evt_open = 331 @@ -341,6 +346,7 @@ def get_filters(): libc = ctypes.CDLL('libc.so.6', use_errno=True) syscall = libc.syscall + class perf_event_attr(ctypes.Structure): """Struct that holds the necessary data to set up a trace event. @@ -369,6 +375,7 @@ class perf_event_attr(ctypes.Structure): self.size = ctypes.sizeof(self) self.read_format = PERF_FORMAT_GROUP + def perf_event_open(attr, pid, cpu, group_fd, flags): """Wrapper for the sys_perf_evt_open() syscall. @@ -394,6 +401,7 @@ PERF_FORMAT_GROUP = 1 << 3 PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing' PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm' + class Group(object): """Represents a perf event group.""" @@ -426,6 +434,7 @@ class Group(object): struct.unpack(read_format, os.read(self.events[0].fd, length)))) + class Event(object): """Represents a performance event and manages its life cycle.""" def __init__(self, name, group, trace_cpu, trace_pid, trace_point, @@ -509,6 +518,7 @@ class Event(object): """Resets the count of the trace event in the kernel.""" fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0) + class TracepointProvider(object): """Data provider for the stats class. @@ -650,6 +660,7 @@ class TracepointProvider(object): ret[name] += val return ret + class DebugfsProvider(object): """Provides data from the files that KVM creates in the kvm debugfs folder.""" @@ -719,6 +730,7 @@ class DebugfsProvider(object): except IOError: return 0 + class Stats(object): """Manages the data providers and the data they provide. @@ -790,6 +802,7 @@ class Stats(object): LABEL_WIDTH = 40 NUMBER_WIDTH = 10 + class Tui(object): """Instruments curses to draw a nice text ui.""" def __init__(self, stats): @@ -859,6 +872,7 @@ class Tui(object): len('Current'), 'Current') row = 3 stats = self.stats.get() + def sortkey(x): if stats[x][1]: return (-stats[x][1], -stats[x][0]) @@ -966,6 +980,7 @@ class Tui(object): except curses.error: continue + def batch(stats): """Prints statistics in a key, value format.""" try: @@ -978,13 +993,16 @@ def batch(stats): except KeyboardInterrupt: pass + def log(stats): """Prints statistics as reiterating key block, multiple value blocks.""" keys = sorted(stats.get().iterkeys()) + def banner(): for k in keys: print '%s' % k, print + def statline(): s = stats.get() for k in keys: @@ -1002,6 +1020,7 @@ def log(stats): except KeyboardInterrupt: break + def get_options(): """Returns processed program arguments.""" description_text = """ @@ -1072,6 +1091,7 @@ Requirements: (options, _) = optparser.parse_args(sys.argv) return options + def get_providers(options): """Returns a list of data providers depending on the passed options.""" providers = [] @@ -1085,6 +1105,7 @@ def get_providers(options): return providers + def check_access(options): """Exits if the current user can't access all needed directories.""" if not os.path.exists('/sys/kernel/debug'): @@ -1114,6 +1135,7 @@ def check_access(options): return options + def main(): options = get_options() options = check_access(options) -- cgit v1.2.3 From 184b2d23b057b35fba7fd4049962a897ef0e3f9d Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:06 +0100 Subject: tools/kvm_stat: reduce perceived idle time on filter updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Whenever a user adds a filter, we * redraw the header immediately for a snappy response * print a message indicating to the user that we're busy while the noticeable delay induced by updating all of the stats objects takes place * update the statistics ASAP (i.e. after 0.25s instead of 3s) to be consistent with behavior on startup To do so, we split the Tui's refresh() method to allow for drawing header and stats separately, and trigger a header refresh whenever we are about to do something that takes a while - like updating filters. Signed-off-by: Stefan Raspl Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 48 ++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 5c4f24879dc4..3e60d93870c0 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -801,6 +801,8 @@ class Stats(object): LABEL_WIDTH = 40 NUMBER_WIDTH = 10 +DELAY_INITIAL = 0.25 +DELAY_REGULAR = 3.0 class Tui(object): @@ -856,13 +858,14 @@ class Tui(object): """Propagates pid selection to stats object.""" self.stats.pid_filter = pid - def refresh(self, sleeptime): - """Refreshes on-screen data.""" + def refresh_header(self, pid=None): + """Refreshes the header.""" + if pid is None: + pid = self.stats.pid_filter self.screen.erase() - if self.stats.pid_filter > 0: + if pid > 0: self.screen.addstr(0, 0, 'kvm statistics - pid {0}' - .format(self.stats.pid_filter), - curses.A_BOLD) + .format(pid), curses.A_BOLD) else: self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) self.screen.addstr(2, 1, 'Event') @@ -870,7 +873,13 @@ class Tui(object): len('Total'), 'Total') self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - len('Current'), 'Current') + self.screen.addstr(4, 1, 'Collecting data...') + self.screen.refresh() + + def refresh_body(self, sleeptime): row = 3 + self.screen.move(row, 0) + self.screen.clrtobot() stats = self.stats.get() def sortkey(x): @@ -914,10 +923,12 @@ class Tui(object): regex = self.screen.getstr() curses.noecho() if len(regex) == 0: + self.refresh_header() return try: re.compile(regex) self.stats.fields_filter = regex + self.refresh_header() return except re.error: continue @@ -944,37 +955,38 @@ class Tui(object): try: pid = int(pid) - - if pid == 0: - self.update_pid(pid) - break - else: - if not os.path.isdir(os.path.join('/proc/', str(pid))): - continue - else: - self.update_pid(pid) - break + if pid != 0 and not os.path.isdir(os.path.join('/proc/', + str(pid))): + continue + self.refresh_header(pid) + self.update_pid(pid) + break except ValueError: continue def show_stats(self): """Refreshes the screen and processes user input.""" - sleeptime = 0.25 + sleeptime = DELAY_INITIAL + self.refresh_header() while True: - self.refresh(sleeptime) + self.refresh_body(sleeptime) curses.halfdelay(int(sleeptime * 10)) - sleeptime = 3.0 + sleeptime = DELAY_REGULAR try: char = self.screen.getkey() if char == 'x': + self.refresh_header() self.update_drilldown() + sleeptime = DELAY_INITIAL if char == 'q': break if char == 'f': self.show_filter_selection() + sleeptime = DELAY_INITIAL if char == 'p': self.show_vm_selection() + sleeptime = DELAY_INITIAL except KeyboardInterrupt: break except curses.error: -- cgit v1.2.3 From 1eaa2f9022d55a8d7249c42def8dc4b0d682e142 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:07 +0100 Subject: tools/kvm_stat: document list of interactive commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apart from the source code, there does not seem to be a place that documents the interactive capabilities of kvm_stat yet. Signed-off-by: Stefan Raspl Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 7 +++++++ tools/kvm/kvm_stat/kvm_stat.txt | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 3e60d93870c0..aca85086be1e 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -1052,6 +1052,13 @@ Requirements: CAP_SYS_ADMIN and perf events are used. - CAP_SYS_RESOURCE if the hard limit is not high enough to allow the large number of files that are possibly opened. + +Interactive Commands: + f filter by regular expression + p filter by PID + q quit + x toggle reporting of stats for individual child trace events +Press any other key to refresh statistics immediately. """ class PlainHelpFormatter(optparse.IndentedHelpFormatter): diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index b92a153d7115..077bcc7e20dc 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt @@ -18,11 +18,27 @@ state transitions such as guest mode entry and exit. This tool is useful for observing guest behavior from the host perspective. Often conclusions about performance or buggy behavior can be drawn from the output. +While running in regular mode, use any of the keys listed in section +'Interactive Commands' below. +Use batch and logging modes for scripting purposes. The set of KVM kernel module trace events may be specific to the kernel version or architecture. It is best to check the KVM kernel module source code for the meaning of events. +INTERACTIVE COMMANDS +-------------------- +[horizontal] +*f*:: filter by regular expression + +*p*:: filter by PID + +*q*:: quit + +*x*:: toggle reporting of stats for child trace events + +Press any other key to refresh statistics immediately. + OPTIONS ------- -1:: -- cgit v1.2.3 From a24e85f6a69f09a9d09a86110a6bb168c60610ef Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:08 +0100 Subject: tools/kvm_stat: display guest name when using pid filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When running kvm_stat with option '-p' to filter per process, display the QEMU guest name next to the pid, if available. Signed-off-by: Stefan Raspl Reviewed-By: Janosch Frank Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index aca85086be1e..95ffa9a4b044 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -320,6 +320,37 @@ def parse_int_list(list_string): return integers +def get_gname_from_pid(pid): + """Returns the guest name for a QEMU process pid. + + Extracts the guest name from the QEMU comma line by processing the '-name' + option. Will also handle names specified out of sequence. + + """ + name = '' + try: + line = open('/proc/{}/cmdline'.format(pid), 'rb').read().split('\0') + parms = line[line.index('-name') + 1].split(',') + while '' in parms: + # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in + # ['foo', '', 'bar'], which we revert here + idx = parms.index('') + parms[idx - 1] += ',' + parms[idx + 1] + del parms[idx:idx+2] + # the '-name' switch allows for two ways to specify the guest name, + # where the plain name overrides the name specified via 'guest=' + for arg in parms: + if '=' not in arg: + name = arg + break + if arg[:6] == 'guest=': + name = arg[6:] + except (ValueError, IOError, IndexError): + pass + + return name + + def get_online_cpus(): """Returns a list of cpu id integers.""" with open('/sys/devices/system/cpu/online') as cpu_list: @@ -803,6 +834,7 @@ LABEL_WIDTH = 40 NUMBER_WIDTH = 10 DELAY_INITIAL = 0.25 DELAY_REGULAR = 3.0 +MAX_GUEST_NAME_LEN = 48 class Tui(object): @@ -863,9 +895,14 @@ class Tui(object): if pid is None: pid = self.stats.pid_filter self.screen.erase() + gname = get_gname_from_pid(pid) + if gname: + gname = ('({})'.format(gname[:MAX_GUEST_NAME_LEN] + '...' + if len(gname) > MAX_GUEST_NAME_LEN + else gname)) if pid > 0: - self.screen.addstr(0, 0, 'kvm statistics - pid {0}' - .format(pid), curses.A_BOLD) + self.screen.addstr(0, 0, 'kvm statistics - pid {0} {1}' + .format(pid, gname), curses.A_BOLD) else: self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) self.screen.addstr(2, 1, 'Event') -- cgit v1.2.3 From be03ea3b77387db36617d71d60ee182a866fb9cd Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:09 +0100 Subject: tools/kvm_stat: remove pid filter on empty input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improve consistency in the interactive dialogue for pid filtering by removing any filters on empty input (in addition to entering 0). Signed-off-by: Stefan Raspl Reviewed-by: Janosch Frank Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 95ffa9a4b044..9e9eb983f6fe 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -991,10 +991,13 @@ class Tui(object): curses.noecho() try: - pid = int(pid) - if pid != 0 and not os.path.isdir(os.path.join('/proc/', - str(pid))): - continue + if len(pid) > 0: + pid = int(pid) + if pid != 0 and not os.path.isdir(os.path.join('/proc/', + str(pid))): + continue + else: + pid = 0 self.refresh_header(pid) self.update_pid(pid) break -- cgit v1.2.3 From 0152c20f0400498774ae56067f8076cef312abc7 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:10 +0100 Subject: tools/kvm_stat: print error messages on faulty pid filter input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print helpful messages in case users enter invalid input or invalid pids in the interactive pid filter dialogue. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 9e9eb983f6fe..ced0cb908ddb 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -976,6 +976,7 @@ class Tui(object): Asks for a pid until a valid pid or 0 has been entered. """ + msg = '' while True: self.screen.erase() self.screen.addstr(0, 0, @@ -984,6 +985,7 @@ class Tui(object): 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, "Pid [0 or pid]: ") @@ -995,6 +997,7 @@ class Tui(object): pid = int(pid) if pid != 0 and not os.path.isdir(os.path.join('/proc/', str(pid))): + msg = '"' + str(pid) + '": Not a running process' continue else: pid = 0 @@ -1003,6 +1006,7 @@ class Tui(object): break except ValueError: + msg = '"' + str(pid) + '": Not a valid pid' continue def show_stats(self): -- cgit v1.2.3 From 72187dfa8e2686b748ad7485d0ca59ba993ba526 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:11 +0100 Subject: tools/kvm_stat: display regex when set to non-default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a user defines a regex filter through the interactive command, display the active regex in the header's second line. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index ced0cb908ddb..af7071778a0c 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -835,6 +835,7 @@ NUMBER_WIDTH = 10 DELAY_INITIAL = 0.25 DELAY_REGULAR = 3.0 MAX_GUEST_NAME_LEN = 48 +MAX_REGEX_LEN = 44 class Tui(object): @@ -905,6 +906,11 @@ class Tui(object): .format(pid, gname), curses.A_BOLD) else: self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) + if self.stats.fields_filter and self.stats.fields_filter != '^[^\(]*$': + regex = self.stats.fields_filter + if len(regex) > MAX_REGEX_LEN: + regex = regex[:MAX_REGEX_LEN] + '...' + self.screen.addstr(1, 17, 'regex filter: {0}'.format(regex)) self.screen.addstr(2, 1, 'Event') self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - len('Total'), 'Total') -- cgit v1.2.3 From 645c1728a9d33d78028d93a2ed770f51df0a92c6 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:12 +0100 Subject: tools/kvm_stat: remove regex filter on empty input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Behavior on empty/0 input for regex and pid filtering was inconsistent, as the former would keep the current filter, while the latter would (naturally) remove any pid filtering. Make things consistent by falling back to the default filter on empty input for the regex filter dialogue. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index af7071778a0c..f2a868b696a8 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -966,6 +966,7 @@ class Tui(object): regex = self.screen.getstr() curses.noecho() if len(regex) == 0: + self.stats.fields_filter = r'^[^\(]*$' self.refresh_header() return try: -- cgit v1.2.3 From f9ff1087354e5e063b96a291360a8de84bea0bed Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:13 +0100 Subject: tools/kvm_stat: add option '--guest' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Janosch Frank Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 101 +++++++++++++++++++++++++++++++++++++++- tools/kvm/kvm_stat/kvm_stat.txt | 6 +++ 2 files changed, 105 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index f2a868b696a8..f263312c9a29 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -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 diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index 077bcc7e20dc..35587c3c2610 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt @@ -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=:: limit statistics to one virtual machine (pid) +-g:: +--guest=:: + limit statistics to one virtual machine (guest name) + -f:: --fields=:: fields to display (regex) -- cgit v1.2.3 From 4443084fa0cf85f91d357c8917b90504b784d925 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:14 +0100 Subject: tools/kvm_stat: add interactive command 'c' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide a real simple way to erase any active filter. Signed-off-by: Stefan Raspl Reviewed-by: Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 16 ++++++++++++---- tools/kvm/kvm_stat/kvm_stat.txt | 2 ++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index f263312c9a29..676a92a4a12e 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -861,6 +861,7 @@ DELAY_INITIAL = 0.25 DELAY_REGULAR = 3.0 MAX_GUEST_NAME_LEN = 48 MAX_REGEX_LEN = 44 +DEFAULT_REGEX = r'^[^\(]*$' class Tui(object): @@ -907,9 +908,9 @@ class Tui(object): def update_drilldown(self): """Sets or removes a filter that only allows fields without braces.""" if not self.stats.fields_filter: - self.stats.fields_filter = r'^[^\(]*$' + self.stats.fields_filter = DEFAULT_REGEX - elif self.stats.fields_filter == r'^[^\(]*$': + elif self.stats.fields_filter == DEFAULT_REGEX: self.stats.fields_filter = None def update_pid(self, pid): @@ -931,7 +932,8 @@ class Tui(object): .format(pid, gname), curses.A_BOLD) else: self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD) - if self.stats.fields_filter and self.stats.fields_filter != '^[^\(]*$': + if self.stats.fields_filter and self.stats.fields_filter \ + != DEFAULT_REGEX: regex = self.stats.fields_filter if len(regex) > MAX_REGEX_LEN: regex = regex[:MAX_REGEX_LEN] + '...' @@ -991,7 +993,7 @@ class Tui(object): regex = self.screen.getstr() curses.noecho() if len(regex) == 0: - self.stats.fields_filter = r'^[^\(]*$' + self.stats.fields_filter = DEFAULT_REGEX self.refresh_header() return try: @@ -1101,6 +1103,11 @@ class Tui(object): sleeptime = DELAY_INITIAL if char == 'q': break + if char == 'c': + self.stats.fields_filter = DEFAULT_REGEX + self.refresh_header(0) + self.update_pid(0) + sleeptime = DELAY_INITIAL if char == 'f': self.show_filter_selection() sleeptime = DELAY_INITIAL @@ -1177,6 +1184,7 @@ Requirements: the large number of files that are possibly opened. Interactive Commands: + c clear filter f filter by regular expression g filter by guest name p filter by PID diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index 35587c3c2610..c3ab6a2c8c37 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] +*c*:: clear filter + *f*:: filter by regular expression *g*:: filter by guest name -- cgit v1.2.3 From 9f114a03c6854f49065dd036c17e1b4bb947f842 Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:15 +0100 Subject: tools/kvm_stat: add interactive command 'r' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide an interactive command to reset the tracepoint statistics. Requires some extra work for debugfs, as the counters cannot be reset. On the up side, this offers us the opportunity to have debugfs values reset on startup and whenever a filter is modified, becoming consistent with the tracepoint provider. As a bonus, 'kvmstat -dt' will now provide useful output, instead of mixing values in totally different orders of magnitude. Furthermore, we avoid unnecessary resets when any of the filters is "changed" interactively to the previous value. Signed-off-by: Stefan Raspl Acked-by: Janosch Frank Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 65 ++++++++++++++++++++++++++++++++--------- tools/kvm/kvm_stat/kvm_stat.txt | 2 ++ 2 files changed, 53 insertions(+), 14 deletions(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index 676a92a4a12e..f8c48f8d07a7 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -716,15 +716,23 @@ class TracepointProvider(object): ret[name] += val return ret + def reset(self): + """Reset all field counters""" + for group in self.group_leaders: + for event in group.events: + event.reset() + class DebugfsProvider(object): """Provides data from the files that KVM creates in the kvm debugfs folder.""" def __init__(self): self._fields = self.get_available_fields() + self._baseline = {} self._pid = 0 self.do_read = True self.paths = [] + self.reset() def get_available_fields(self): """"Returns a list of available fields. @@ -741,6 +749,7 @@ class DebugfsProvider(object): @fields.setter def fields(self, fields): self._fields = fields + self.reset() @property def pid(self): @@ -758,10 +767,11 @@ class DebugfsProvider(object): self.paths = filter(lambda x: "{}-".format(pid) in x, vms) else: - self.paths = [''] + self.paths = [] self.do_read = True + self.reset() - def read(self): + def read(self, reset=0): """Returns a dict with format:'file name / field -> current value'.""" results = {} @@ -769,10 +779,22 @@ class DebugfsProvider(object): if not self.do_read: return results - for path in self.paths: + paths = self.paths + if self._pid == 0: + paths = [] + for entry in os.walk(PATH_DEBUGFS_KVM): + for dir in entry[1]: + paths.append(dir) + for path in paths: for field in self._fields: - results[field] = results.get(field, 0) \ - + self.read_field(field, path) + value = self.read_field(field, path) + key = path + field + if reset: + self._baseline[key] = value + if self._baseline.get(key, -1) == -1: + self._baseline[key] = value + results[field] = (results.get(field, 0) + value - + self._baseline.get(key, 0)) return results @@ -786,6 +808,11 @@ class DebugfsProvider(object): except IOError: return 0 + def reset(self): + """Reset field counters""" + self._baseline = {} + self.read(1) + class Stats(object): """Manages the data providers and the data they provide. @@ -822,14 +849,20 @@ class Stats(object): for provider in self.providers: provider.pid = self._pid_filter + def reset(self): + self.values = {} + for provider in self.providers: + provider.reset() + @property def fields_filter(self): return self._fields_filter @fields_filter.setter def fields_filter(self, fields_filter): - self._fields_filter = fields_filter - self.update_provider_filters() + if fields_filter != self._fields_filter: + self._fields_filter = fields_filter + self.update_provider_filters() @property def pid_filter(self): @@ -837,9 +870,10 @@ class Stats(object): @pid_filter.setter def pid_filter(self, pid): - self._pid_filter = pid - self.values = {} - self.update_provider_pid() + if pid != self._pid_filter: + self._pid_filter = pid + self.values = {} + self.update_provider_pid() def get(self): """Returns a dict with field -> (value, delta to last value) of all @@ -847,11 +881,9 @@ class Stats(object): for provider in self.providers: new = provider.read() for key in provider.fields: - oldval = self.values.get(key, (0, 0)) + oldval = self.values.get(key, (0, 0))[0] newval = new.get(key, 0) - newdelta = None - if oldval is not None: - newdelta = newval - oldval[0] + newdelta = newval - oldval self.values[key] = (newval, newdelta) return self.values @@ -1117,6 +1149,10 @@ class Tui(object): if char == 'p': self.show_vm_selection_by_pid() sleeptime = DELAY_INITIAL + if char == 'r': + self.refresh_header() + self.stats.reset() + sleeptime = DELAY_INITIAL except KeyboardInterrupt: break except curses.error: @@ -1190,6 +1226,7 @@ Interactive Commands: p filter by PID q quit x toggle reporting of stats for individual child trace events + r reset stats Press any other key to refresh statistics immediately. """ diff --git a/tools/kvm/kvm_stat/kvm_stat.txt b/tools/kvm/kvm_stat/kvm_stat.txt index c3ab6a2c8c37..109431bdc63c 100644 --- a/tools/kvm/kvm_stat/kvm_stat.txt +++ b/tools/kvm/kvm_stat/kvm_stat.txt @@ -39,6 +39,8 @@ INTERACTIVE COMMANDS *q*:: quit +*r*:: reset stats + *x*:: toggle reporting of stats for child trace events Press any other key to refresh statistics immediately. -- cgit v1.2.3 From e55fe3ccccc1efb8f20c99728c8863424ae9ee4a Mon Sep 17 00:00:00 2001 From: Stefan Raspl Date: Fri, 10 Mar 2017 13:40:16 +0100 Subject: tools/kvm_stat: add '%Total' column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add column '%Total' next to 'Total' for easier comparison of numbers between hosts. Signed-off-by: Stefan Raspl Marc Hartmayer Signed-off-by: Radim Krčmář --- tools/kvm/kvm_stat/kvm_stat | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/kvm/kvm_stat/kvm_stat b/tools/kvm/kvm_stat/kvm_stat index f8c48f8d07a7..8f74ed8e7237 100755 --- a/tools/kvm/kvm_stat/kvm_stat +++ b/tools/kvm/kvm_stat/kvm_stat @@ -973,7 +973,9 @@ class Tui(object): self.screen.addstr(2, 1, 'Event') self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH - len('Total'), 'Total') - self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 - + self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 - + len('%Total'), '%Total') + self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 7 + 8 - len('Current'), 'Current') self.screen.addstr(4, 1, 'Collecting data...') self.screen.refresh() @@ -989,6 +991,9 @@ class Tui(object): return (-stats[x][1], -stats[x][0]) else: return (0, -stats[x][0]) + total = 0. + for val in stats.values(): + total += val[0] for key in sorted(stats.keys(), key=sortkey): if row >= self.screen.getmaxyx()[0]: @@ -1001,6 +1006,8 @@ class Tui(object): col += LABEL_WIDTH self.screen.addstr(row, col, '%10d' % (values[0],)) col += NUMBER_WIDTH + self.screen.addstr(row, col, '%7.1f' % (values[0] * 100 / total,)) + col += 7 if values[1] is not None: self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,)) row += 1 -- cgit v1.2.3 From e000b8e0968dd7bfa09c444607ce1e48e57aafd3 Mon Sep 17 00:00:00 2001 From: "Jason J. Herne" Date: Mon, 20 Mar 2017 09:57:42 -0400 Subject: s390: kvm: Cpu model support for msa6, msa7 and msa8 msa6 and msa7 require no changes. msa8 adds kma instruction and feature area. Signed-off-by: Jason J. Herne Reviewed-by: Christian Borntraeger Signed-off-by: Christian Borntraeger --- tools/arch/s390/include/uapi/asm/kvm.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/arch/s390/include/uapi/asm/kvm.h b/tools/arch/s390/include/uapi/asm/kvm.h index a2ffec4139ad..7f4fd65e9208 100644 --- a/tools/arch/s390/include/uapi/asm/kvm.h +++ b/tools/arch/s390/include/uapi/asm/kvm.h @@ -131,7 +131,8 @@ struct kvm_s390_vm_cpu_subfunc { __u8 kmo[16]; /* with MSA4 */ __u8 pcc[16]; /* with MSA4 */ __u8 ppno[16]; /* with MSA5 */ - __u8 reserved[1824]; + __u8 kma[16]; /* with MSA8 */ + __u8 reserved[1808]; }; /* kvm attributes for crypto */ -- cgit v1.2.3 From ee5f7d79a80550179b258417442b7bdbccaf476a Mon Sep 17 00:00:00 2001 From: "Justin M. Forbes" Date: Tue, 11 Apr 2017 10:34:35 -0500 Subject: tools/kvm: fix top level makefile The top level tools/Makefile includes kvm_stat as a target in help, but the actual target is missing. Signed-off-by: Justin M. Forbes Signed-off-by: Paolo Bonzini --- tools/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/Makefile b/tools/Makefile index 00caacd3ed92..c8a90d01dd8e 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -86,10 +86,13 @@ tmon: FORCE freefall: FORCE $(call descend,laptop/$@) +kvm_stat: FORCE + $(call descend,kvm/$@) + all: acpi cgroup cpupower gpio hv firewire lguest \ perf selftests turbostat usb \ virtio vm net x86_energy_perf_policy \ - tmon freefall objtool + tmon freefall objtool kvm_stat acpi_install: $(call descend,power/$(@:_install=),install) -- cgit v1.2.3