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 | |
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 | |
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) |