Annotation of qemu/scripts/kvm/kvm_stat, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.