]> Git Repo - qemu.git/blame - scripts/kvm/kvm_stat
scripts/kvm/kvm_stat: Cleanup of multiple imports
[qemu.git] / scripts / kvm / kvm_stat
CommitLineData
626c4276
JK
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 <[email protected]>
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
14import curses
c81ab0ac
JF
15import sys
16import os
17import time
18import optparse
19import ctypes
20import fcntl
21import resource
22import struct
23import re
24from collections import defaultdict
626c4276
JK
25
26class DebugfsProvider(object):
27 def __init__(self):
28 self.base = '/sys/kernel/debug/kvm'
29 self._fields = os.listdir(self.base)
30 def fields(self):
31 return self._fields
32 def select(self, fields):
33 self._fields = fields
34 def read(self):
35 def val(key):
36 return int(file(self.base + '/' + key).read())
37 return dict([(key, val(key)) for key in self._fields])
38
39vmx_exit_reasons = {
40 0: 'EXCEPTION_NMI',
41 1: 'EXTERNAL_INTERRUPT',
42 2: 'TRIPLE_FAULT',
43 7: 'PENDING_INTERRUPT',
44 8: 'NMI_WINDOW',
45 9: 'TASK_SWITCH',
46 10: 'CPUID',
47 12: 'HLT',
48 14: 'INVLPG',
49 15: 'RDPMC',
50 16: 'RDTSC',
51 18: 'VMCALL',
52 19: 'VMCLEAR',
53 20: 'VMLAUNCH',
54 21: 'VMPTRLD',
55 22: 'VMPTRST',
56 23: 'VMREAD',
57 24: 'VMRESUME',
58 25: 'VMWRITE',
59 26: 'VMOFF',
60 27: 'VMON',
61 28: 'CR_ACCESS',
62 29: 'DR_ACCESS',
63 30: 'IO_INSTRUCTION',
64 31: 'MSR_READ',
65 32: 'MSR_WRITE',
66 33: 'INVALID_STATE',
67 36: 'MWAIT_INSTRUCTION',
68 39: 'MONITOR_INSTRUCTION',
69 40: 'PAUSE_INSTRUCTION',
70 41: 'MCE_DURING_VMENTRY',
71 43: 'TPR_BELOW_THRESHOLD',
72 44: 'APIC_ACCESS',
73 48: 'EPT_VIOLATION',
74 49: 'EPT_MISCONFIG',
75 54: 'WBINVD',
76 55: 'XSETBV',
2c9d535a
WH
77 56: 'APIC_WRITE',
78 58: 'INVPCID',
626c4276
JK
79}
80
81svm_exit_reasons = {
82 0x000: 'READ_CR0',
83 0x003: 'READ_CR3',
84 0x004: 'READ_CR4',
85 0x008: 'READ_CR8',
86 0x010: 'WRITE_CR0',
87 0x013: 'WRITE_CR3',
88 0x014: 'WRITE_CR4',
89 0x018: 'WRITE_CR8',
90 0x020: 'READ_DR0',
91 0x021: 'READ_DR1',
92 0x022: 'READ_DR2',
93 0x023: 'READ_DR3',
94 0x024: 'READ_DR4',
95 0x025: 'READ_DR5',
96 0x026: 'READ_DR6',
97 0x027: 'READ_DR7',
98 0x030: 'WRITE_DR0',
99 0x031: 'WRITE_DR1',
100 0x032: 'WRITE_DR2',
101 0x033: 'WRITE_DR3',
102 0x034: 'WRITE_DR4',
103 0x035: 'WRITE_DR5',
104 0x036: 'WRITE_DR6',
105 0x037: 'WRITE_DR7',
106 0x040: 'EXCP_BASE',
107 0x060: 'INTR',
108 0x061: 'NMI',
109 0x062: 'SMI',
110 0x063: 'INIT',
111 0x064: 'VINTR',
112 0x065: 'CR0_SEL_WRITE',
113 0x066: 'IDTR_READ',
114 0x067: 'GDTR_READ',
115 0x068: 'LDTR_READ',
116 0x069: 'TR_READ',
117 0x06a: 'IDTR_WRITE',
118 0x06b: 'GDTR_WRITE',
119 0x06c: 'LDTR_WRITE',
120 0x06d: 'TR_WRITE',
121 0x06e: 'RDTSC',
122 0x06f: 'RDPMC',
123 0x070: 'PUSHF',
124 0x071: 'POPF',
125 0x072: 'CPUID',
126 0x073: 'RSM',
127 0x074: 'IRET',
128 0x075: 'SWINT',
129 0x076: 'INVD',
130 0x077: 'PAUSE',
131 0x078: 'HLT',
132 0x079: 'INVLPG',
133 0x07a: 'INVLPGA',
134 0x07b: 'IOIO',
135 0x07c: 'MSR',
136 0x07d: 'TASK_SWITCH',
137 0x07e: 'FERR_FREEZE',
138 0x07f: 'SHUTDOWN',
139 0x080: 'VMRUN',
140 0x081: 'VMMCALL',
141 0x082: 'VMLOAD',
142 0x083: 'VMSAVE',
143 0x084: 'STGI',
144 0x085: 'CLGI',
145 0x086: 'SKINIT',
146 0x087: 'RDTSCP',
147 0x088: 'ICEBP',
148 0x089: 'WBINVD',
149 0x08a: 'MONITOR',
150 0x08b: 'MWAIT',
151 0x08c: 'MWAIT_COND',
2c9d535a 152 0x08d: 'XSETBV',
626c4276
JK
153 0x400: 'NPF',
154}
155
edecf5ec
WH
156# EC definition of HSR (from arch/arm64/include/asm/kvm_arm.h)
157aarch64_exit_reasons = {
158 0x00: 'UNKNOWN',
159 0x01: 'WFI',
160 0x03: 'CP15_32',
161 0x04: 'CP15_64',
162 0x05: 'CP14_MR',
163 0x06: 'CP14_LS',
164 0x07: 'FP_ASIMD',
165 0x08: 'CP10_ID',
166 0x0C: 'CP14_64',
167 0x0E: 'ILL_ISS',
168 0x11: 'SVC32',
169 0x12: 'HVC32',
170 0x13: 'SMC32',
171 0x15: 'SVC64',
172 0x16: 'HVC64',
173 0x17: 'SMC64',
174 0x18: 'SYS64',
175 0x20: 'IABT',
176 0x21: 'IABT_HYP',
177 0x22: 'PC_ALIGN',
178 0x24: 'DABT',
179 0x25: 'DABT_HYP',
180 0x26: 'SP_ALIGN',
181 0x28: 'FP_EXC32',
182 0x2C: 'FP_EXC64',
183 0x2F: 'SERROR',
184 0x30: 'BREAKPT',
185 0x31: 'BREAKPT_HYP',
186 0x32: 'SOFTSTP',
187 0x33: 'SOFTSTP_HYP',
188 0x34: 'WATCHPT',
189 0x35: 'WATCHPT_HYP',
190 0x38: 'BKPT32',
191 0x3A: 'VECTOR32',
192 0x3C: 'BRK64',
193}
194
27d318a8
ME
195# From include/uapi/linux/kvm.h, KVM_EXIT_xxx
196userspace_exit_reasons = {
197 0: 'UNKNOWN',
198 1: 'EXCEPTION',
199 2: 'IO',
200 3: 'HYPERCALL',
201 4: 'DEBUG',
202 5: 'HLT',
203 6: 'MMIO',
204 7: 'IRQ_WINDOW_OPEN',
205 8: 'SHUTDOWN',
206 9: 'FAIL_ENTRY',
207 10: 'INTR',
208 11: 'SET_TPR',
209 12: 'TPR_ACCESS',
210 13: 'S390_SIEIC',
211 14: 'S390_RESET',
212 15: 'DCR',
213 16: 'NMI',
214 17: 'INTERNAL_ERROR',
215 18: 'OSI',
216 19: 'PAPR_HCALL',
217 20: 'S390_UCONTROL',
218 21: 'WATCHDOG',
219 22: 'S390_TSCH',
220 23: 'EPR',
2c9d535a 221 24: 'SYSTEM_EVENT',
c5854acb
JF
222}
223
4d4103ff 224x86_exit_reasons = {
626c4276
JK
225 'vmx': vmx_exit_reasons,
226 'svm': svm_exit_reasons,
227}
228
4d4103ff
ME
229sc_perf_evt_open = None
230exit_reasons = None
1b3e6f88 231
a15d5642
ME
232ioctl_numbers = {
233 'SET_FILTER' : 0x40082406,
234 'ENABLE' : 0x00002400,
235 'DISABLE' : 0x00002401,
fc116efa 236 'RESET' : 0x00002403,
a15d5642
ME
237}
238
4d4103ff
ME
239def x86_init(flag):
240 globals().update({
241 'sc_perf_evt_open' : 298,
242 'exit_reasons' : x86_exit_reasons[flag],
243 })
1b3e6f88 244
4d4103ff
ME
245def s390_init():
246 globals().update({
247 'sc_perf_evt_open' : 331
248 })
249
4725398f
ME
250def ppc_init():
251 globals().update({
252 'sc_perf_evt_open' : 319,
253 'ioctl_numbers' : {
254 'SET_FILTER' : 0x80002406 | (ctypes.sizeof(ctypes.c_char_p) << 16),
255 'ENABLE' : 0x20002400,
256 'DISABLE' : 0x20002401,
257 }
258 })
259
edcbc401
WH
260def aarch64_init():
261 globals().update({
edecf5ec
WH
262 'sc_perf_evt_open' : 241,
263 'exit_reasons' : aarch64_exit_reasons,
edcbc401
WH
264 })
265
4d4103ff 266def detect_platform():
4725398f
ME
267 if os.uname()[4].startswith('ppc'):
268 ppc_init()
269 return
edcbc401
WH
270 elif os.uname()[4].startswith('aarch64'):
271 aarch64_init()
272 return
4725398f 273
4d4103ff
ME
274 for line in file('/proc/cpuinfo').readlines():
275 if line.startswith('flags'):
276 for flag in line.split():
277 if flag in x86_exit_reasons:
278 x86_init(flag)
279 return
280 elif line.startswith('vendor_id'):
281 for flag in line.split():
282 if flag == 'IBM/S390':
283 s390_init()
284 return
626c4276 285
4d4103ff 286detect_platform()
626c4276
JK
287
288def invert(d):
289 return dict((x[1], x[0]) for x in d.iteritems())
290
27d318a8
ME
291filters = {}
292filters['kvm_userspace_exit'] = ('reason', invert(userspace_exit_reasons))
293if exit_reasons:
294 filters['kvm_exit'] = ('exit_reason', invert(exit_reasons))
626c4276 295
626c4276
JK
296libc = ctypes.CDLL('libc.so.6')
297syscall = libc.syscall
874b1cfa 298get_errno = libc.__errno_location
c81ab0ac 299get_errno.restype = ctypes.POINTER(ctypes.c_int)
874b1cfa 300
626c4276
JK
301class perf_event_attr(ctypes.Structure):
302 _fields_ = [('type', ctypes.c_uint32),
303 ('size', ctypes.c_uint32),
304 ('config', ctypes.c_uint64),
305 ('sample_freq', ctypes.c_uint64),
306 ('sample_type', ctypes.c_uint64),
307 ('read_format', ctypes.c_uint64),
308 ('flags', ctypes.c_uint64),
309 ('wakeup_events', ctypes.c_uint32),
310 ('bp_type', ctypes.c_uint32),
311 ('bp_addr', ctypes.c_uint64),
312 ('bp_len', ctypes.c_uint64),
313 ]
314def _perf_event_open(attr, pid, cpu, group_fd, flags):
1b3e6f88 315 return syscall(sc_perf_evt_open, ctypes.pointer(attr), ctypes.c_int(pid),
626c4276
JK
316 ctypes.c_int(cpu), ctypes.c_int(group_fd),
317 ctypes.c_long(flags))
318
319PERF_TYPE_HARDWARE = 0
320PERF_TYPE_SOFTWARE = 1
321PERF_TYPE_TRACEPOINT = 2
322PERF_TYPE_HW_CACHE = 3
323PERF_TYPE_RAW = 4
324PERF_TYPE_BREAKPOINT = 5
325
326PERF_SAMPLE_IP = 1 << 0
327PERF_SAMPLE_TID = 1 << 1
328PERF_SAMPLE_TIME = 1 << 2
329PERF_SAMPLE_ADDR = 1 << 3
330PERF_SAMPLE_READ = 1 << 4
331PERF_SAMPLE_CALLCHAIN = 1 << 5
332PERF_SAMPLE_ID = 1 << 6
333PERF_SAMPLE_CPU = 1 << 7
334PERF_SAMPLE_PERIOD = 1 << 8
335PERF_SAMPLE_STREAM_ID = 1 << 9
336PERF_SAMPLE_RAW = 1 << 10
337
338PERF_FORMAT_TOTAL_TIME_ENABLED = 1 << 0
339PERF_FORMAT_TOTAL_TIME_RUNNING = 1 << 1
340PERF_FORMAT_ID = 1 << 2
341PERF_FORMAT_GROUP = 1 << 3
342
626c4276
JK
343sys_tracing = '/sys/kernel/debug/tracing'
344
345class Group(object):
346 def __init__(self, cpu):
347 self.events = []
348 self.group_leader = None
349 self.cpu = cpu
350 def add_event(self, name, event_set, tracepoint, filter = None):
351 self.events.append(Event(group = self,
352 name = name, event_set = event_set,
353 tracepoint = tracepoint, filter = filter))
354 if len(self.events) == 1:
355 self.file = os.fdopen(self.events[0].fd)
356 def read(self):
357 bytes = 8 * (1 + len(self.events))
358 fmt = 'xxxxxxxx' + 'q' * len(self.events)
359 return dict(zip([event.name for event in self.events],
360 struct.unpack(fmt, self.file.read(bytes))))
361
362class Event(object):
363 def __init__(self, group, name, event_set, tracepoint, filter = None):
364 self.name = name
365 attr = perf_event_attr()
366 attr.type = PERF_TYPE_TRACEPOINT
367 attr.size = ctypes.sizeof(attr)
368 id_path = os.path.join(sys_tracing, 'events', event_set,
369 tracepoint, 'id')
370 id = int(file(id_path).read())
371 attr.config = id
372 attr.sample_type = (PERF_SAMPLE_RAW
373 | PERF_SAMPLE_TIME
374 | PERF_SAMPLE_CPU)
375 attr.sample_period = 1
376 attr.read_format = PERF_FORMAT_GROUP
377 group_leader = -1
378 if group.events:
379 group_leader = group.events[0].fd
380 fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
381 if fd == -1:
874b1cfa
WH
382 err = get_errno()[0]
383 raise Exception('perf_event_open failed, errno = ' + err.__str__())
626c4276 384 if filter:
a15d5642 385 fcntl.ioctl(fd, ioctl_numbers['SET_FILTER'], filter)
626c4276
JK
386 self.fd = fd
387 def enable(self):
a15d5642 388 fcntl.ioctl(self.fd, ioctl_numbers['ENABLE'], 0)
626c4276 389 def disable(self):
a15d5642 390 fcntl.ioctl(self.fd, ioctl_numbers['DISABLE'], 0)
fc116efa 391 def reset(self):
fc116efa 392 fcntl.ioctl(self.fd, ioctl_numbers['RESET'], 0)
626c4276
JK
393
394class TracepointProvider(object):
395 def __init__(self):
396 path = os.path.join(sys_tracing, 'events', 'kvm')
397 fields = [f
398 for f in os.listdir(path)
399 if os.path.isdir(os.path.join(path, f))]
400 extra = []
401 for f in fields:
402 if f in filters:
403 subfield, values = filters[f]
404 for name, number in values.iteritems():
405 extra.append(f + '(' + name + ')')
406 fields += extra
407 self._setup(fields)
408 self.select(fields)
409 def fields(self):
410 return self._fields
763952d0
ME
411
412 def _online_cpus(self):
413 l = []
414 pattern = r'cpu([0-9]+)'
415 basedir = '/sys/devices/system/cpu'
416 for entry in os.listdir(basedir):
417 match = re.match(pattern, entry)
418 if not match:
419 continue
420 path = os.path.join(basedir, entry, 'online')
421 if os.path.exists(path) and open(path).read().strip() != '1':
422 continue
423 l.append(int(match.group(1)))
424 return l
425
626c4276
JK
426 def _setup(self, _fields):
427 self._fields = _fields
763952d0 428 cpus = self._online_cpus()
763952d0 429 nfiles = len(cpus) * 1000
626c4276
JK
430 resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
431 events = []
432 self.group_leaders = []
763952d0 433 for cpu in cpus:
626c4276
JK
434 group = Group(cpu)
435 for name in _fields:
436 tracepoint = name
437 filter = None
438 m = re.match(r'(.*)\((.*)\)', name)
439 if m:
440 tracepoint, sub = m.groups()
441 filter = '%s==%d\0' % (filters[tracepoint][0],
442 filters[tracepoint][1][sub])
443 event = group.add_event(name, event_set = 'kvm',
444 tracepoint = tracepoint,
445 filter = filter)
446 self.group_leaders.append(group)
447 def select(self, fields):
448 for group in self.group_leaders:
449 for event in group.events:
450 if event.name in fields:
fc116efa 451 event.reset()
626c4276
JK
452 event.enable()
453 else:
454 event.disable()
455 def read(self):
626c4276
JK
456 ret = defaultdict(int)
457 for group in self.group_leaders:
458 for name, val in group.read().iteritems():
459 ret[name] += val
460 return ret
461
462class Stats:
b763adf1
PB
463 def __init__(self, providers, fields = None):
464 self.providers = providers
626c4276
JK
465 self.fields_filter = fields
466 self._update()
467 def _update(self):
468 def wanted(key):
626c4276
JK
469 if not self.fields_filter:
470 return True
471 return re.match(self.fields_filter, key) is not None
b763adf1
PB
472 self.values = dict()
473 for d in providers:
474 provider_fields = [key for key in d.fields() if wanted(key)]
475 for key in provider_fields:
476 self.values[key] = None
477 d.select(provider_fields)
626c4276
JK
478 def set_fields_filter(self, fields_filter):
479 self.fields_filter = fields_filter
480 self._update()
481 def get(self):
b763adf1
PB
482 for d in providers:
483 new = d.read()
484 for key in d.fields():
485 oldval = self.values.get(key, (0, 0))
486 newval = new[key]
487 newdelta = None
488 if oldval is not None:
489 newdelta = newval - oldval[0]
490 self.values[key] = (newval, newdelta)
626c4276
JK
491 return self.values
492
493if not os.access('/sys/kernel/debug', os.F_OK):
494 print 'Please enable CONFIG_DEBUG_FS in your kernel'
495 sys.exit(1)
496if not os.access('/sys/kernel/debug/kvm', os.F_OK):
497 print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
498 print "and ensure the kvm modules are loaded"
499 sys.exit(1)
500
501label_width = 40
502number_width = 10
503
504def tui(screen, stats):
505 curses.use_default_colors()
506 curses.noecho()
507 drilldown = False
508 fields_filter = stats.fields_filter
509 def update_drilldown():
510 if not fields_filter:
511 if drilldown:
512 stats.set_fields_filter(None)
513 else:
514 stats.set_fields_filter(r'^[^\(]*$')
515 update_drilldown()
516 def refresh(sleeptime):
517 screen.erase()
518 screen.addstr(0, 0, 'kvm statistics')
9a7dcb71
SH
519 screen.addstr(2, 1, 'Event')
520 screen.addstr(2, 1 + label_width + number_width - len('Total'), 'Total')
521 screen.addstr(2, 1 + label_width + number_width + 8 - len('Current'), 'Current')
522 row = 3
626c4276
JK
523 s = stats.get()
524 def sortkey(x):
525 if s[x][1]:
526 return (-s[x][1], -s[x][0])
527 else:
528 return (0, -s[x][0])
529 for key in sorted(s.keys(), key = sortkey):
530 if row >= screen.getmaxyx()[0]:
531 break
532 values = s[key]
533 if not values[0] and not values[1]:
534 break
535 col = 1
536 screen.addstr(row, col, key)
537 col += label_width
538 screen.addstr(row, col, '%10d' % (values[0],))
539 col += number_width
540 if values[1] is not None:
541 screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
542 row += 1
543 screen.refresh()
544
545 sleeptime = 0.25
546 while True:
547 refresh(sleeptime)
548 curses.halfdelay(int(sleeptime * 10))
549 sleeptime = 3
550 try:
551 c = screen.getkey()
552 if c == 'x':
553 drilldown = not drilldown
554 update_drilldown()
555 if c == 'q':
556 break
557 except KeyboardInterrupt:
558 break
559 except curses.error:
560 continue
561
562def batch(stats):
563 s = stats.get()
564 time.sleep(1)
565 s = stats.get()
566 for key in sorted(s.keys()):
567 values = s[key]
568 print '%-22s%10d%10d' % (key, values[0], values[1])
569
570def log(stats):
571 keys = sorted(stats.get().iterkeys())
572 def banner():
573 for k in keys:
574 print '%10s' % k[0:9],
575 print
576 def statline():
577 s = stats.get()
578 for k in keys:
579 print ' %9d' % s[k][1],
580 print
581 line = 0
582 banner_repeat = 20
583 while True:
584 time.sleep(1)
585 if line % banner_repeat == 0:
586 banner()
587 statline()
588 line += 1
589
590options = optparse.OptionParser()
591options.add_option('-1', '--once', '--batch',
592 action = 'store_true',
593 default = False,
594 dest = 'once',
595 help = 'run in batch mode for one second',
596 )
597options.add_option('-l', '--log',
598 action = 'store_true',
599 default = False,
600 dest = 'log',
601 help = 'run in logging mode (like vmstat)',
602 )
b763adf1
PB
603options.add_option('-t', '--tracepoints',
604 action = 'store_true',
605 default = False,
606 dest = 'tracepoints',
607 help = 'retrieve statistics from tracepoints',
608 )
609options.add_option('-d', '--debugfs',
610 action = 'store_true',
611 default = False,
612 dest = 'debugfs',
613 help = 'retrieve statistics from debugfs',
614 )
626c4276
JK
615options.add_option('-f', '--fields',
616 action = 'store',
617 default = None,
618 dest = 'fields',
619 help = 'fields to display (regex)',
620 )
621(options, args) = options.parse_args(sys.argv)
622
b763adf1
PB
623providers = []
624if options.tracepoints:
625 providers.append(TracepointProvider())
626if options.debugfs:
627 providers.append(DebugfsProvider())
628
629if len(providers) == 0:
630 try:
631 providers = [TracepointProvider()]
632 except:
633 providers = [DebugfsProvider()]
626c4276 634
b763adf1 635stats = Stats(providers, fields = options.fields)
626c4276
JK
636
637if options.log:
638 log(stats)
639elif not options.once:
626c4276
JK
640 curses.wrapper(tui, stats)
641else:
642 batch(stats)
This page took 0.395266 seconds and 4 git commands to generate.