]> git.karo-electronics.de Git - linux-beck.git/blob - tools/kvm/kvm_stat/kvm_stat
tools: kvm_stat: Powerpc related fixes
[linux-beck.git] / tools / kvm / kvm_stat / 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         self.ioctl_numbers['RESET'] = 0x20002403
260
261         # PPC comes in 32 and 64 bit and some generated ioctl
262         # numbers depend on the wordsize.
263         char_ptr_size = ctypes.sizeof(ctypes.c_char_p)
264         self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16
265         self.exit_reasons = {}
266
267 class ArchA64(Arch):
268     def __init__(self):
269         self.sc_perf_evt_open = 241
270         self.ioctl_numbers = IOCTL_NUMBERS
271         self.exit_reasons = AARCH64_EXIT_REASONS
272
273 class ArchS390(Arch):
274     def __init__(self):
275         self.sc_perf_evt_open = 331
276         self.ioctl_numbers = IOCTL_NUMBERS
277         self.exit_reasons = None
278
279 ARCH = Arch.get_arch()
280
281
282 def walkdir(path):
283     """Returns os.walk() data for specified directory.
284
285     As it is only a wrapper it returns the same 3-tuple of (dirpath,
286     dirnames, filenames).
287     """
288     return next(os.walk(path))
289
290
291 def parse_int_list(list_string):
292     """Returns an int list from a string of comma separated integers and
293     integer ranges."""
294     integers = []
295     members = list_string.split(',')
296
297     for member in members:
298         if '-' not in member:
299             integers.append(int(member))
300         else:
301             int_range = member.split('-')
302             integers.extend(range(int(int_range[0]),
303                                   int(int_range[1]) + 1))
304
305     return integers
306
307
308 def get_online_cpus():
309     with open('/sys/devices/system/cpu/online') as cpu_list:
310         cpu_string = cpu_list.readline()
311         return parse_int_list(cpu_string)
312
313
314 def get_filters():
315     filters = {}
316     filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS)
317     if ARCH.exit_reasons:
318         filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons)
319     return filters
320
321 libc = ctypes.CDLL('libc.so.6', use_errno=True)
322 syscall = libc.syscall
323
324 class perf_event_attr(ctypes.Structure):
325     _fields_ = [('type', ctypes.c_uint32),
326                 ('size', ctypes.c_uint32),
327                 ('config', ctypes.c_uint64),
328                 ('sample_freq', ctypes.c_uint64),
329                 ('sample_type', ctypes.c_uint64),
330                 ('read_format', ctypes.c_uint64),
331                 ('flags', ctypes.c_uint64),
332                 ('wakeup_events', ctypes.c_uint32),
333                 ('bp_type', ctypes.c_uint32),
334                 ('bp_addr', ctypes.c_uint64),
335                 ('bp_len', ctypes.c_uint64),
336                 ]
337
338     def __init__(self):
339         super(self.__class__, self).__init__()
340         self.type = PERF_TYPE_TRACEPOINT
341         self.size = ctypes.sizeof(self)
342         self.read_format = PERF_FORMAT_GROUP
343
344 def perf_event_open(attr, pid, cpu, group_fd, flags):
345     return syscall(ARCH.sc_perf_evt_open, ctypes.pointer(attr),
346                    ctypes.c_int(pid), ctypes.c_int(cpu),
347                    ctypes.c_int(group_fd), ctypes.c_long(flags))
348
349 PERF_TYPE_TRACEPOINT = 2
350 PERF_FORMAT_GROUP = 1 << 3
351
352 PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing'
353 PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm'
354
355 class Group(object):
356     def __init__(self):
357         self.events = []
358
359     def add_event(self, event):
360         self.events.append(event)
361
362     def read(self):
363         length = 8 * (1 + len(self.events))
364         read_format = 'xxxxxxxx' + 'Q' * len(self.events)
365         return dict(zip([event.name for event in self.events],
366                         struct.unpack(read_format,
367                                       os.read(self.events[0].fd, length))))
368
369 class Event(object):
370     def __init__(self, name, group, trace_cpu, trace_point, trace_filter,
371                  trace_set='kvm'):
372         self.name = name
373         self.fd = None
374         self.setup_event(group, trace_cpu, trace_point, trace_filter,
375                          trace_set)
376
377     def setup_event_attribute(self, trace_set, trace_point):
378         id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set,
379                                trace_point, 'id')
380
381         event_attr = perf_event_attr()
382         event_attr.config = int(open(id_path).read())
383         return event_attr
384
385     def setup_event(self, group, trace_cpu, trace_point, trace_filter,
386                     trace_set):
387         event_attr = self.setup_event_attribute(trace_set, trace_point)
388
389         group_leader = -1
390         if group.events:
391             group_leader = group.events[0].fd
392
393         fd = perf_event_open(event_attr, -1, trace_cpu,
394                              group_leader, 0)
395         if fd == -1:
396             err = ctypes.get_errno()
397             raise OSError(err, os.strerror(err),
398                           'while calling sys_perf_event_open().')
399
400         if trace_filter:
401             fcntl.ioctl(fd, ARCH.ioctl_numbers['SET_FILTER'],
402                         trace_filter)
403
404         self.fd = fd
405
406     def enable(self):
407         fcntl.ioctl(self.fd, ARCH.ioctl_numbers['ENABLE'], 0)
408
409     def disable(self):
410         fcntl.ioctl(self.fd, ARCH.ioctl_numbers['DISABLE'], 0)
411
412     def reset(self):
413         fcntl.ioctl(self.fd, ARCH.ioctl_numbers['RESET'], 0)
414
415 class TracepointProvider(object):
416     def __init__(self):
417         self.group_leaders = []
418         self.filters = get_filters()
419         self._fields = self.get_available_fields()
420         self.setup_traces()
421         self.fields = self._fields
422
423     def get_available_fields(self):
424         path = os.path.join(PATH_DEBUGFS_TRACING, 'events', 'kvm')
425         fields = walkdir(path)[1]
426         extra = []
427         for field in fields:
428             if field in self.filters:
429                 filter_name_, filter_dicts = self.filters[field]
430                 for name in filter_dicts:
431                     extra.append(field + '(' + name + ')')
432         fields += extra
433         return fields
434
435     def setup_traces(self):
436         cpus = get_online_cpus()
437
438         # The constant is needed as a buffer for python libs, std
439         # streams and other files that the script opens.
440         newlim = len(cpus) * len(self._fields) + 50
441         try:
442             softlim_, hardlim = resource.getrlimit(resource.RLIMIT_NOFILE)
443
444             if hardlim < newlim:
445                 # Now we need CAP_SYS_RESOURCE, to increase the hard limit.
446                 resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, newlim))
447             else:
448                 # Raising the soft limit is sufficient.
449                 resource.setrlimit(resource.RLIMIT_NOFILE, (newlim, hardlim))
450
451         except ValueError:
452             sys.exit("NOFILE rlimit could not be raised to {0}".format(newlim))
453
454         for cpu in cpus:
455             group = Group()
456             for name in self._fields:
457                 tracepoint = name
458                 tracefilter = None
459                 match = re.match(r'(.*)\((.*)\)', name)
460                 if match:
461                     tracepoint, sub = match.groups()
462                     tracefilter = ('%s==%d\0' %
463                                    (self.filters[tracepoint][0],
464                                     self.filters[tracepoint][1][sub]))
465
466                 group.add_event(Event(name=name,
467                                       group=group,
468                                       trace_cpu=cpu,
469                                       trace_point=tracepoint,
470                                       trace_filter=tracefilter))
471             self.group_leaders.append(group)
472
473     def available_fields(self):
474         return self.get_available_fields()
475
476     @property
477     def fields(self):
478         return self._fields
479
480     @fields.setter
481     def fields(self, fields):
482         self._fields = fields
483         for group in self.group_leaders:
484             for index, event in enumerate(group.events):
485                 if event.name in fields:
486                     event.reset()
487                     event.enable()
488                 else:
489                     # Do not disable the group leader.
490                     # It would disable all of its events.
491                     if index != 0:
492                         event.disable()
493
494     def read(self):
495         ret = defaultdict(int)
496         for group in self.group_leaders:
497             for name, val in group.read().iteritems():
498                 if name in self._fields:
499                     ret[name] += val
500         return ret
501
502 class DebugfsProvider(object):
503     def __init__(self):
504         self._fields = self.get_available_fields()
505
506     def get_available_fields(self):
507         return walkdir(PATH_DEBUGFS_KVM)[2]
508
509     @property
510     def fields(self):
511         return self._fields
512
513     @fields.setter
514     def fields(self, fields):
515         self._fields = fields
516
517     def read(self):
518         def val(key):
519             return int(file(PATH_DEBUGFS_KVM + '/' + key).read())
520         return dict([(key, val(key)) for key in self._fields])
521
522 class Stats(object):
523     def __init__(self, providers, fields=None):
524         self.providers = providers
525         self._fields_filter = fields
526         self.values = {}
527         self.update_provider_filters()
528
529     def update_provider_filters(self):
530         def wanted(key):
531             if not self._fields_filter:
532                 return True
533             return re.match(self._fields_filter, key) is not None
534
535         # As we reset the counters when updating the fields we can
536         # also clear the cache of old values.
537         self.values = {}
538         for provider in self.providers:
539             provider_fields = [key for key in provider.get_available_fields()
540                                if wanted(key)]
541             provider.fields = provider_fields
542
543     @property
544     def fields_filter(self):
545         return self._fields_filter
546
547     @fields_filter.setter
548     def fields_filter(self, fields_filter):
549         self._fields_filter = fields_filter
550         self.update_provider_filters()
551
552     def get(self):
553         for provider in self.providers:
554             new = provider.read()
555             for key in provider.fields:
556                 oldval = self.values.get(key, (0, 0))
557                 newval = new.get(key, 0)
558                 newdelta = None
559                 if oldval is not None:
560                     newdelta = newval - oldval[0]
561                 self.values[key] = (newval, newdelta)
562         return self.values
563
564 LABEL_WIDTH = 40
565 NUMBER_WIDTH = 10
566
567 class Tui(object):
568     def __init__(self, stats):
569         self.stats = stats
570         self.screen = None
571         self.drilldown = False
572         self.update_drilldown()
573
574     def __enter__(self):
575         """Initialises curses for later use.  Based on curses.wrapper
576            implementation from the Python standard library."""
577         self.screen = curses.initscr()
578         curses.noecho()
579         curses.cbreak()
580
581         # The try/catch works around a minor bit of
582         # over-conscientiousness in the curses module, the error
583         # return from C start_color() is ignorable.
584         try:
585             curses.start_color()
586         except:
587             pass
588
589         curses.use_default_colors()
590         return self
591
592     def __exit__(self, *exception):
593         """Resets the terminal to its normal state.  Based on curses.wrappre
594            implementation from the Python standard library."""
595         if self.screen:
596             self.screen.keypad(0)
597             curses.echo()
598             curses.nocbreak()
599             curses.endwin()
600
601     def update_drilldown(self):
602         if not self.stats.fields_filter:
603             self.stats.fields_filter = r'^[^\(]*$'
604
605         elif self.stats.fields_filter == r'^[^\(]*$':
606             self.stats.fields_filter = None
607
608     def refresh(self, sleeptime):
609         self.screen.erase()
610         self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD)
611         self.screen.addstr(2, 1, 'Event')
612         self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH -
613                            len('Total'), 'Total')
614         self.screen.addstr(2, 1 + LABEL_WIDTH + NUMBER_WIDTH + 8 -
615                            len('Current'), 'Current')
616         row = 3
617         stats = self.stats.get()
618         def sortkey(x):
619             if stats[x][1]:
620                 return (-stats[x][1], -stats[x][0])
621             else:
622                 return (0, -stats[x][0])
623         for key in sorted(stats.keys(), key=sortkey):
624
625             if row >= self.screen.getmaxyx()[0]:
626                 break
627             values = stats[key]
628             if not values[0] and not values[1]:
629                 break
630             col = 1
631             self.screen.addstr(row, col, key)
632             col += LABEL_WIDTH
633             self.screen.addstr(row, col, '%10d' % (values[0],))
634             col += NUMBER_WIDTH
635             if values[1] is not None:
636                 self.screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
637             row += 1
638         self.screen.refresh()
639
640     def show_filter_selection(self):
641         while True:
642             self.screen.erase()
643             self.screen.addstr(0, 0,
644                                "Show statistics for events matching a regex.",
645                                curses.A_BOLD)
646             self.screen.addstr(2, 0,
647                                "Current regex: {0}"
648                                .format(self.stats.fields_filter))
649             self.screen.addstr(3, 0, "New regex: ")
650             curses.echo()
651             regex = self.screen.getstr()
652             curses.noecho()
653             if len(regex) == 0:
654                 return
655             try:
656                 re.compile(regex)
657                 self.stats.fields_filter = regex
658                 return
659             except re.error:
660                 continue
661
662     def show_stats(self):
663         sleeptime = 0.25
664         while True:
665             self.refresh(sleeptime)
666             curses.halfdelay(int(sleeptime * 10))
667             sleeptime = 3
668             try:
669                 char = self.screen.getkey()
670                 if char == 'x':
671                     self.drilldown = not self.drilldown
672                     self.update_drilldown()
673                 if char == 'q':
674                     break
675                 if char == 'f':
676                     self.show_filter_selection()
677             except KeyboardInterrupt:
678                 break
679             except curses.error:
680                 continue
681
682 def batch(stats):
683     s = stats.get()
684     time.sleep(1)
685     s = stats.get()
686     for key in sorted(s.keys()):
687         values = s[key]
688         print '%-42s%10d%10d' % (key, values[0], values[1])
689
690 def log(stats):
691     keys = sorted(stats.get().iterkeys())
692     def banner():
693         for k in keys:
694             print '%s' % k,
695         print
696     def statline():
697         s = stats.get()
698         for k in keys:
699             print ' %9d' % s[k][1],
700         print
701     line = 0
702     banner_repeat = 20
703     while True:
704         time.sleep(1)
705         if line % banner_repeat == 0:
706             banner()
707         statline()
708         line += 1
709
710 def get_options():
711     description_text = """
712 This script displays various statistics about VMs running under KVM.
713 The statistics are gathered from the KVM debugfs entries and / or the
714 currently available perf traces.
715
716 The monitoring takes additional cpu cycles and might affect the VM's
717 performance.
718
719 Requirements:
720 - Access to:
721     /sys/kernel/debug/kvm
722     /sys/kernel/debug/trace/events/*
723     /proc/pid/task
724 - /proc/sys/kernel/perf_event_paranoid < 1 if user has no
725   CAP_SYS_ADMIN and perf events are used.
726 - CAP_SYS_RESOURCE if the hard limit is not high enough to allow
727   the large number of files that are possibly opened.
728 """
729
730     class PlainHelpFormatter(optparse.IndentedHelpFormatter):
731         def format_description(self, description):
732             if description:
733                 return description + "\n"
734             else:
735                 return ""
736
737     optparser = optparse.OptionParser(description=description_text,
738                                       formatter=PlainHelpFormatter())
739     optparser.add_option('-1', '--once', '--batch',
740                          action='store_true',
741                          default=False,
742                          dest='once',
743                          help='run in batch mode for one second',
744                          )
745     optparser.add_option('-l', '--log',
746                          action='store_true',
747                          default=False,
748                          dest='log',
749                          help='run in logging mode (like vmstat)',
750                          )
751     optparser.add_option('-t', '--tracepoints',
752                          action='store_true',
753                          default=False,
754                          dest='tracepoints',
755                          help='retrieve statistics from tracepoints',
756                          )
757     optparser.add_option('-d', '--debugfs',
758                          action='store_true',
759                          default=False,
760                          dest='debugfs',
761                          help='retrieve statistics from debugfs',
762                          )
763     optparser.add_option('-f', '--fields',
764                          action='store',
765                          default=None,
766                          dest='fields',
767                          help='fields to display (regex)',
768                          )
769     (options, _) = optparser.parse_args(sys.argv)
770     return options
771
772 def get_providers(options):
773     providers = []
774
775     if options.tracepoints:
776         providers.append(TracepointProvider())
777     if options.debugfs:
778         providers.append(DebugfsProvider())
779     if len(providers) == 0:
780         providers.append(TracepointProvider())
781
782     return providers
783
784 def check_access(options):
785     if not os.path.exists('/sys/kernel/debug'):
786         sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.')
787         sys.exit(1)
788
789     if not os.path.exists(PATH_DEBUGFS_KVM):
790         sys.stderr.write("Please make sure, that debugfs is mounted and "
791                          "readable by the current user:\n"
792                          "('mount -t debugfs debugfs /sys/kernel/debug')\n"
793                          "Also ensure, that the kvm modules are loaded.\n")
794         sys.exit(1)
795
796     if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints
797                                                      or not options.debugfs):
798         sys.stderr.write("Please enable CONFIG_TRACING in your kernel "
799                          "when using the option -t (default).\n"
800                          "If it is enabled, make {0} readable by the "
801                          "current user.\n"
802                          .format(PATH_DEBUGFS_TRACING))
803         if options.tracepoints:
804             sys.exit(1)
805
806         sys.stderr.write("Falling back to debugfs statistics!\n")
807         options.debugfs = True
808         sleep(5)
809
810     return options
811
812 def main():
813     options = get_options()
814     options = check_access(options)
815     providers = get_providers(options)
816     stats = Stats(providers, fields=options.fields)
817
818     if options.log:
819         log(stats)
820     elif not options.once:
821         with Tui(stats) as tui:
822             tui.show_stats()
823     else:
824         batch(stats)
825
826 if __name__ == "__main__":
827     main()