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