Statistics
| Branch: | Revision:

root / scripts / kvm / kvm_stat @ 1b3e6f88

History | View | Annotate | Download (14.5 kB)

1 626c4276 Jan Kiszka
#!/usr/bin/python
2 626c4276 Jan Kiszka
#
3 626c4276 Jan Kiszka
# top-like utility for displaying kvm statistics
4 626c4276 Jan Kiszka
#
5 626c4276 Jan Kiszka
# Copyright 2006-2008 Qumranet Technologies
6 626c4276 Jan Kiszka
# Copyright 2008-2011 Red Hat, Inc.
7 626c4276 Jan Kiszka
#
8 626c4276 Jan Kiszka
# Authors:
9 626c4276 Jan Kiszka
#  Avi Kivity <avi@redhat.com>
10 626c4276 Jan Kiszka
#
11 626c4276 Jan Kiszka
# This work is licensed under the terms of the GNU GPL, version 2.  See
12 626c4276 Jan Kiszka
# the COPYING file in the top-level directory.
13 626c4276 Jan Kiszka
14 626c4276 Jan Kiszka
import curses
15 626c4276 Jan Kiszka
import sys, os, time, optparse
16 626c4276 Jan Kiszka
17 626c4276 Jan Kiszka
class DebugfsProvider(object):
18 626c4276 Jan Kiszka
    def __init__(self):
19 626c4276 Jan Kiszka
        self.base = '/sys/kernel/debug/kvm'
20 626c4276 Jan Kiszka
        self._fields = os.listdir(self.base)
21 626c4276 Jan Kiszka
    def fields(self):
22 626c4276 Jan Kiszka
        return self._fields
23 626c4276 Jan Kiszka
    def select(self, fields):
24 626c4276 Jan Kiszka
        self._fields = fields
25 626c4276 Jan Kiszka
    def read(self):
26 626c4276 Jan Kiszka
        def val(key):
27 626c4276 Jan Kiszka
            return int(file(self.base + '/' + key).read())
28 626c4276 Jan Kiszka
        return dict([(key, val(key)) for key in self._fields])
29 626c4276 Jan Kiszka
30 626c4276 Jan Kiszka
vmx_exit_reasons = {
31 626c4276 Jan Kiszka
    0: 'EXCEPTION_NMI',
32 626c4276 Jan Kiszka
    1: 'EXTERNAL_INTERRUPT',
33 626c4276 Jan Kiszka
    2: 'TRIPLE_FAULT',
34 626c4276 Jan Kiszka
    7: 'PENDING_INTERRUPT',
35 626c4276 Jan Kiszka
    8: 'NMI_WINDOW',
36 626c4276 Jan Kiszka
    9: 'TASK_SWITCH',
37 626c4276 Jan Kiszka
    10: 'CPUID',
38 626c4276 Jan Kiszka
    12: 'HLT',
39 626c4276 Jan Kiszka
    14: 'INVLPG',
40 626c4276 Jan Kiszka
    15: 'RDPMC',
41 626c4276 Jan Kiszka
    16: 'RDTSC',
42 626c4276 Jan Kiszka
    18: 'VMCALL',
43 626c4276 Jan Kiszka
    19: 'VMCLEAR',
44 626c4276 Jan Kiszka
    20: 'VMLAUNCH',
45 626c4276 Jan Kiszka
    21: 'VMPTRLD',
46 626c4276 Jan Kiszka
    22: 'VMPTRST',
47 626c4276 Jan Kiszka
    23: 'VMREAD',
48 626c4276 Jan Kiszka
    24: 'VMRESUME',
49 626c4276 Jan Kiszka
    25: 'VMWRITE',
50 626c4276 Jan Kiszka
    26: 'VMOFF',
51 626c4276 Jan Kiszka
    27: 'VMON',
52 626c4276 Jan Kiszka
    28: 'CR_ACCESS',
53 626c4276 Jan Kiszka
    29: 'DR_ACCESS',
54 626c4276 Jan Kiszka
    30: 'IO_INSTRUCTION',
55 626c4276 Jan Kiszka
    31: 'MSR_READ',
56 626c4276 Jan Kiszka
    32: 'MSR_WRITE',
57 626c4276 Jan Kiszka
    33: 'INVALID_STATE',
58 626c4276 Jan Kiszka
    36: 'MWAIT_INSTRUCTION',
59 626c4276 Jan Kiszka
    39: 'MONITOR_INSTRUCTION',
60 626c4276 Jan Kiszka
    40: 'PAUSE_INSTRUCTION',
61 626c4276 Jan Kiszka
    41: 'MCE_DURING_VMENTRY',
62 626c4276 Jan Kiszka
    43: 'TPR_BELOW_THRESHOLD',
63 626c4276 Jan Kiszka
    44: 'APIC_ACCESS',
64 626c4276 Jan Kiszka
    48: 'EPT_VIOLATION',
65 626c4276 Jan Kiszka
    49: 'EPT_MISCONFIG',
66 626c4276 Jan Kiszka
    54: 'WBINVD',
67 626c4276 Jan Kiszka
    55: 'XSETBV',
68 626c4276 Jan Kiszka
}
69 626c4276 Jan Kiszka
70 626c4276 Jan Kiszka
svm_exit_reasons = {
71 626c4276 Jan Kiszka
    0x000: 'READ_CR0',
72 626c4276 Jan Kiszka
    0x003: 'READ_CR3',
73 626c4276 Jan Kiszka
    0x004: 'READ_CR4',
74 626c4276 Jan Kiszka
    0x008: 'READ_CR8',
75 626c4276 Jan Kiszka
    0x010: 'WRITE_CR0',
76 626c4276 Jan Kiszka
    0x013: 'WRITE_CR3',
77 626c4276 Jan Kiszka
    0x014: 'WRITE_CR4',
78 626c4276 Jan Kiszka
    0x018: 'WRITE_CR8',
79 626c4276 Jan Kiszka
    0x020: 'READ_DR0',
80 626c4276 Jan Kiszka
    0x021: 'READ_DR1',
81 626c4276 Jan Kiszka
    0x022: 'READ_DR2',
82 626c4276 Jan Kiszka
    0x023: 'READ_DR3',
83 626c4276 Jan Kiszka
    0x024: 'READ_DR4',
84 626c4276 Jan Kiszka
    0x025: 'READ_DR5',
85 626c4276 Jan Kiszka
    0x026: 'READ_DR6',
86 626c4276 Jan Kiszka
    0x027: 'READ_DR7',
87 626c4276 Jan Kiszka
    0x030: 'WRITE_DR0',
88 626c4276 Jan Kiszka
    0x031: 'WRITE_DR1',
89 626c4276 Jan Kiszka
    0x032: 'WRITE_DR2',
90 626c4276 Jan Kiszka
    0x033: 'WRITE_DR3',
91 626c4276 Jan Kiszka
    0x034: 'WRITE_DR4',
92 626c4276 Jan Kiszka
    0x035: 'WRITE_DR5',
93 626c4276 Jan Kiszka
    0x036: 'WRITE_DR6',
94 626c4276 Jan Kiszka
    0x037: 'WRITE_DR7',
95 626c4276 Jan Kiszka
    0x040: 'EXCP_BASE',
96 626c4276 Jan Kiszka
    0x060: 'INTR',
97 626c4276 Jan Kiszka
    0x061: 'NMI',
98 626c4276 Jan Kiszka
    0x062: 'SMI',
99 626c4276 Jan Kiszka
    0x063: 'INIT',
100 626c4276 Jan Kiszka
    0x064: 'VINTR',
101 626c4276 Jan Kiszka
    0x065: 'CR0_SEL_WRITE',
102 626c4276 Jan Kiszka
    0x066: 'IDTR_READ',
103 626c4276 Jan Kiszka
    0x067: 'GDTR_READ',
104 626c4276 Jan Kiszka
    0x068: 'LDTR_READ',
105 626c4276 Jan Kiszka
    0x069: 'TR_READ',
106 626c4276 Jan Kiszka
    0x06a: 'IDTR_WRITE',
107 626c4276 Jan Kiszka
    0x06b: 'GDTR_WRITE',
108 626c4276 Jan Kiszka
    0x06c: 'LDTR_WRITE',
109 626c4276 Jan Kiszka
    0x06d: 'TR_WRITE',
110 626c4276 Jan Kiszka
    0x06e: 'RDTSC',
111 626c4276 Jan Kiszka
    0x06f: 'RDPMC',
112 626c4276 Jan Kiszka
    0x070: 'PUSHF',
113 626c4276 Jan Kiszka
    0x071: 'POPF',
114 626c4276 Jan Kiszka
    0x072: 'CPUID',
115 626c4276 Jan Kiszka
    0x073: 'RSM',
116 626c4276 Jan Kiszka
    0x074: 'IRET',
117 626c4276 Jan Kiszka
    0x075: 'SWINT',
118 626c4276 Jan Kiszka
    0x076: 'INVD',
119 626c4276 Jan Kiszka
    0x077: 'PAUSE',
120 626c4276 Jan Kiszka
    0x078: 'HLT',
121 626c4276 Jan Kiszka
    0x079: 'INVLPG',
122 626c4276 Jan Kiszka
    0x07a: 'INVLPGA',
123 626c4276 Jan Kiszka
    0x07b: 'IOIO',
124 626c4276 Jan Kiszka
    0x07c: 'MSR',
125 626c4276 Jan Kiszka
    0x07d: 'TASK_SWITCH',
126 626c4276 Jan Kiszka
    0x07e: 'FERR_FREEZE',
127 626c4276 Jan Kiszka
    0x07f: 'SHUTDOWN',
128 626c4276 Jan Kiszka
    0x080: 'VMRUN',
129 626c4276 Jan Kiszka
    0x081: 'VMMCALL',
130 626c4276 Jan Kiszka
    0x082: 'VMLOAD',
131 626c4276 Jan Kiszka
    0x083: 'VMSAVE',
132 626c4276 Jan Kiszka
    0x084: 'STGI',
133 626c4276 Jan Kiszka
    0x085: 'CLGI',
134 626c4276 Jan Kiszka
    0x086: 'SKINIT',
135 626c4276 Jan Kiszka
    0x087: 'RDTSCP',
136 626c4276 Jan Kiszka
    0x088: 'ICEBP',
137 626c4276 Jan Kiszka
    0x089: 'WBINVD',
138 626c4276 Jan Kiszka
    0x08a: 'MONITOR',
139 626c4276 Jan Kiszka
    0x08b: 'MWAIT',
140 626c4276 Jan Kiszka
    0x08c: 'MWAIT_COND',
141 626c4276 Jan Kiszka
    0x400: 'NPF',
142 626c4276 Jan Kiszka
}
143 626c4276 Jan Kiszka
144 c5854acb Jens Freimann
s390_exit_reasons = {
145 c5854acb Jens Freimann
	0x000: 'UNKNOWN',
146 c5854acb Jens Freimann
	0x001: 'EXCEPTION',
147 c5854acb Jens Freimann
	0x002: 'IO',
148 c5854acb Jens Freimann
	0x003: 'HYPERCALL',
149 c5854acb Jens Freimann
	0x004: 'DEBUG',
150 c5854acb Jens Freimann
	0x005: 'HLT',
151 c5854acb Jens Freimann
	0x006: 'MMIO',
152 c5854acb Jens Freimann
	0x007: 'IRQ_WINDOW_OPEN',
153 c5854acb Jens Freimann
	0x008: 'SHUTDOWN',
154 c5854acb Jens Freimann
	0x009: 'FAIL_ENTRY',
155 c5854acb Jens Freimann
	0x010: 'INTR',
156 c5854acb Jens Freimann
	0x011: 'SET_TPR',
157 c5854acb Jens Freimann
	0x012: 'TPR_ACCESS',
158 c5854acb Jens Freimann
	0x013: 'S390_SIEIC',
159 c5854acb Jens Freimann
	0x014: 'S390_RESET',
160 c5854acb Jens Freimann
	0x015: 'DCR',
161 c5854acb Jens Freimann
	0x016: 'NMI',
162 c5854acb Jens Freimann
	0x017: 'INTERNAL_ERROR',
163 c5854acb Jens Freimann
	0x018: 'OSI',
164 c5854acb Jens Freimann
	0x019: 'PAPR_HCALL',
165 c5854acb Jens Freimann
}
166 c5854acb Jens Freimann
167 626c4276 Jan Kiszka
vendor_exit_reasons = {
168 626c4276 Jan Kiszka
    'vmx': vmx_exit_reasons,
169 626c4276 Jan Kiszka
    'svm': svm_exit_reasons,
170 c5854acb Jens Freimann
    'IBM/S390': s390_exit_reasons,
171 626c4276 Jan Kiszka
}
172 626c4276 Jan Kiszka
173 1b3e6f88 Heinz Graalfs
syscall_numbers = {
174 1b3e6f88 Heinz Graalfs
    'IBM/S390': 331,
175 1b3e6f88 Heinz Graalfs
}
176 1b3e6f88 Heinz Graalfs
177 1b3e6f88 Heinz Graalfs
sc_perf_evt_open = 298
178 1b3e6f88 Heinz Graalfs
179 626c4276 Jan Kiszka
exit_reasons = None
180 626c4276 Jan Kiszka
181 626c4276 Jan Kiszka
for line in file('/proc/cpuinfo').readlines():
182 c5854acb Jens Freimann
    if line.startswith('flags') or line.startswith('vendor_id'):
183 626c4276 Jan Kiszka
        for flag in line.split():
184 626c4276 Jan Kiszka
            if flag in vendor_exit_reasons:
185 626c4276 Jan Kiszka
                exit_reasons = vendor_exit_reasons[flag]
186 1b3e6f88 Heinz Graalfs
            if flag in syscall_numbers:
187 1b3e6f88 Heinz Graalfs
                sc_perf_evt_open = syscall_numbers[flag]
188 626c4276 Jan Kiszka
filters = {
189 626c4276 Jan Kiszka
    'kvm_exit': ('exit_reason', exit_reasons)
190 626c4276 Jan Kiszka
}
191 626c4276 Jan Kiszka
192 626c4276 Jan Kiszka
def invert(d):
193 626c4276 Jan Kiszka
    return dict((x[1], x[0]) for x in d.iteritems())
194 626c4276 Jan Kiszka
195 626c4276 Jan Kiszka
for f in filters:
196 626c4276 Jan Kiszka
    filters[f] = (filters[f][0], invert(filters[f][1]))
197 626c4276 Jan Kiszka
198 626c4276 Jan Kiszka
import ctypes, struct, array
199 626c4276 Jan Kiszka
200 626c4276 Jan Kiszka
libc = ctypes.CDLL('libc.so.6')
201 626c4276 Jan Kiszka
syscall = libc.syscall
202 626c4276 Jan Kiszka
class perf_event_attr(ctypes.Structure):
203 626c4276 Jan Kiszka
    _fields_ = [('type', ctypes.c_uint32),
204 626c4276 Jan Kiszka
                ('size', ctypes.c_uint32),
205 626c4276 Jan Kiszka
                ('config', ctypes.c_uint64),
206 626c4276 Jan Kiszka
                ('sample_freq', ctypes.c_uint64),
207 626c4276 Jan Kiszka
                ('sample_type', ctypes.c_uint64),
208 626c4276 Jan Kiszka
                ('read_format', ctypes.c_uint64),
209 626c4276 Jan Kiszka
                ('flags', ctypes.c_uint64),
210 626c4276 Jan Kiszka
                ('wakeup_events', ctypes.c_uint32),
211 626c4276 Jan Kiszka
                ('bp_type', ctypes.c_uint32),
212 626c4276 Jan Kiszka
                ('bp_addr', ctypes.c_uint64),
213 626c4276 Jan Kiszka
                ('bp_len', ctypes.c_uint64),
214 626c4276 Jan Kiszka
                ]
215 626c4276 Jan Kiszka
def _perf_event_open(attr, pid, cpu, group_fd, flags):
216 1b3e6f88 Heinz Graalfs
    return syscall(sc_perf_evt_open, ctypes.pointer(attr), ctypes.c_int(pid),
217 626c4276 Jan Kiszka
                   ctypes.c_int(cpu), ctypes.c_int(group_fd),
218 626c4276 Jan Kiszka
                   ctypes.c_long(flags))
219 626c4276 Jan Kiszka
220 626c4276 Jan Kiszka
PERF_TYPE_HARDWARE              = 0
221 626c4276 Jan Kiszka
PERF_TYPE_SOFTWARE              = 1
222 626c4276 Jan Kiszka
PERF_TYPE_TRACEPOINT            = 2
223 626c4276 Jan Kiszka
PERF_TYPE_HW_CACHE              = 3
224 626c4276 Jan Kiszka
PERF_TYPE_RAW                   = 4
225 626c4276 Jan Kiszka
PERF_TYPE_BREAKPOINT            = 5
226 626c4276 Jan Kiszka
227 626c4276 Jan Kiszka
PERF_SAMPLE_IP                  = 1 << 0
228 626c4276 Jan Kiszka
PERF_SAMPLE_TID                 = 1 << 1
229 626c4276 Jan Kiszka
PERF_SAMPLE_TIME                = 1 << 2
230 626c4276 Jan Kiszka
PERF_SAMPLE_ADDR                = 1 << 3
231 626c4276 Jan Kiszka
PERF_SAMPLE_READ                = 1 << 4
232 626c4276 Jan Kiszka
PERF_SAMPLE_CALLCHAIN           = 1 << 5
233 626c4276 Jan Kiszka
PERF_SAMPLE_ID                  = 1 << 6
234 626c4276 Jan Kiszka
PERF_SAMPLE_CPU                 = 1 << 7
235 626c4276 Jan Kiszka
PERF_SAMPLE_PERIOD              = 1 << 8
236 626c4276 Jan Kiszka
PERF_SAMPLE_STREAM_ID           = 1 << 9
237 626c4276 Jan Kiszka
PERF_SAMPLE_RAW                 = 1 << 10
238 626c4276 Jan Kiszka
239 626c4276 Jan Kiszka
PERF_FORMAT_TOTAL_TIME_ENABLED  = 1 << 0
240 626c4276 Jan Kiszka
PERF_FORMAT_TOTAL_TIME_RUNNING  = 1 << 1
241 626c4276 Jan Kiszka
PERF_FORMAT_ID                  = 1 << 2
242 626c4276 Jan Kiszka
PERF_FORMAT_GROUP               = 1 << 3
243 626c4276 Jan Kiszka
244 626c4276 Jan Kiszka
import re
245 626c4276 Jan Kiszka
246 626c4276 Jan Kiszka
sys_tracing = '/sys/kernel/debug/tracing'
247 626c4276 Jan Kiszka
248 626c4276 Jan Kiszka
class Group(object):
249 626c4276 Jan Kiszka
    def __init__(self, cpu):
250 626c4276 Jan Kiszka
        self.events = []
251 626c4276 Jan Kiszka
        self.group_leader = None
252 626c4276 Jan Kiszka
        self.cpu = cpu
253 626c4276 Jan Kiszka
    def add_event(self, name, event_set, tracepoint, filter = None):
254 626c4276 Jan Kiszka
        self.events.append(Event(group = self,
255 626c4276 Jan Kiszka
                                 name = name, event_set = event_set,
256 626c4276 Jan Kiszka
                                 tracepoint = tracepoint, filter = filter))
257 626c4276 Jan Kiszka
        if len(self.events) == 1:
258 626c4276 Jan Kiszka
            self.file = os.fdopen(self.events[0].fd)
259 626c4276 Jan Kiszka
    def read(self):
260 626c4276 Jan Kiszka
        bytes = 8 * (1 + len(self.events))
261 626c4276 Jan Kiszka
        fmt = 'xxxxxxxx' + 'q' * len(self.events)
262 626c4276 Jan Kiszka
        return dict(zip([event.name for event in self.events],
263 626c4276 Jan Kiszka
                        struct.unpack(fmt, self.file.read(bytes))))
264 626c4276 Jan Kiszka
265 626c4276 Jan Kiszka
class Event(object):
266 626c4276 Jan Kiszka
    def __init__(self, group, name, event_set, tracepoint, filter = None):
267 626c4276 Jan Kiszka
        self.name = name
268 626c4276 Jan Kiszka
        attr = perf_event_attr()
269 626c4276 Jan Kiszka
        attr.type = PERF_TYPE_TRACEPOINT
270 626c4276 Jan Kiszka
        attr.size = ctypes.sizeof(attr)
271 626c4276 Jan Kiszka
        id_path = os.path.join(sys_tracing, 'events', event_set,
272 626c4276 Jan Kiszka
                               tracepoint, 'id')
273 626c4276 Jan Kiszka
        id = int(file(id_path).read())
274 626c4276 Jan Kiszka
        attr.config = id
275 626c4276 Jan Kiszka
        attr.sample_type = (PERF_SAMPLE_RAW
276 626c4276 Jan Kiszka
                            | PERF_SAMPLE_TIME
277 626c4276 Jan Kiszka
                            | PERF_SAMPLE_CPU)
278 626c4276 Jan Kiszka
        attr.sample_period = 1
279 626c4276 Jan Kiszka
        attr.read_format = PERF_FORMAT_GROUP
280 626c4276 Jan Kiszka
        group_leader = -1
281 626c4276 Jan Kiszka
        if group.events:
282 626c4276 Jan Kiszka
            group_leader = group.events[0].fd
283 626c4276 Jan Kiszka
        fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
284 626c4276 Jan Kiszka
        if fd == -1:
285 626c4276 Jan Kiszka
            raise Exception('perf_event_open failed')
286 626c4276 Jan Kiszka
        if filter:
287 626c4276 Jan Kiszka
            import fcntl
288 626c4276 Jan Kiszka
            fcntl.ioctl(fd, 0x40082406, filter)
289 626c4276 Jan Kiszka
        self.fd = fd
290 626c4276 Jan Kiszka
    def enable(self):
291 626c4276 Jan Kiszka
        import fcntl
292 626c4276 Jan Kiszka
        fcntl.ioctl(self.fd, 0x00002400, 0)
293 626c4276 Jan Kiszka
    def disable(self):
294 626c4276 Jan Kiszka
        import fcntl
295 626c4276 Jan Kiszka
        fcntl.ioctl(self.fd, 0x00002401, 0)
296 626c4276 Jan Kiszka
297 626c4276 Jan Kiszka
class TracepointProvider(object):
298 626c4276 Jan Kiszka
    def __init__(self):
299 626c4276 Jan Kiszka
        path = os.path.join(sys_tracing, 'events', 'kvm')
300 626c4276 Jan Kiszka
        fields = [f
301 626c4276 Jan Kiszka
                  for f in os.listdir(path)
302 626c4276 Jan Kiszka
                  if os.path.isdir(os.path.join(path, f))]
303 626c4276 Jan Kiszka
        extra = []
304 626c4276 Jan Kiszka
        for f in fields:
305 626c4276 Jan Kiszka
            if f in filters:
306 626c4276 Jan Kiszka
                subfield, values = filters[f]
307 626c4276 Jan Kiszka
                for name, number in values.iteritems():
308 626c4276 Jan Kiszka
                    extra.append(f + '(' + name + ')')
309 626c4276 Jan Kiszka
        fields += extra
310 626c4276 Jan Kiszka
        self._setup(fields)
311 626c4276 Jan Kiszka
        self.select(fields)
312 626c4276 Jan Kiszka
    def fields(self):
313 626c4276 Jan Kiszka
        return self._fields
314 626c4276 Jan Kiszka
    def _setup(self, _fields):
315 626c4276 Jan Kiszka
        self._fields = _fields
316 626c4276 Jan Kiszka
        cpure = r'cpu([0-9]+)'
317 626c4276 Jan Kiszka
        self.cpus = [int(re.match(cpure, x).group(1))
318 626c4276 Jan Kiszka
                     for x in os.listdir('/sys/devices/system/cpu')
319 626c4276 Jan Kiszka
                     if re.match(cpure, x)]
320 626c4276 Jan Kiszka
        import resource
321 626c4276 Jan Kiszka
        nfiles = len(self.cpus) * 1000
322 626c4276 Jan Kiszka
        resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
323 626c4276 Jan Kiszka
        events = []
324 626c4276 Jan Kiszka
        self.group_leaders = []
325 626c4276 Jan Kiszka
        for cpu in self.cpus:
326 626c4276 Jan Kiszka
            group = Group(cpu)
327 626c4276 Jan Kiszka
            for name in _fields:
328 626c4276 Jan Kiszka
                tracepoint = name
329 626c4276 Jan Kiszka
                filter = None
330 626c4276 Jan Kiszka
                m = re.match(r'(.*)\((.*)\)', name)
331 626c4276 Jan Kiszka
                if m:
332 626c4276 Jan Kiszka
                    tracepoint, sub = m.groups()
333 626c4276 Jan Kiszka
                    filter = '%s==%d\0' % (filters[tracepoint][0],
334 626c4276 Jan Kiszka
                                           filters[tracepoint][1][sub])
335 626c4276 Jan Kiszka
                event = group.add_event(name, event_set = 'kvm',
336 626c4276 Jan Kiszka
                                        tracepoint = tracepoint,
337 626c4276 Jan Kiszka
                                        filter = filter)
338 626c4276 Jan Kiszka
            self.group_leaders.append(group)
339 626c4276 Jan Kiszka
    def select(self, fields):
340 626c4276 Jan Kiszka
        for group in self.group_leaders:
341 626c4276 Jan Kiszka
            for event in group.events:
342 626c4276 Jan Kiszka
                if event.name in fields:
343 626c4276 Jan Kiszka
                    event.enable()
344 626c4276 Jan Kiszka
                else:
345 626c4276 Jan Kiszka
                    event.disable()
346 626c4276 Jan Kiszka
    def read(self):
347 626c4276 Jan Kiszka
        from collections import defaultdict
348 626c4276 Jan Kiszka
        ret = defaultdict(int)
349 626c4276 Jan Kiszka
        for group in self.group_leaders:
350 626c4276 Jan Kiszka
            for name, val in group.read().iteritems():
351 626c4276 Jan Kiszka
                ret[name] += val
352 626c4276 Jan Kiszka
        return ret
353 626c4276 Jan Kiszka
354 626c4276 Jan Kiszka
class Stats:
355 626c4276 Jan Kiszka
    def __init__(self, provider, fields = None):
356 626c4276 Jan Kiszka
        self.provider = provider
357 626c4276 Jan Kiszka
        self.fields_filter = fields
358 626c4276 Jan Kiszka
        self._update()
359 626c4276 Jan Kiszka
    def _update(self):
360 626c4276 Jan Kiszka
        def wanted(key):
361 626c4276 Jan Kiszka
            import re
362 626c4276 Jan Kiszka
            if not self.fields_filter:
363 626c4276 Jan Kiszka
                return True
364 626c4276 Jan Kiszka
            return re.match(self.fields_filter, key) is not None
365 626c4276 Jan Kiszka
        self.values = dict([(key, None)
366 626c4276 Jan Kiszka
                            for key in provider.fields()
367 626c4276 Jan Kiszka
                            if wanted(key)])
368 626c4276 Jan Kiszka
        self.provider.select(self.values.keys())
369 626c4276 Jan Kiszka
    def set_fields_filter(self, fields_filter):
370 626c4276 Jan Kiszka
        self.fields_filter = fields_filter
371 626c4276 Jan Kiszka
        self._update()
372 626c4276 Jan Kiszka
    def get(self):
373 626c4276 Jan Kiszka
        new = self.provider.read()
374 626c4276 Jan Kiszka
        for key in self.provider.fields():
375 626c4276 Jan Kiszka
            oldval = self.values.get(key, (0, 0))
376 626c4276 Jan Kiszka
            newval = new[key]
377 626c4276 Jan Kiszka
            newdelta = None
378 626c4276 Jan Kiszka
            if oldval is not None:
379 626c4276 Jan Kiszka
                newdelta = newval - oldval[0]
380 626c4276 Jan Kiszka
            self.values[key] = (newval, newdelta)
381 626c4276 Jan Kiszka
        return self.values
382 626c4276 Jan Kiszka
383 626c4276 Jan Kiszka
if not os.access('/sys/kernel/debug', os.F_OK):
384 626c4276 Jan Kiszka
    print 'Please enable CONFIG_DEBUG_FS in your kernel'
385 626c4276 Jan Kiszka
    sys.exit(1)
386 626c4276 Jan Kiszka
if not os.access('/sys/kernel/debug/kvm', os.F_OK):
387 626c4276 Jan Kiszka
    print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
388 626c4276 Jan Kiszka
    print "and ensure the kvm modules are loaded"
389 626c4276 Jan Kiszka
    sys.exit(1)
390 626c4276 Jan Kiszka
391 626c4276 Jan Kiszka
label_width = 40
392 626c4276 Jan Kiszka
number_width = 10
393 626c4276 Jan Kiszka
394 626c4276 Jan Kiszka
def tui(screen, stats):
395 626c4276 Jan Kiszka
    curses.use_default_colors()
396 626c4276 Jan Kiszka
    curses.noecho()
397 626c4276 Jan Kiszka
    drilldown = False
398 626c4276 Jan Kiszka
    fields_filter = stats.fields_filter
399 626c4276 Jan Kiszka
    def update_drilldown():
400 626c4276 Jan Kiszka
        if not fields_filter:
401 626c4276 Jan Kiszka
            if drilldown:
402 626c4276 Jan Kiszka
                stats.set_fields_filter(None)
403 626c4276 Jan Kiszka
            else:
404 626c4276 Jan Kiszka
                stats.set_fields_filter(r'^[^\(]*$')
405 626c4276 Jan Kiszka
    update_drilldown()
406 626c4276 Jan Kiszka
    def refresh(sleeptime):
407 626c4276 Jan Kiszka
        screen.erase()
408 626c4276 Jan Kiszka
        screen.addstr(0, 0, 'kvm statistics')
409 626c4276 Jan Kiszka
        row = 2
410 626c4276 Jan Kiszka
        s = stats.get()
411 626c4276 Jan Kiszka
        def sortkey(x):
412 626c4276 Jan Kiszka
            if s[x][1]:
413 626c4276 Jan Kiszka
                return (-s[x][1], -s[x][0])
414 626c4276 Jan Kiszka
            else:
415 626c4276 Jan Kiszka
                return (0, -s[x][0])
416 626c4276 Jan Kiszka
        for key in sorted(s.keys(), key = sortkey):
417 626c4276 Jan Kiszka
            if row >= screen.getmaxyx()[0]:
418 626c4276 Jan Kiszka
                break
419 626c4276 Jan Kiszka
            values = s[key]
420 626c4276 Jan Kiszka
            if not values[0] and not values[1]:
421 626c4276 Jan Kiszka
                break
422 626c4276 Jan Kiszka
            col = 1
423 626c4276 Jan Kiszka
            screen.addstr(row, col, key)
424 626c4276 Jan Kiszka
            col += label_width
425 626c4276 Jan Kiszka
            screen.addstr(row, col, '%10d' % (values[0],))
426 626c4276 Jan Kiszka
            col += number_width
427 626c4276 Jan Kiszka
            if values[1] is not None:
428 626c4276 Jan Kiszka
                screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
429 626c4276 Jan Kiszka
            row += 1
430 626c4276 Jan Kiszka
        screen.refresh()
431 626c4276 Jan Kiszka
432 626c4276 Jan Kiszka
    sleeptime = 0.25
433 626c4276 Jan Kiszka
    while True:
434 626c4276 Jan Kiszka
        refresh(sleeptime)
435 626c4276 Jan Kiszka
        curses.halfdelay(int(sleeptime * 10))
436 626c4276 Jan Kiszka
        sleeptime = 3
437 626c4276 Jan Kiszka
        try:
438 626c4276 Jan Kiszka
            c = screen.getkey()
439 626c4276 Jan Kiszka
            if c == 'x':
440 626c4276 Jan Kiszka
                drilldown = not drilldown
441 626c4276 Jan Kiszka
                update_drilldown()
442 626c4276 Jan Kiszka
            if c == 'q':
443 626c4276 Jan Kiszka
                break
444 626c4276 Jan Kiszka
        except KeyboardInterrupt:
445 626c4276 Jan Kiszka
            break
446 626c4276 Jan Kiszka
        except curses.error:
447 626c4276 Jan Kiszka
            continue
448 626c4276 Jan Kiszka
449 626c4276 Jan Kiszka
def batch(stats):
450 626c4276 Jan Kiszka
    s = stats.get()
451 626c4276 Jan Kiszka
    time.sleep(1)
452 626c4276 Jan Kiszka
    s = stats.get()
453 626c4276 Jan Kiszka
    for key in sorted(s.keys()):
454 626c4276 Jan Kiszka
        values = s[key]
455 626c4276 Jan Kiszka
        print '%-22s%10d%10d' % (key, values[0], values[1])
456 626c4276 Jan Kiszka
457 626c4276 Jan Kiszka
def log(stats):
458 626c4276 Jan Kiszka
    keys = sorted(stats.get().iterkeys())
459 626c4276 Jan Kiszka
    def banner():
460 626c4276 Jan Kiszka
        for k in keys:
461 626c4276 Jan Kiszka
            print '%10s' % k[0:9],
462 626c4276 Jan Kiszka
        print
463 626c4276 Jan Kiszka
    def statline():
464 626c4276 Jan Kiszka
        s = stats.get()
465 626c4276 Jan Kiszka
        for k in keys:
466 626c4276 Jan Kiszka
            print ' %9d' % s[k][1],
467 626c4276 Jan Kiszka
        print
468 626c4276 Jan Kiszka
    line = 0
469 626c4276 Jan Kiszka
    banner_repeat = 20
470 626c4276 Jan Kiszka
    while True:
471 626c4276 Jan Kiszka
        time.sleep(1)
472 626c4276 Jan Kiszka
        if line % banner_repeat == 0:
473 626c4276 Jan Kiszka
            banner()
474 626c4276 Jan Kiszka
        statline()
475 626c4276 Jan Kiszka
        line += 1
476 626c4276 Jan Kiszka
477 626c4276 Jan Kiszka
options = optparse.OptionParser()
478 626c4276 Jan Kiszka
options.add_option('-1', '--once', '--batch',
479 626c4276 Jan Kiszka
                   action = 'store_true',
480 626c4276 Jan Kiszka
                   default = False,
481 626c4276 Jan Kiszka
                   dest = 'once',
482 626c4276 Jan Kiszka
                   help = 'run in batch mode for one second',
483 626c4276 Jan Kiszka
                   )
484 626c4276 Jan Kiszka
options.add_option('-l', '--log',
485 626c4276 Jan Kiszka
                   action = 'store_true',
486 626c4276 Jan Kiszka
                   default = False,
487 626c4276 Jan Kiszka
                   dest = 'log',
488 626c4276 Jan Kiszka
                   help = 'run in logging mode (like vmstat)',
489 626c4276 Jan Kiszka
                   )
490 626c4276 Jan Kiszka
options.add_option('-f', '--fields',
491 626c4276 Jan Kiszka
                   action = 'store',
492 626c4276 Jan Kiszka
                   default = None,
493 626c4276 Jan Kiszka
                   dest = 'fields',
494 626c4276 Jan Kiszka
                   help = 'fields to display (regex)',
495 626c4276 Jan Kiszka
                   )
496 626c4276 Jan Kiszka
(options, args) = options.parse_args(sys.argv)
497 626c4276 Jan Kiszka
498 626c4276 Jan Kiszka
try:
499 626c4276 Jan Kiszka
    provider = TracepointProvider()
500 626c4276 Jan Kiszka
except:
501 626c4276 Jan Kiszka
    provider = DebugfsProvider()
502 626c4276 Jan Kiszka
503 626c4276 Jan Kiszka
stats = Stats(provider, fields = options.fields)
504 626c4276 Jan Kiszka
505 626c4276 Jan Kiszka
if options.log:
506 626c4276 Jan Kiszka
    log(stats)
507 626c4276 Jan Kiszka
elif not options.once:
508 626c4276 Jan Kiszka
    import curses.wrapper
509 626c4276 Jan Kiszka
    curses.wrapper(tui, stats)
510 626c4276 Jan Kiszka
else:
511 626c4276 Jan Kiszka
    batch(stats)