]>
git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - tools/kvm/kvm_stat/kvm_stat
f2a868b696a8cd9898c210db09337392083ff0c7
3 # top-like utility for displaying kvm statistics
5 # Copyright 2006-2008 Qumranet Technologies
6 # Copyright 2008-2011 Red Hat, Inc.
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.
13 """The kvm_stat module outputs statistics about running KVM VMs
15 Three different ways of output formatting are available:
16 - as a top-like text ui
17 - in a key -> value format
18 - in an all keys, all values format
20 The data is sampled from the KVM's debugfs entries and its perf events.
33 from collections
import defaultdict
37 'EXTERNAL_INTERRUPT': 1,
39 'PENDING_INTERRUPT': 7,
63 'MWAIT_INSTRUCTION': 36,
64 'MONITOR_INSTRUCTION': 39,
65 'PAUSE_INSTRUCTION': 40,
66 'MCE_DURING_VMENTRY': 41,
67 'TPR_BELOW_THRESHOLD': 43,
108 'CR0_SEL_WRITE': 0x065,
132 'TASK_SWITCH': 0x07d,
133 'FERR_FREEZE': 0x07e,
152 # EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h)
153 AARCH64_EXIT_REASONS
= {
191 # From include/uapi/linux/kvm.h, KVM_EXIT_xxx
192 USERSPACE_EXIT_REASONS
= {
200 'IRQ_WINDOW_OPEN': 7,
210 'INTERNAL_ERROR': 17,
221 'SET_FILTER': 0x40082406,
222 'ENABLE': 0x00002400,
223 'DISABLE': 0x00002401,
229 """Encapsulates global architecture specific data.
231 Contains the performance event open syscall and ioctl numbers, as
232 well as the VM exit reasons for the architecture it runs on.
237 machine
= os
.uname()[4]
239 if machine
.startswith('ppc'):
241 elif machine
.startswith('aarch64'):
243 elif machine
.startswith('s390'):
247 for line
in open('/proc/cpuinfo'):
248 if not line
.startswith('flags'):
253 return ArchX86(VMX_EXIT_REASONS
)
255 return ArchX86(SVM_EXIT_REASONS
)
260 def __init__(self
, exit_reasons
):
261 self
.sc_perf_evt_open
= 298
262 self
.ioctl_numbers
= IOCTL_NUMBERS
263 self
.exit_reasons
= exit_reasons
268 self
.sc_perf_evt_open
= 319
269 self
.ioctl_numbers
= IOCTL_NUMBERS
270 self
.ioctl_numbers
['ENABLE'] = 0x20002400
271 self
.ioctl_numbers
['DISABLE'] = 0x20002401
272 self
.ioctl_numbers
['RESET'] = 0x20002403
274 # PPC comes in 32 and 64 bit and some generated ioctl
275 # numbers depend on the wordsize.
276 char_ptr_size
= ctypes
.sizeof(ctypes
.c_char_p
)
277 self
.ioctl_numbers
['SET_FILTER'] = 0x80002406 | char_ptr_size
<< 16
278 self
.exit_reasons
= {}
283 self
.sc_perf_evt_open
= 241
284 self
.ioctl_numbers
= IOCTL_NUMBERS
285 self
.exit_reasons
= AARCH64_EXIT_REASONS
288 class ArchS390(Arch
):
290 self
.sc_perf_evt_open
= 331
291 self
.ioctl_numbers
= IOCTL_NUMBERS
292 self
.exit_reasons
= None
294 ARCH
= Arch
.get_arch()
298 """Returns os.walk() data for specified directory.
300 As it is only a wrapper it returns the same 3-tuple of (dirpath,
301 dirnames, filenames).
303 return next(os
.walk(path
))
306 def parse_int_list(list_string
):
307 """Returns an int list from a string of comma separated integers and
310 members
= list_string
.split(',')
312 for member
in members
:
313 if '-' not in member
:
314 integers
.append(int(member
))
316 int_range
= member
.split('-')
317 integers
.extend(range(int(int_range
[0]),
318 int(int_range
[1]) + 1))
323 def get_gname_from_pid(pid
):
324 """Returns the guest name for a QEMU process pid.
326 Extracts the guest name from the QEMU comma line by processing the '-name'
327 option. Will also handle names specified out of sequence.
332 line
= open('/proc/{}/cmdline'.format(pid
), 'rb').read().split('\0')
333 parms
= line
[line
.index('-name') + 1].split(',')
335 # commas are escaped (i.e. ',,'), hence e.g. 'foo,bar' results in
336 # ['foo', '', 'bar'], which we revert here
337 idx
= parms
.index('')
338 parms
[idx
- 1] += ',' + parms
[idx
+ 1]
340 # the '-name' switch allows for two ways to specify the guest name,
341 # where the plain name overrides the name specified via 'guest='
346 if arg
[:6] == 'guest=':
348 except (ValueError, IOError, IndexError):
354 def get_online_cpus():
355 """Returns a list of cpu id integers."""
356 with
open('/sys/devices/system/cpu/online') as cpu_list
:
357 cpu_string
= cpu_list
.readline()
358 return parse_int_list(cpu_string
)
362 """Returns a dict of trace events, their filter ids and
363 the values that can be filtered.
365 Trace events can be filtered for special values by setting a
366 filter string via an ioctl. The string normally has the format
367 identifier==value. For each filter a new event will be created, to
368 be able to distinguish the events.
372 filters
['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS
)
373 if ARCH
.exit_reasons
:
374 filters
['kvm_exit'] = ('exit_reason', ARCH
.exit_reasons
)
377 libc
= ctypes
.CDLL('libc.so.6', use_errno
=True)
378 syscall
= libc
.syscall
381 class perf_event_attr(ctypes
.Structure
):
382 """Struct that holds the necessary data to set up a trace event.
384 For an extensive explanation see perf_event_open(2) and
385 include/uapi/linux/perf_event.h, struct perf_event_attr
387 All fields that are not initialized in the constructor are 0.
390 _fields_
= [('type', ctypes
.c_uint32
),
391 ('size', ctypes
.c_uint32
),
392 ('config', ctypes
.c_uint64
),
393 ('sample_freq', ctypes
.c_uint64
),
394 ('sample_type', ctypes
.c_uint64
),
395 ('read_format', ctypes
.c_uint64
),
396 ('flags', ctypes
.c_uint64
),
397 ('wakeup_events', ctypes
.c_uint32
),
398 ('bp_type', ctypes
.c_uint32
),
399 ('bp_addr', ctypes
.c_uint64
),
400 ('bp_len', ctypes
.c_uint64
),
404 super(self
.__class
__, self
).__init
__()
405 self
.type = PERF_TYPE_TRACEPOINT
406 self
.size
= ctypes
.sizeof(self
)
407 self
.read_format
= PERF_FORMAT_GROUP
410 def perf_event_open(attr
, pid
, cpu
, group_fd
, flags
):
411 """Wrapper for the sys_perf_evt_open() syscall.
413 Used to set up performance events, returns a file descriptor or -1
418 - struct perf_event_attr *
419 - pid or -1 to monitor all pids
420 - cpu number or -1 to monitor all cpus
421 - The file descriptor of the group leader or -1 to create a group.
425 return syscall(ARCH
.sc_perf_evt_open
, ctypes
.pointer(attr
),
426 ctypes
.c_int(pid
), ctypes
.c_int(cpu
),
427 ctypes
.c_int(group_fd
), ctypes
.c_long(flags
))
429 PERF_TYPE_TRACEPOINT
= 2
430 PERF_FORMAT_GROUP
= 1 << 3
432 PATH_DEBUGFS_TRACING
= '/sys/kernel/debug/tracing'
433 PATH_DEBUGFS_KVM
= '/sys/kernel/debug/kvm'
437 """Represents a perf event group."""
442 def add_event(self
, event
):
443 self
.events
.append(event
)
446 """Returns a dict with 'event name: value' for all events in the
449 Values are read by reading from the file descriptor of the
450 event that is the group leader. See perf_event_open(2) for
453 Read format for the used event configuration is:
455 u64 nr; /* The number of events */
457 u64 value; /* The value of the event */
462 length
= 8 * (1 + len(self
.events
))
463 read_format
= 'xxxxxxxx' + 'Q' * len(self
.events
)
464 return dict(zip([event
.name
for event
in self
.events
],
465 struct
.unpack(read_format
,
466 os
.read(self
.events
[0].fd
, length
))))
470 """Represents a performance event and manages its life cycle."""
471 def __init__(self
, name
, group
, trace_cpu
, trace_pid
, trace_point
,
472 trace_filter
, trace_set
='kvm'):
475 self
.setup_event(group
, trace_cpu
, trace_pid
, trace_point
,
476 trace_filter
, trace_set
)
479 """Closes the event's file descriptor.
481 As no python file object was created for the file descriptor,
482 python will not reference count the descriptor and will not
483 close it itself automatically, so we do it.
489 def setup_event_attribute(self
, trace_set
, trace_point
):
490 """Returns an initialized ctype perf_event_attr struct."""
492 id_path
= os
.path
.join(PATH_DEBUGFS_TRACING
, 'events', trace_set
,
495 event_attr
= perf_event_attr()
496 event_attr
.config
= int(open(id_path
).read())
499 def setup_event(self
, group
, trace_cpu
, trace_pid
, trace_point
,
500 trace_filter
, trace_set
):
501 """Sets up the perf event in Linux.
503 Issues the syscall to register the event in the kernel and
504 then sets the optional filter.
508 event_attr
= self
.setup_event_attribute(trace_set
, trace_point
)
510 # First event will be group leader.
513 # All others have to pass the leader's descriptor instead.
515 group_leader
= group
.events
[0].fd
517 fd
= perf_event_open(event_attr
, trace_pid
,
518 trace_cpu
, group_leader
, 0)
520 err
= ctypes
.get_errno()
521 raise OSError(err
, os
.strerror(err
),
522 'while calling sys_perf_event_open().')
525 fcntl
.ioctl(fd
, ARCH
.ioctl_numbers
['SET_FILTER'],
531 """Enables the trace event in the kernel.
533 Enabling the group leader makes reading counters from it and the
534 events under it possible.
537 fcntl
.ioctl(self
.fd
, ARCH
.ioctl_numbers
['ENABLE'], 0)
540 """Disables the trace event in the kernel.
542 Disabling the group leader makes reading all counters under it
546 fcntl
.ioctl(self
.fd
, ARCH
.ioctl_numbers
['DISABLE'], 0)
549 """Resets the count of the trace event in the kernel."""
550 fcntl
.ioctl(self
.fd
, ARCH
.ioctl_numbers
['RESET'], 0)
553 class TracepointProvider(object):
554 """Data provider for the stats class.
556 Manages the events/groups from which it acquires its data.
560 self
.group_leaders
= []
561 self
.filters
= get_filters()
562 self
._fields
= self
.get_available_fields()
565 def get_available_fields(self
):
566 """Returns a list of available event's of format 'event name(filter
569 All available events have directories under
570 /sys/kernel/debug/tracing/events/ which export information
571 about the specific event. Therefore, listing the dirs gives us
572 a list of all available events.
574 Some events like the vm exit reasons can be filtered for
575 specific values. To take account for that, the routine below
576 creates special fields with the following format:
577 event name(filter name)
580 path
= os
.path
.join(PATH_DEBUGFS_TRACING
, 'events', 'kvm')
581 fields
= walkdir(path
)[1]
584 if field
in self
.filters
:
585 filter_name_
, filter_dicts
= self
.filters
[field
]
586 for name
in filter_dicts
:
587 extra
.append(field
+ '(' + name
+ ')')
591 def setup_traces(self
):
592 """Creates all event and group objects needed to be able to retrieve
594 fields
= self
.get_available_fields()
596 # Fetch list of all threads of the monitored pid, as qemu
597 # starts a thread for each vcpu.
598 path
= os
.path
.join('/proc', str(self
._pid
), 'task')
599 groupids
= walkdir(path
)[1]
601 groupids
= get_online_cpus()
603 # The constant is needed as a buffer for python libs, std
604 # streams and other files that the script opens.
605 newlim
= len(groupids
) * len(fields
) + 50
607 softlim_
, hardlim
= resource
.getrlimit(resource
.RLIMIT_NOFILE
)
610 # Now we need CAP_SYS_RESOURCE, to increase the hard limit.
611 resource
.setrlimit(resource
.RLIMIT_NOFILE
, (newlim
, newlim
))
613 # Raising the soft limit is sufficient.
614 resource
.setrlimit(resource
.RLIMIT_NOFILE
, (newlim
, hardlim
))
617 sys
.exit("NOFILE rlimit could not be raised to {0}".format(newlim
))
619 for groupid
in groupids
:
624 match
= re
.match(r
'(.*)\((.*)\)', name
)
626 tracepoint
, sub
= match
.groups()
627 tracefilter
= ('%s==%d\0' %
628 (self
.filters
[tracepoint
][0],
629 self
.filters
[tracepoint
][1][sub
]))
631 # From perf_event_open(2):
632 # pid > 0 and cpu == -1
633 # This measures the specified process/thread on any CPU.
635 # pid == -1 and cpu >= 0
636 # This measures all processes/threads on the specified CPU.
637 trace_cpu
= groupid
if self
._pid
== 0 else -1
638 trace_pid
= int(groupid
) if self
._pid
!= 0 else -1
640 group
.add_event(Event(name
=name
,
644 trace_point
=tracepoint
,
645 trace_filter
=tracefilter
))
647 self
.group_leaders
.append(group
)
649 def available_fields(self
):
650 return self
.get_available_fields()
657 def fields(self
, fields
):
658 """Enables/disables the (un)wanted events"""
659 self
._fields
= fields
660 for group
in self
.group_leaders
:
661 for index
, event
in enumerate(group
.events
):
662 if event
.name
in fields
:
666 # Do not disable the group leader.
667 # It would disable all of its events.
677 """Changes the monitored pid by setting new traces."""
679 # The garbage collector will get rid of all Event/Group
680 # objects and open files after removing the references.
681 self
.group_leaders
= []
683 self
.fields
= self
._fields
686 """Returns 'event name: current value' for all enabled events."""
687 ret
= defaultdict(int)
688 for group
in self
.group_leaders
:
689 for name
, val
in group
.read().iteritems():
690 if name
in self
._fields
:
695 class DebugfsProvider(object):
696 """Provides data from the files that KVM creates in the kvm debugfs
699 self
._fields
= self
.get_available_fields()
704 def get_available_fields(self
):
705 """"Returns a list of available fields.
707 The fields are all available KVM debugfs files
710 return walkdir(PATH_DEBUGFS_KVM
)[2]
717 def fields(self
, fields
):
718 self
._fields
= fields
729 vms
= walkdir(PATH_DEBUGFS_KVM
)[1]
733 self
.paths
= filter(lambda x
: "{}-".format(pid
) in x
, vms
)
740 """Returns a dict with format:'file name / field -> current value'."""
743 # If no debugfs filtering support is available, then don't read.
747 for path
in self
.paths
:
748 for field
in self
._fields
:
749 results
[field
] = results
.get(field
, 0) \
750 + self
.read_field(field
, path
)
754 def read_field(self
, field
, path
):
755 """Returns the value of a single field from a specific VM."""
757 return int(open(os
.path
.join(PATH_DEBUGFS_KVM
,
766 """Manages the data providers and the data they provide.
768 It is used to set filters on the provider's data and collect all
772 def __init__(self
, providers
, pid
, fields
=None):
773 self
.providers
= providers
774 self
._pid
_filter
= pid
775 self
._fields
_filter
= fields
777 self
.update_provider_pid()
778 self
.update_provider_filters()
780 def update_provider_filters(self
):
781 """Propagates fields filters to providers."""
783 if not self
._fields
_filter
:
785 return re
.match(self
._fields
_filter
, key
) is not None
787 # As we reset the counters when updating the fields we can
788 # also clear the cache of old values.
790 for provider
in self
.providers
:
791 provider_fields
= [key
for key
in provider
.get_available_fields()
793 provider
.fields
= provider_fields
795 def update_provider_pid(self
):
796 """Propagates pid filters to providers."""
797 for provider
in self
.providers
:
798 provider
.pid
= self
._pid
_filter
801 def fields_filter(self
):
802 return self
._fields
_filter
804 @fields_filter.setter
805 def fields_filter(self
, fields_filter
):
806 self
._fields
_filter
= fields_filter
807 self
.update_provider_filters()
810 def pid_filter(self
):
811 return self
._pid
_filter
814 def pid_filter(self
, pid
):
815 self
._pid
_filter
= pid
817 self
.update_provider_pid()
820 """Returns a dict with field -> (value, delta to last value) of all
822 for provider
in self
.providers
:
823 new
= provider
.read()
824 for key
in provider
.fields
:
825 oldval
= self
.values
.get(key
, (0, 0))
826 newval
= new
.get(key
, 0)
828 if oldval
is not None:
829 newdelta
= newval
- oldval
[0]
830 self
.values
[key
] = (newval
, newdelta
)
837 MAX_GUEST_NAME_LEN
= 48
842 """Instruments curses to draw a nice text ui."""
843 def __init__(self
, stats
):
846 self
.update_drilldown()
849 """Initialises curses for later use. Based on curses.wrapper
850 implementation from the Python standard library."""
851 self
.screen
= curses
.initscr()
855 # The try/catch works around a minor bit of
856 # over-conscientiousness in the curses module, the error
857 # return from C start_color() is ignorable.
863 # Hide cursor in extra statement as some monochrome terminals
864 # might support hiding but not colors.
870 curses
.use_default_colors()
873 def __exit__(self
, *exception
):
874 """Resets the terminal to its normal state. Based on curses.wrappre
875 implementation from the Python standard library."""
877 self
.screen
.keypad(0)
882 def update_drilldown(self
):
883 """Sets or removes a filter that only allows fields without braces."""
884 if not self
.stats
.fields_filter
:
885 self
.stats
.fields_filter
= r
'^[^\(]*$'
887 elif self
.stats
.fields_filter
== r
'^[^\(]*$':
888 self
.stats
.fields_filter
= None
890 def update_pid(self
, pid
):
891 """Propagates pid selection to stats object."""
892 self
.stats
.pid_filter
= pid
894 def refresh_header(self
, pid
=None):
895 """Refreshes the header."""
897 pid
= self
.stats
.pid_filter
899 gname
= get_gname_from_pid(pid
)
901 gname
= ('({})'.format(gname
[:MAX_GUEST_NAME_LEN
] + '...'
902 if len(gname
) > MAX_GUEST_NAME_LEN
905 self
.screen
.addstr(0, 0, 'kvm statistics - pid {0} {1}'
906 .format(pid
, gname
), curses
.A_BOLD
)
908 self
.screen
.addstr(0, 0, 'kvm statistics - summary', curses
.A_BOLD
)
909 if self
.stats
.fields_filter
and self
.stats
.fields_filter
!= '^[^\(]*$':
910 regex
= self
.stats
.fields_filter
911 if len(regex
) > MAX_REGEX_LEN
:
912 regex
= regex
[:MAX_REGEX_LEN
] + '...'
913 self
.screen
.addstr(1, 17, 'regex filter: {0}'.format(regex
))
914 self
.screen
.addstr(2, 1, 'Event')
915 self
.screen
.addstr(2, 1 + LABEL_WIDTH
+ NUMBER_WIDTH
-
916 len('Total'), 'Total')
917 self
.screen
.addstr(2, 1 + LABEL_WIDTH
+ NUMBER_WIDTH
+ 8 -
918 len('Current'), 'Current')
919 self
.screen
.addstr(4, 1, 'Collecting data...')
920 self
.screen
.refresh()
922 def refresh_body(self
, sleeptime
):
924 self
.screen
.move(row
, 0)
925 self
.screen
.clrtobot()
926 stats
= self
.stats
.get()
930 return (-stats
[x
][1], -stats
[x
][0])
932 return (0, -stats
[x
][0])
933 for key
in sorted(stats
.keys(), key
=sortkey
):
935 if row
>= self
.screen
.getmaxyx()[0]:
938 if not values
[0] and not values
[1]:
941 self
.screen
.addstr(row
, col
, key
)
943 self
.screen
.addstr(row
, col
, '%10d' % (values
[0],))
945 if values
[1] is not None:
946 self
.screen
.addstr(row
, col
, '%8d' % (values
[1] / sleeptime
,))
948 self
.screen
.refresh()
950 def show_filter_selection(self
):
951 """Draws filter selection mask.
953 Asks for a valid regex and sets the fields filter accordingly.
958 self
.screen
.addstr(0, 0,
959 "Show statistics for events matching a regex.",
961 self
.screen
.addstr(2, 0,
963 .format(self
.stats
.fields_filter
))
964 self
.screen
.addstr(3, 0, "New regex: ")
966 regex
= self
.screen
.getstr()
969 self
.stats
.fields_filter
= r
'^[^\(]*$'
970 self
.refresh_header()
974 self
.stats
.fields_filter
= regex
975 self
.refresh_header()
980 def show_vm_selection(self
):
981 """Draws PID selection mask.
983 Asks for a pid until a valid pid or 0 has been entered.
989 self
.screen
.addstr(0, 0,
990 'Show statistics for specific pid.',
992 self
.screen
.addstr(1, 0,
993 'This might limit the shown data to the trace '
995 self
.screen
.addstr(5, 0, msg
)
998 self
.screen
.addstr(3, 0, "Pid [0 or pid]: ")
999 pid
= self
.screen
.getstr()
1005 if pid
!= 0 and not os
.path
.isdir(os
.path
.join('/proc/',
1007 msg
= '"' + str(pid
) + '": Not a running process'
1011 self
.refresh_header(pid
)
1012 self
.update_pid(pid
)
1016 msg
= '"' + str(pid
) + '": Not a valid pid'
1019 def show_stats(self
):
1020 """Refreshes the screen and processes user input."""
1021 sleeptime
= DELAY_INITIAL
1022 self
.refresh_header()
1024 self
.refresh_body(sleeptime
)
1025 curses
.halfdelay(int(sleeptime
* 10))
1026 sleeptime
= DELAY_REGULAR
1028 char
= self
.screen
.getkey()
1030 self
.refresh_header()
1031 self
.update_drilldown()
1032 sleeptime
= DELAY_INITIAL
1036 self
.show_filter_selection()
1037 sleeptime
= DELAY_INITIAL
1039 self
.show_vm_selection()
1040 sleeptime
= DELAY_INITIAL
1041 except KeyboardInterrupt:
1043 except curses
.error
:
1048 """Prints statistics in a key, value format."""
1053 for key
in sorted(s
.keys()):
1055 print '%-42s%10d%10d' % (key
, values
[0], values
[1])
1056 except KeyboardInterrupt:
1061 """Prints statistics as reiterating key block, multiple value blocks."""
1062 keys
= sorted(stats
.get().iterkeys())
1072 print ' %9d' % s
[k
][1],
1079 if line
% banner_repeat
== 0:
1083 except KeyboardInterrupt:
1088 """Returns processed program arguments."""
1089 description_text
= """
1090 This script displays various statistics about VMs running under KVM.
1091 The statistics are gathered from the KVM debugfs entries and / or the
1092 currently available perf traces.
1094 The monitoring takes additional cpu cycles and might affect the VM's
1099 /sys/kernel/debug/kvm
1100 /sys/kernel/debug/trace/events/*
1102 - /proc/sys/kernel/perf_event_paranoid < 1 if user has no
1103 CAP_SYS_ADMIN and perf events are used.
1104 - CAP_SYS_RESOURCE if the hard limit is not high enough to allow
1105 the large number of files that are possibly opened.
1107 Interactive Commands:
1108 f filter by regular expression
1111 x toggle reporting of stats for individual child trace events
1112 Press any other key to refresh statistics immediately.
1115 class PlainHelpFormatter(optparse
.IndentedHelpFormatter
):
1116 def format_description(self
, description
):
1118 return description
+ "\n"
1122 optparser
= optparse
.OptionParser(description
=description_text
,
1123 formatter
=PlainHelpFormatter())
1124 optparser
.add_option('-1', '--once', '--batch',
1125 action
='store_true',
1128 help='run in batch mode for one second',
1130 optparser
.add_option('-l', '--log',
1131 action
='store_true',
1134 help='run in logging mode (like vmstat)',
1136 optparser
.add_option('-t', '--tracepoints',
1137 action
='store_true',
1140 help='retrieve statistics from tracepoints',
1142 optparser
.add_option('-d', '--debugfs',
1143 action
='store_true',
1146 help='retrieve statistics from debugfs',
1148 optparser
.add_option('-f', '--fields',
1152 help='fields to display (regex)',
1154 optparser
.add_option('-p', '--pid',
1159 help='restrict statistics to pid',
1161 (options
, _
) = optparser
.parse_args(sys
.argv
)
1165 def get_providers(options
):
1166 """Returns a list of data providers depending on the passed options."""
1169 if options
.tracepoints
:
1170 providers
.append(TracepointProvider())
1172 providers
.append(DebugfsProvider())
1173 if len(providers
) == 0:
1174 providers
.append(TracepointProvider())
1179 def check_access(options
):
1180 """Exits if the current user can't access all needed directories."""
1181 if not os
.path
.exists('/sys/kernel/debug'):
1182 sys
.stderr
.write('Please enable CONFIG_DEBUG_FS in your kernel.')
1185 if not os
.path
.exists(PATH_DEBUGFS_KVM
):
1186 sys
.stderr
.write("Please make sure, that debugfs is mounted and "
1187 "readable by the current user:\n"
1188 "('mount -t debugfs debugfs /sys/kernel/debug')\n"
1189 "Also ensure, that the kvm modules are loaded.\n")
1192 if not os
.path
.exists(PATH_DEBUGFS_TRACING
) and (options
.tracepoints
or
1193 not options
.debugfs
):
1194 sys
.stderr
.write("Please enable CONFIG_TRACING in your kernel "
1195 "when using the option -t (default).\n"
1196 "If it is enabled, make {0} readable by the "
1198 .format(PATH_DEBUGFS_TRACING
))
1199 if options
.tracepoints
:
1202 sys
.stderr
.write("Falling back to debugfs statistics!\n")
1203 options
.debugfs
= True
1210 options
= get_options()
1211 options
= check_access(options
)
1213 if (options
.pid
> 0 and
1214 not os
.path
.isdir(os
.path
.join('/proc/',
1215 str(options
.pid
)))):
1216 sys
.stderr
.write('Did you use a (unsupported) tid instead of a pid?\n')
1217 sys
.exit('Specified pid does not exist.')
1219 providers
= get_providers(options
)
1220 stats
= Stats(providers
, options
.pid
, fields
=options
.fields
)
1224 elif not options
.once
:
1225 with
Tui(stats
) as tui
:
1230 if __name__
== "__main__":