These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / scripts / kvm / kvm_stat
1 #!/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
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
25 from time import sleep
26
27 VMX_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
69 SVM_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)
145 AARCH64_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
184 USERSPACE_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
212 IOCTL_NUMBERS = {
213     'SET_FILTER':  0x40082406,
214     'ENABLE':      0x00002400,
215     'DISABLE':     0x00002401,
216     'RESET':       0x00002403,
217 }
218
219 class 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
247 class 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
253 class 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
265 class 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
271 class 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
277 ARCH = Arch.get_arch()
278
279
280 def 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
289 def 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
306 def 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
312 def 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
319 libc = ctypes.CDLL('libc.so.6', use_errno=True)
320 syscall = libc.syscall
321
322 class 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
342 def 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
347 PERF_TYPE_TRACEPOINT = 2
348 PERF_FORMAT_GROUP = 1 << 3
349
350 PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing'
351 PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm'
352
353 class 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
367 class 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
413 class 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
500 class 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
520 class 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
562 LABEL_WIDTH = 40
563 NUMBER_WIDTH = 10
564
565 class 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
680 def 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
688 def 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
708 def get_options():
709     description_text = """
710 This script displays various statistics about VMs running under KVM.
711 The statistics are gathered from the KVM debugfs entries and / or the
712 currently available perf traces.
713
714 The monitoring takes additional cpu cycles and might affect the VM's
715 performance.
716
717 Requirements:
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
770 def 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
782 def 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
810 def 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
824 if __name__ == "__main__":
825     main()