blob: 769d884b6d94ccc6c69399b2ea3ed6c206c87887 [file] [log] [blame]
Janosch Frankf9bc9e62016-05-18 13:26:21 +02001#!/usr/bin/python
2#
3# top-like utility for displaying kvm statistics
4#
5# Copyright 2006-2008 Qumranet Technologies
6# Copyright 2008-2011 Red Hat, Inc.
7#
8# Authors:
9# Avi Kivity <avi@redhat.com>
10#
11# This work is licensed under the terms of the GNU GPL, version 2. See
12# the COPYING file in the top-level directory.
13
14import curses
15import sys
16import os
17import time
18import optparse
19import ctypes
20import fcntl
21import resource
22import struct
23import re
24from collections import defaultdict
25from time import sleep
26
27VMX_EXIT_REASONS = {
28 'EXCEPTION_NMI': 0,
29 'EXTERNAL_INTERRUPT': 1,
30 'TRIPLE_FAULT': 2,
31 'PENDING_INTERRUPT': 7,
32 'NMI_WINDOW': 8,
33 'TASK_SWITCH': 9,
34 'CPUID': 10,
35 'HLT': 12,
36 'INVLPG': 14,
37 'RDPMC': 15,
38 'RDTSC': 16,
39 'VMCALL': 18,
40 'VMCLEAR': 19,
41 'VMLAUNCH': 20,
42 'VMPTRLD': 21,
43 'VMPTRST': 22,
44 'VMREAD': 23,
45 'VMRESUME': 24,
46 'VMWRITE': 25,
47 'VMOFF': 26,
48 'VMON': 27,
49 'CR_ACCESS': 28,
50 'DR_ACCESS': 29,
51 'IO_INSTRUCTION': 30,
52 'MSR_READ': 31,
53 'MSR_WRITE': 32,
54 'INVALID_STATE': 33,
55 'MWAIT_INSTRUCTION': 36,
56 'MONITOR_INSTRUCTION': 39,
57 'PAUSE_INSTRUCTION': 40,
58 'MCE_DURING_VMENTRY': 41,
59 'TPR_BELOW_THRESHOLD': 43,
60 'APIC_ACCESS': 44,
61 'EPT_VIOLATION': 48,
62 'EPT_MISCONFIG': 49,
63 'WBINVD': 54,
64 'XSETBV': 55,
65 'APIC_WRITE': 56,
66 'INVPCID': 58,
67}
68
69SVM_EXIT_REASONS = {
70 'READ_CR0': 0x000,
71 'READ_CR3': 0x003,
72 'READ_CR4': 0x004,
73 'READ_CR8': 0x008,
74 'WRITE_CR0': 0x010,
75 'WRITE_CR3': 0x013,
76 'WRITE_CR4': 0x014,
77 'WRITE_CR8': 0x018,
78 'READ_DR0': 0x020,
79 'READ_DR1': 0x021,
80 'READ_DR2': 0x022,
81 'READ_DR3': 0x023,
82 'READ_DR4': 0x024,
83 'READ_DR5': 0x025,
84 'READ_DR6': 0x026,
85 'READ_DR7': 0x027,
86 'WRITE_DR0': 0x030,
87 'WRITE_DR1': 0x031,
88 'WRITE_DR2': 0x032,
89 'WRITE_DR3': 0x033,
90 'WRITE_DR4': 0x034,
91 'WRITE_DR5': 0x035,
92 'WRITE_DR6': 0x036,
93 'WRITE_DR7': 0x037,
94 'EXCP_BASE': 0x040,
95 'INTR': 0x060,
96 'NMI': 0x061,
97 'SMI': 0x062,
98 'INIT': 0x063,
99 'VINTR': 0x064,
100 'CR0_SEL_WRITE': 0x065,
101 'IDTR_READ': 0x066,
102 'GDTR_READ': 0x067,
103 'LDTR_READ': 0x068,
104 'TR_READ': 0x069,
105 'IDTR_WRITE': 0x06a,
106 'GDTR_WRITE': 0x06b,
107 'LDTR_WRITE': 0x06c,
108 'TR_WRITE': 0x06d,
109 'RDTSC': 0x06e,
110 'RDPMC': 0x06f,
111 'PUSHF': 0x070,
112 'POPF': 0x071,
113 'CPUID': 0x072,
114 'RSM': 0x073,
115 'IRET': 0x074,
116 'SWINT': 0x075,
117 'INVD': 0x076,
118 'PAUSE': 0x077,
119 'HLT': 0x078,
120 'INVLPG': 0x079,
121 'INVLPGA': 0x07a,
122 'IOIO': 0x07b,
123 'MSR': 0x07c,
124 'TASK_SWITCH': 0x07d,
125 'FERR_FREEZE': 0x07e,
126 'SHUTDOWN': 0x07f,
127 'VMRUN': 0x080,
128 'VMMCALL': 0x081,
129 'VMLOAD': 0x082,
130 'VMSAVE': 0x083,
131 'STGI': 0x084,
132 'CLGI': 0x085,
133 'SKINIT': 0x086,
134 'RDTSCP': 0x087,
135 'ICEBP': 0x088,
136 'WBINVD': 0x089,
137 'MONITOR': 0x08a,
138 'MWAIT': 0x08b,
139 'MWAIT_COND': 0x08c,
140 'XSETBV': 0x08d,
141 'NPF': 0x400,
142}
143
144# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h)
145AARCH64_EXIT_REASONS = {
146 'UNKNOWN': 0x00,
147 'WFI': 0x01,
148 'CP15_32': 0x03,
149 'CP15_64': 0x04,
150 'CP14_MR': 0x05,
151 'CP14_LS': 0x06,
152 'FP_ASIMD': 0x07,
153 'CP10_ID': 0x08,
154 'CP14_64': 0x0C,
155 'ILL_ISS': 0x0E,
156 'SVC32': 0x11,
157 'HVC32': 0x12,
158 'SMC32': 0x13,
159 'SVC64': 0x15,
160 'HVC64': 0x16,
161 'SMC64': 0x17,
162 'SYS64': 0x18,
163 'IABT': 0x20,
164 'IABT_HYP': 0x21,
165 'PC_ALIGN': 0x22,
166 'DABT': 0x24,
167 'DABT_HYP': 0x25,
168 'SP_ALIGN': 0x26,
169 'FP_EXC32': 0x28,
170 'FP_EXC64': 0x2C,
171 'SERROR': 0x2F,
172 'BREAKPT': 0x30,
173 'BREAKPT_HYP': 0x31,
174 'SOFTSTP': 0x32,
175 'SOFTSTP_HYP': 0x33,
176 'WATCHPT': 0x34,
177 'WATCHPT_HYP': 0x35,
178 'BKPT32': 0x38,
179 'VECTOR32': 0x3A,
180 'BRK64': 0x3C,
181}
182
183# From include/uapi/linux/kvm.h, KVM_EXIT_xxx
184USERSPACE_EXIT_REASONS = {
185 'UNKNOWN': 0,
186 'EXCEPTION': 1,
187 'IO': 2,
188 'HYPERCALL': 3,
189 'DEBUG': 4,
190 'HLT': 5,
191 'MMIO': 6,
192 'IRQ_WINDOW_OPEN': 7,
193 'SHUTDOWN': 8,
194 'FAIL_ENTRY': 9,
195 'INTR': 10,
196 'SET_TPR': 11,
197 'TPR_ACCESS': 12,
198 'S390_SIEIC': 13,
199 'S390_RESET': 14,
200 'DCR': 15,
201 'NMI': 16,
202 'INTERNAL_ERROR': 17,
203 'OSI': 18,
204 'PAPR_HCALL': 19,
205 'S390_UCONTROL': 20,
206 'WATCHDOG': 21,
207 'S390_TSCH': 22,
208 'EPR': 23,
209 'SYSTEM_EVENT': 24,
210}
211
212IOCTL_NUMBERS = {
213 'SET_FILTER': 0x40082406,
214 'ENABLE': 0x00002400,
215 'DISABLE': 0x00002401,
216 'RESET': 0x00002403,
217}
218
219class Arch(object):
220 """Class that encapsulates global architecture specific data like
221 syscall and ioctl numbers.
222
223 """
224 @staticmethod
225 def get_arch():
226 machine = os.uname()[4]
227
228 if machine.startswith('ppc'):
229 return ArchPPC()
230 elif machine.startswith('aarch64'):
231 return ArchA64()
232 elif machine.startswith('s390'):
233 return ArchS390()
234 else:
235 # X86_64
236 for line in open('/proc/cpuinfo'):
237 if not line.startswith('flags'):
238 continue
239
240 flags = line.split()
241 if 'vmx' in flags:
242 return ArchX86(VMX_EXIT_REASONS)
243 if 'svm' in flags:
244 return ArchX86(SVM_EXIT_REASONS)
245 return
246
247class ArchX86(Arch):
248 def __init__(self, exit_reasons):
249 self.sc_perf_evt_open = 298
250 self.ioctl_numbers = IOCTL_NUMBERS
251 self.exit_reasons = exit_reasons
252
253class ArchPPC(Arch):
254 def __init__(self):
255 self.sc_perf_evt_open = 319
256 self.ioctl_numbers = IOCTL_NUMBERS
257 self.ioctl_numbers['ENABLE'] = 0x20002400
258 self.ioctl_numbers['DISABLE'] = 0x20002401
259
260 # PPC comes in 32 and 64 bit and some generated ioctl
261 # numbers depend on the wordsize.
262 char_ptr_size = ctypes.sizeof(ctypes.c_char_p)
263 self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16
264
265class ArchA64(Arch):
266 def __init__(self):
267 self.sc_perf_evt_open = 241
268 self.ioctl_numbers = IOCTL_NUMBERS
269 self.exit_reasons = AARCH64_EXIT_REASONS
270
271class ArchS390(Arch):
272 def __init__(self):
273 self.sc_perf_evt_open = 331
274 self.ioctl_numbers = IOCTL_NUMBERS
275 self.exit_reasons = None
276
277ARCH = Arch.get_arch()
278
279
280def walkdir(path):
281 """Returns os.walk() data for specified directory.
282
283 As it is only a wrapper it returns the same 3-tuple of (dirpath,
284 dirnames, filenames).
285 """
286 return next(os.walk(path))
287
288
289def parse_int_list(list_string):
290 """Returns an int list from a string of comma separated integers and
291 integer ranges."""
292 integers = []
293 members = list_string.split(',')
294
295 for member in members:
296 if '-' not in member:
297 integers.append(int(member))
298 else:
299 int_range = member.split('-')
300 integers.extend(range(int(int_range[0]),
301 int(int_range[1]) + 1))
302
303 return integers
304
305
306def get_online_cpus():
307 with open('/sys/devices/system/cpu/online') as cpu_list:
308 cpu_string = cpu_list.readline()
309 return parse_int_list(cpu_string)
310
311
312def get_filters():
313 filters = {}
314 filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS)
315 if ARCH.exit_reasons:
316 filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons)
317 return filters
318
319libc = ctypes.CDLL('libc.so.6', use_errno=True)
320syscall = libc.syscall
321
322class perf_event_attr(ctypes.Structure):
323 _fields_ = [('type', ctypes.c_uint32),
324 ('size', ctypes.c_uint32),
325 ('config', ctypes.c_uint64),
326 ('sample_freq', ctypes.c_uint64),
327 ('sample_type', ctypes.c_uint64),
328 ('read_format', ctypes.c_uint64),
329 ('flags', ctypes.c_uint64),
330 ('wakeup_events', ctypes.c_uint32),
331 ('bp_type', ctypes.c_uint32),
332 ('bp_addr', ctypes.c_uint64),
333 ('bp_len', ctypes.c_uint64),
334 ]
335
336 def __init__(self):
337 super(self.__class__, self).__init__()
338 self.type = PERF_TYPE_TRACEPOINT
339 self.size = ctypes.sizeof(self)
340 self.read_format = PERF_FORMAT_GROUP
341
342def perf_event_open(attr, pid, cpu, group_fd, flags):
343 return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr),
344 ctypes.c_int(pid), ctypes.c_int(cpu),
345 ctypes.c_int(group_fd), ctypes.c_long(flags))
346
347PERF_TYPE_TRACEPOINT = 2
348PERF_FORMAT_GROUP = 1 << 3
349
350PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing'
351PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm'
352
353class Group(object):
354 def __init__(self):
355 self.events = []
356
357 def add_event(self, event):
358 self.events.append(event)
359
360 def read(self):
361 length = 8 * (1 + len(self.events))
362 read_format = 'xxxxxxxx' + 'Q' * len(self.events)
363 return dict(zip([event.name for event in self.events],
364 struct.unpack(read_format,
365 os.read(self.events[0].fd, length))))
366
367class Event(object):
368 def __init__(self, name, group, trace_cpu, trace_point, trace_filter,
369 trace_set='kvm'):
370 self.name = name
371 self.fd = None
372 self.setup_event(group, trace_cpu, trace_point, trace_filter,
373 trace_set)
374
375 def setup_event_attribute(self, trace_set, trace_point):
376 id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set,
377 trace_point, 'id')
378
379 event_attr = perf_event_attr()
380 event_attr.config = int(open(id_path).read())
381 return event_attr
382
383 def setup_event(self, group, trace_cpu, trace_point, trace_filter,
384 trace_set):
385 event_attr = self.setup_event_attribute(trace_set, trace_point)
386
387 group_leader = -1
388 if group.events:
389 group_leader = group.events[0].fd
390
391 fd = perf_event_open(event_attr, -1, trace_cpu,
392 group_leader, 0)
393 if fd == -1:
394 err = ctypes.get_errno()
395 raise OSError(err, os.strerror(err),
396 'while calling sys_perf_event_open().')
397
398 if trace_filter:
399 fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'],
400 trace_filter)
401
402 self.fd = fd
403
404 def enable(self):
405 fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0)
406
407 def disable(self):
408 fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0)
409
410 def reset(self):
411 fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0)
412
413class TracepointProvider(object):
414 def __init__(self):
415 self.group_leaders = []
416 self.filters = get_filters()
417 self._fields = self.get_available_fields()
418 self.setup_traces()
419 self.fields = self._fields
420
421 def get_available_fields(self):
422 path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm')
423 fields = walkdir(path)[1]
424 extra = []
425 for field in fields:
426 if field in self.filters:
427 filter_name_, filter_dicts = self.filters[field]
428 for name in filter_dicts:
429 extra.append(field + '(' + name + ')')
430 fields += extra
431 return fields
432
433 def setup_traces(self):
434 cpus = get_online_cpus()
435
436 # The constant is needed as a buffer for python libs, std
437 # streams and other files that the script opens.
438 newlim = len(cpus) * len(self._fields) + 50
439 try:
440 softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE)
441
442 if hardlim < newlim:
443 # Now we need CAP_SYS_RESOURCE, to increase the hard limit.
444 resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim))
445 else:
446 # Raising the soft limit is sufficient.
447 resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim))
448
449 except ValueError:
450 sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim))
451
452 for cpu in cpus:
453 group = Group()
454 for name in self._fields:
455 tracepoint = name
456 tracefilter = None
457 match = re.match(r'(.*)\((.*)\)', name)
458 if match:
459 tracepoint, sub = match.groups()
460 tracefilter = ('%s==%d\0' %
461 (self.filters[tracepoint][0],
462 self.filters[tracepoint][1][sub]))
463
464 group.add_event(Event(name=name,
465 group=group,
466 trace_cpu=cpu,
467 trace_point=tracepoint,
468 trace_filter=tracefilter))
469 self.group_leaders.append(group)
470
471 def available_fields(self):
472 return self.get_available_fields()
473
474 @property
475 def fields(self):
476 return self._fields
477
478 @fields.setter
479 def fields(self, fields):
480 self._fields = fields
481 for group in self.group_leaders:
482 for index, event in enumerate(group.events):
483 if event.name in fields:
484 event.reset()
485 event.enable()
486 else:
487 # Do not disable the group leader.
488 # It would disable all of its events.
489 if index != 0:
490 event.disable()
491
492 def read(self):
493 ret = defaultdict(int)
494 for group in self.group_leaders:
495 for name, val in group.read().iteritems():
496 if name in self._fields:
497 ret[name] += val
498 return ret
499
500class DebugfsProvider(object):
501 def __init__(self):
502 self._fields = self.get_available_fields()
503
504 def get_available_fields(self):
505 return walkdir(PATH_DEBUGFS_KVM)[2]
506
507 @property
508 def fields(self):
509 return self._fields
510
511 @fields.setter
512 def fields(self, fields):
513 self._fields = fields
514
515 def read(self):
516 def val(key):
517 return int(file(PATH_DEBUGFS_KVM + '/' + key).read())
518 return dict([(key, val(key)) for key in self._fields])
519
520class Stats(object):
521 def __init__(self, providers, fields=None):
522 self.providers = providers
523 self._fields_filter = fields
524 self.values = {}
525 self.update_provider_filters()
526
527 def update_provider_filters(self):
528 def wanted(key):
529 if not self._fields_filter:
530 return True
531 return re.match(self._fields_filter, key) is not None
532
533 # As we reset the counters when updating the fields we can
534 # also clear the cache of old values.
535 self.values = {}
536 for provider in self.providers:
537 provider_fields = [key for key in provider.get_available_fields()
538 if wanted(key)]
539 provider.fields = provider_fields
540
541 @property
542 def fields_filter(self):
543 return self._fields_filter
544
545 @fields_filter.setter
546 def fields_filter(self, fields_filter):
547 self._fields_filter = fields_filter
548 self.update_provider_filters()
549
550 def get(self):
551 for provider in self.providers:
552 new = provider.read()
553 for key in provider.fields:
554 oldval = self.values.get(key, (0, 0))
555 newval = new.get(key, 0)
556 newdelta = None
557 if oldval is not None:
558 newdelta = newval - oldval[0]
559 self.values[key] = (newval, newdelta)
560 return self.values
561
562LABEL_WIDTH = 40
563NUMBER_WIDTH = 10
564
565class Tui(object):
566 def __init__(self, stats):
567 self.stats = stats
568 self.screen = None
569 self.drilldown = False
570 self.update_drilldown()
571
572 def __enter__(self):
573 """Initialises curses for later use. Based on curses.wrapper
574 implementation from the Python standard library."""
575 self.screen = curses.initscr()
576 curses.noecho()
577 curses.cbreak()
578
579 # The try/catch works around a minor bit of
580 # over-conscientiousness in the curses module, the error
581 # return from C start_color() is ignorable.
582 try:
583 curses.start_color()
584 except:
585 pass
586
587 curses.use_default_colors()
588 return self
589
590 def __exit__(self, *exception):
591 """Resets the terminal to its normal state. Based on curses.wrappre
592 implementation from the Python standard library."""
593 if self.screen:
594 self.screen.keypad(0)
595 curses.echo()
596 curses.nocbreak()
597 curses.endwin()
598
599 def update_drilldown(self):
600 if not self.stats.fields_filter:
601 self.stats.fields_filter = r'^[^\(]*$'
602
603 elif self.stats.fields_filter == r'^[^\(]*$':
604 self.stats.fields_filter = None
605
606 def refresh(self, sleeptime):
607 self.screen.erase()
608 self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD)
609 self.screen.addstr(2, 1, 'Event')
610 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH -
611 len('Total'), 'Total')
612 self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 -
613 len('Current'), 'Current')
614 row = 3
615 stats = self.stats.get()
616 def sortkey(x):
617 if stats[x][1]:
618 return (-stats[x][1], -stats[x][0])
619 else:
620 return (0, -stats[x][0])
621 for key in sorted(stats.keys(), key=sortkey):
622
623 if row >= self.screen.getmaxyx()[0]:
624 break
625 values = stats[key]
626 if not values[0] and not values[1]:
627 break
628 col = 1
629 self.screen.addstr(row, col, key)
630 col += LABEL_WIDTH
631 self.screen.addstr(row, col, '%10d' % (values[0],))
632 col += NUMBER_WIDTH
633 if values[1] is not None:
634 self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
635 row += 1
636 self.screen.refresh()
637
638 def show_filter_selection(self):
639 while True:
640 self.screen.erase()
641 self.screen.addstr(0, 0,
642 "Show statistics for events matching a regex.",
643 curses.A_BOLD)
644 self.screen.addstr(2, 0,
645 "Current regex: {0}"
646 .format(self.stats.fields_filter))
647 self.screen.addstr(3, 0, "New regex: ")
648 curses.echo()
649 regex = self.screen.getstr()
650 curses.noecho()
651 if len(regex) == 0:
652 return
653 try:
654 re.compile(regex)
655 self.stats.fields_filter = regex
656 return
657 except re.error:
658 continue
659
660 def show_stats(self):
661 sleeptime = 0.25
662 while True:
663 self.refresh(sleeptime)
664 curses.halfdelay(int(sleeptime * 10))
665 sleeptime = 3
666 try:
667 char = self.screen.getkey()
668 if char == 'x':
669 self.drilldown = not self.drilldown
670 self.update_drilldown()
671 if char == 'q':
672 break
673 if char == 'f':
674 self.show_filter_selection()
675 except KeyboardInterrupt:
676 break
677 except curses.error:
678 continue
679
680def batch(stats):
681 s = stats.get()
682 time.sleep(1)
683 s = stats.get()
684 for key in sorted(s.keys()):
685 values = s[key]
686 print '%-42s%10d%10d' % (key, values[0], values[1])
687
688def log(stats):
689 keys = sorted(stats.get().iterkeys())
690 def banner():
691 for k in keys:
692 print '%s' % k,
693 print
694 def statline():
695 s = stats.get()
696 for k in keys:
697 print ' %9d' % s[k][1],
698 print
699 line = 0
700 banner_repeat = 20
701 while True:
702 time.sleep(1)
703 if line % banner_repeat == 0:
704 banner()
705 statline()
706 line += 1
707
708def get_options():
709 description_text = """
710This script displays various statistics about VMs running under KVM.
711The statistics are gathered from the KVM debugfs entries and / or the
712currently available perf traces.
713
714The monitoring takes additional cpu cycles and might affect the VM's
715performance.
716
717Requirements:
718- Access to:
719 /sys/kernel/debug/kvm
720 /sys/kernel/debug/trace/events/*
721 /proc/pid/task
722- /proc/sys/kernel/perf_event_paranoid < 1 if user has no
723 CAP_SYS_ADMIN and perf events are used.
724- CAP_SYS_RESOURCE if the hard limit is not high enough to allow
725 the large number of files that are possibly opened.
726"""
727
728 class PlainHelpFormatter(optparse.IndentedHelpFormatter):
729 def format_description(self, description):
730 if description:
731 return description + "\n"
732 else:
733 return ""
734
735 optparser = optparse.OptionParser(description=description_text,
736 formatter=PlainHelpFormatter())
737 optparser.add_option('-1', '--once', '--batch',
738 action='store_true',
739 default=False,
740 dest='once',
741 help='run in batch mode for one second',
742 )
743 optparser.add_option('-l', '--log',
744 action='store_true',
745 default=False,
746 dest='log',
747 help='run in logging mode (like vmstat)',
748 )
749 optparser.add_option('-t', '--tracepoints',
750 action='store_true',
751 default=False,
752 dest='tracepoints',
753 help='retrieve statistics from tracepoints',
754 )
755 optparser.add_option('-d', '--debugfs',
756 action='store_true',
757 default=False,
758 dest='debugfs',
759 help='retrieve statistics from debugfs',
760 )
761 optparser.add_option('-f', '--fields',
762 action='store',
763 default=None,
764 dest='fields',
765 help='fields to display (regex)',
766 )
767 (options, _) = optparser.parse_args(sys.argv)
768 return options
769
770def get_providers(options):
771 providers = []
772
773 if options.tracepoints:
774 providers.append(TracepointProvider())
775 if options.debugfs:
776 providers.append(DebugfsProvider())
777 if len(providers) == 0:
778 providers.append(TracepointProvider())
779
780 return providers
781
782def check_access(options):
783 if not os.path.exists('/sys/kernel/debug'):
784 sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.')
785 sys.exit(1)
786
787 if not os.path.exists(PATH_DEBUGFS_KVM):
788 sys.stderr.write("Please make sure, that debugfs is mounted and "
789 "readable by the current user:\n"
790 "('mount -t debugfs debugfs /sys/kernel/debug')\n"
791 "Also ensure, that the kvm modules are loaded.\n")
792 sys.exit(1)
793
794 if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints
795 or not options.debugfs):
796 sys.stderr.write("Please enable CONFIG_TRACING in your kernel "
797 "when using the option -t (default).\n"
798 "If it is enabled, make {0} readable by the "
799 "current user.\n"
800 .format(PATH_DEBUGFS_TRACING))
801 if options.tracepoints:
802 sys.exit(1)
803
804 sys.stderr.write("Falling back to debugfs statistics!\n")
805 options.debugfs = True
806 sleep(5)
807
808 return options
809
810def main():
811 options = get_options()
812 options = check_access(options)
813 providers = get_providers(options)
814 stats = Stats(providers, fields=options.fields)
815
816 if options.log:
817 log(stats)
818 elif not options.once:
819 with Tui(stats) as tui:
820 tui.show_stats()
821 else:
822 batch(stats)
823
824if __name__ == "__main__":
825 main()