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