Blame view
tools/perf/builtin-kvm.c
38.1 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
a1645ce12 perf: 'perf kvm' ... |
2 3 |
#include "builtin.h" #include "perf.h" |
4a3cec849 perf dsos: Move t... |
4 |
#include "util/build-id.h" |
bcf6edcd6 perf kvm: Events ... |
5 |
#include "util/evsel.h" |
1afe1d148 perf kvm: Add liv... |
6 |
#include "util/evlist.h" |
e0fcfb086 perf evlist: Adop... |
7 |
#include "util/mmap.h" |
b0742e90f perf tools: Don't... |
8 |
#include "util/term.h" |
a1645ce12 perf: 'perf kvm' ... |
9 10 11 12 |
#include "util/symbol.h" #include "util/thread.h" #include "util/header.h" #include "util/session.h" |
2e73f00fe perf kvm stat rep... |
13 |
#include "util/intlist.h" |
fa0d98462 perf tools: Remov... |
14 |
#include <subcmd/pager.h> |
4b6ab94ea perf subcmd: Crea... |
15 |
#include <subcmd/parse-options.h> |
a1645ce12 perf: 'perf kvm' ... |
16 |
#include "util/trace-event.h" |
a1645ce12 perf: 'perf kvm' ... |
17 |
#include "util/debug.h" |
bcf6edcd6 perf kvm: Events ... |
18 19 |
#include "util/tool.h" #include "util/stat.h" |
ea49e01cf perf tools: Move ... |
20 |
#include "util/synthetic-events.h" |
1afe1d148 perf kvm: Add liv... |
21 |
#include "util/top.h" |
f5fc14124 perf tools: Add d... |
22 |
#include "util/data.h" |
d704ebdae perf tools: tool-... |
23 |
#include "util/ordered-events.h" |
8067b3da9 perf kvm: Move kv... |
24 |
#include "util/kvm-stat.h" |
fa0d98462 perf tools: Remov... |
25 |
#include "ui/ui.h" |
a1645ce12 perf: 'perf kvm' ... |
26 27 |
#include <sys/prctl.h> |
87419c9af perf kvm: Disable... |
28 |
#ifdef HAVE_TIMERFD_SUPPORT |
1afe1d148 perf kvm: Add liv... |
29 |
#include <sys/timerfd.h> |
87419c9af perf kvm: Disable... |
30 |
#endif |
c5e4027e0 perf tools: Move ... |
31 |
#include <sys/time.h> |
bafae98e7 perf evlist: Remo... |
32 33 34 |
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> |
a1645ce12 perf: 'perf kvm' ... |
35 |
|
6ef81c55a perf session: Ret... |
36 |
#include <linux/err.h> |
877a7a110 perf tools: Add i... |
37 |
#include <linux/kernel.h> |
fa0d98462 perf tools: Remov... |
38 |
#include <linux/string.h> |
bd48c63eb tools: Introduce ... |
39 |
#include <linux/time64.h> |
7f7c536f2 tools lib: Adopt ... |
40 |
#include <linux/zalloc.h> |
a43783aee perf tools: Inclu... |
41 |
#include <errno.h> |
fd20e8111 perf tools: Inclu... |
42 |
#include <inttypes.h> |
4208735d8 perf tools: Remov... |
43 |
#include <poll.h> |
1afe1d148 perf kvm: Add liv... |
44 |
#include <termios.h> |
a1645ce12 perf: 'perf kvm' ... |
45 |
#include <semaphore.h> |
9607ad3a6 perf tools: Add s... |
46 |
#include <signal.h> |
a1645ce12 perf: 'perf kvm' ... |
47 |
#include <math.h> |
7728fa0cf libperf: Adopt pe... |
48 |
#include <perf/mmap.h> |
a1645ce12 perf: 'perf kvm' ... |
49 |
|
bb8c16db4 perf kvm: Make fu... |
50 51 52 53 54 55 56 57 58 59 60 61 62 |
static const char *get_filename_for_perf_kvm(void) { const char *filename; if (perf_host && !perf_guest) filename = strdup("perf.data.host"); else if (!perf_host && perf_guest) filename = strdup("perf.data.guest"); else filename = strdup("perf.data.kvm"); return filename; } |
da50ad697 perf kvm: Introdu... |
63 |
#ifdef HAVE_KVM_STAT_SUPPORT |
bcf6edcd6 perf kvm: Events ... |
64 |
|
32dcd021d perf evsel: Renam... |
65 |
void exit_event_get_key(struct evsel *evsel, |
9daa81239 perf kvm: Move ar... |
66 67 |
struct perf_sample *sample, struct event_key *key) |
bcf6edcd6 perf kvm: Events ... |
68 69 |
{ key->info = 0; |
efc0cdc9e perf evsel: Renam... |
70 |
key->key = evsel__intval(evsel, sample, kvm_exit_reason); |
bcf6edcd6 perf kvm: Events ... |
71 |
} |
32dcd021d perf evsel: Renam... |
72 |
bool kvm_exit_event(struct evsel *evsel) |
bcf6edcd6 perf kvm: Events ... |
73 |
{ |
162607ea2 perf kvm/{x86,s39... |
74 |
return !strcmp(evsel->name, kvm_exit_trace); |
bcf6edcd6 perf kvm: Events ... |
75 |
} |
32dcd021d perf evsel: Renam... |
76 |
bool exit_event_begin(struct evsel *evsel, |
9daa81239 perf kvm: Move ar... |
77 |
struct perf_sample *sample, struct event_key *key) |
bcf6edcd6 perf kvm: Events ... |
78 |
{ |
14907e738 perf kvm: Use per... |
79 80 |
if (kvm_exit_event(evsel)) { exit_event_get_key(evsel, sample, key); |
bcf6edcd6 perf kvm: Events ... |
81 82 83 84 85 |
return true; } return false; } |
32dcd021d perf evsel: Renam... |
86 |
bool kvm_entry_event(struct evsel *evsel) |
bcf6edcd6 perf kvm: Events ... |
87 |
{ |
162607ea2 perf kvm/{x86,s39... |
88 |
return !strcmp(evsel->name, kvm_entry_trace); |
bcf6edcd6 perf kvm: Events ... |
89 |
} |
32dcd021d perf evsel: Renam... |
90 |
bool exit_event_end(struct evsel *evsel, |
9daa81239 perf kvm: Move ar... |
91 92 |
struct perf_sample *sample __maybe_unused, struct event_key *key __maybe_unused) |
bcf6edcd6 perf kvm: Events ... |
93 |
{ |
14907e738 perf kvm: Use per... |
94 |
return kvm_entry_event(evsel); |
bcf6edcd6 perf kvm: Events ... |
95 |
} |
df74c13b6 perf kvm: Simplif... |
96 97 98 |
static const char *get_exit_reason(struct perf_kvm_stat *kvm, struct exit_reasons_table *tbl, u64 exit_code) |
bcf6edcd6 perf kvm: Events ... |
99 |
{ |
df74c13b6 perf kvm: Simplif... |
100 |
while (tbl->reason != NULL) { |
de332ac40 perf kvm: Move gl... |
101 102 103 |
if (tbl->exit_code == exit_code) return tbl->reason; tbl++; |
bcf6edcd6 perf kvm: Events ... |
104 105 106 107 |
} pr_err("unknown kvm exit code:%lld on %s ", |
de332ac40 perf kvm: Move gl... |
108 |
(unsigned long long)exit_code, kvm->exit_reasons_isa); |
bcf6edcd6 perf kvm: Events ... |
109 110 |
return "UNKNOWN"; } |
9daa81239 perf kvm: Move ar... |
111 112 113 |
void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, char *decode) |
bcf6edcd6 perf kvm: Events ... |
114 |
{ |
3be8e2a0a perf kvm: Add sta... |
115 |
const char *exit_reason = get_exit_reason(kvm, key->exit_reasons, |
df74c13b6 perf kvm: Simplif... |
116 |
key->key); |
bcf6edcd6 perf kvm: Events ... |
117 |
|
162607ea2 perf kvm/{x86,s39... |
118 |
scnprintf(decode, decode_str_len, "%s", exit_reason); |
bcf6edcd6 perf kvm: Events ... |
119 |
} |
9daa81239 perf kvm: Move ar... |
120 |
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
121 |
{ |
9daa81239 perf kvm: Move ar... |
122 |
struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops; |
bcf6edcd6 perf kvm: Events ... |
123 |
|
9daa81239 perf kvm: Move ar... |
124 125 126 127 128 |
for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) { if (!strcmp(events_ops->name, kvm->report_event)) { kvm->events_ops = events_ops->ops; return true; } |
bcf6edcd6 perf kvm: Events ... |
129 130 131 132 |
} return false; } |
bcf6edcd6 perf kvm: Events ... |
133 134 135 136 137 |
struct vcpu_event_record { int vcpu_id; u64 start_time; struct kvm_event *last_event; }; |
bcf6edcd6 perf kvm: Events ... |
138 |
|
3786063a3 perf kvm: Rename ... |
139 |
static void init_kvm_event_record(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
140 |
{ |
b880deeaf perf kvm: Remove ... |
141 |
unsigned int i; |
bcf6edcd6 perf kvm: Events ... |
142 |
|
b880deeaf perf kvm: Remove ... |
143 |
for (i = 0; i < EVENTS_CACHE_SIZE; i++) |
de332ac40 perf kvm: Move gl... |
144 |
INIT_LIST_HEAD(&kvm->kvm_events_cache[i]); |
bcf6edcd6 perf kvm: Events ... |
145 |
} |
87419c9af perf kvm: Disable... |
146 |
#ifdef HAVE_TIMERFD_SUPPORT |
1afe1d148 perf kvm: Add liv... |
147 148 149 150 151 |
static void clear_events_cache_stats(struct list_head *kvm_events_cache) { struct list_head *head; struct kvm_event *event; unsigned int i; |
62d04dbf3 perf kvm: Add min... |
152 |
int j; |
1afe1d148 perf kvm: Add liv... |
153 154 155 156 157 |
for (i = 0; i < EVENTS_CACHE_SIZE; i++) { head = &kvm_events_cache[i]; list_for_each_entry(event, head, hash_entry) { /* reset stats for event */ |
62d04dbf3 perf kvm: Add min... |
158 159 160 161 162 163 164 |
event->total.time = 0; init_stats(&event->total.stats); for (j = 0; j < event->max_vcpu; ++j) { event->vcpu[j].time = 0; init_stats(&event->vcpu[j].stats); } |
1afe1d148 perf kvm: Add liv... |
165 166 167 |
} } } |
87419c9af perf kvm: Disable... |
168 |
#endif |
1afe1d148 perf kvm: Add liv... |
169 |
|
bcf6edcd6 perf kvm: Events ... |
170 171 172 173 174 175 176 177 |
static int kvm_events_hash_fn(u64 key) { return key & (EVENTS_CACHE_SIZE - 1); } static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) { int old_max_vcpu = event->max_vcpu; |
6ca5f3081 perf kvm: Handle ... |
178 |
void *prev; |
bcf6edcd6 perf kvm: Events ... |
179 180 181 182 183 184 |
if (vcpu_id < event->max_vcpu) return true; while (event->max_vcpu <= vcpu_id) event->max_vcpu += DEFAULT_VCPU_NUM; |
6ca5f3081 perf kvm: Handle ... |
185 |
prev = event->vcpu; |
bcf6edcd6 perf kvm: Events ... |
186 187 188 |
event->vcpu = realloc(event->vcpu, event->max_vcpu * sizeof(*event->vcpu)); if (!event->vcpu) { |
6ca5f3081 perf kvm: Handle ... |
189 |
free(prev); |
bcf6edcd6 perf kvm: Events ... |
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
pr_err("Not enough memory "); return false; } memset(event->vcpu + old_max_vcpu, 0, (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu)); return true; } static struct kvm_event *kvm_alloc_init_event(struct event_key *key) { struct kvm_event *event; event = zalloc(sizeof(*event)); if (!event) { pr_err("Not enough memory "); return NULL; } event->key = *key; |
acb61fc8e perf kvm: Fix 'Mi... |
212 |
init_stats(&event->total.stats); |
bcf6edcd6 perf kvm: Events ... |
213 214 |
return event; } |
3786063a3 perf kvm: Rename ... |
215 |
static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm, |
de332ac40 perf kvm: Move gl... |
216 |
struct event_key *key) |
bcf6edcd6 perf kvm: Events ... |
217 218 219 220 221 |
{ struct kvm_event *event; struct list_head *head; BUG_ON(key->key == INVALID_KEY); |
de332ac40 perf kvm: Move gl... |
222 |
head = &kvm->kvm_events_cache[kvm_events_hash_fn(key->key)]; |
355afe816 perf kvm: Add bra... |
223 |
list_for_each_entry(event, head, hash_entry) { |
bcf6edcd6 perf kvm: Events ... |
224 225 |
if (event->key.key == key->key && event->key.info == key->info) return event; |
355afe816 perf kvm: Add bra... |
226 |
} |
bcf6edcd6 perf kvm: Events ... |
227 228 229 230 231 232 233 234 |
event = kvm_alloc_init_event(key); if (!event) return NULL; list_add(&event->hash_entry, head); return event; } |
3786063a3 perf kvm: Rename ... |
235 |
static bool handle_begin_event(struct perf_kvm_stat *kvm, |
de332ac40 perf kvm: Move gl... |
236 |
struct vcpu_event_record *vcpu_record, |
bcf6edcd6 perf kvm: Events ... |
237 238 239 240 241 |
struct event_key *key, u64 timestamp) { struct kvm_event *event = NULL; if (key->key != INVALID_KEY) |
de332ac40 perf kvm: Move gl... |
242 |
event = find_create_kvm_event(kvm, key); |
bcf6edcd6 perf kvm: Events ... |
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
vcpu_record->last_event = event; vcpu_record->start_time = timestamp; return true; } static void kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff) { kvm_stats->time += time_diff; update_stats(&kvm_stats->stats, time_diff); } static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event) { struct kvm_event_stats *kvm_stats = &event->total; if (vcpu_id != -1) kvm_stats = &event->vcpu[vcpu_id]; return rel_stddev_stats(stddev_stats(&kvm_stats->stats), avg_stats(&kvm_stats->stats)); } static bool update_kvm_event(struct kvm_event *event, int vcpu_id, u64 time_diff) { |
2aa8eab02 perf kvm: Only pr... |
270 271 272 273 |
if (vcpu_id == -1) { kvm_update_event_stats(&event->total, time_diff); return true; } |
bcf6edcd6 perf kvm: Events ... |
274 275 276 277 278 279 280 |
if (!kvm_event_expand(event, vcpu_id)) return false; kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff); return true; } |
3be8e2a0a perf kvm: Add sta... |
281 |
static bool is_child_event(struct perf_kvm_stat *kvm, |
32dcd021d perf evsel: Renam... |
282 |
struct evsel *evsel, |
3be8e2a0a perf kvm: Add sta... |
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
struct perf_sample *sample, struct event_key *key) { struct child_event_ops *child_ops; child_ops = kvm->events_ops->child_ops; if (!child_ops) return false; for (; child_ops->name; child_ops++) { if (!strcmp(evsel->name, child_ops->name)) { child_ops->get_key(evsel, sample, key); return true; } } return false; } static bool handle_child_event(struct perf_kvm_stat *kvm, struct vcpu_event_record *vcpu_record, struct event_key *key, struct perf_sample *sample __maybe_unused) { struct kvm_event *event = NULL; if (key->key != INVALID_KEY) event = find_create_kvm_event(kvm, key); vcpu_record->last_event = event; return true; } |
54c801ff7 perf kvm: Add ski... |
317 318 319 320 321 322 323 324 325 326 |
static bool skip_event(const char *event) { const char * const *skip_events; for (skip_events = kvm_skip_events; *skip_events; skip_events++) if (!strcmp(event, *skip_events)) return true; return false; } |
3786063a3 perf kvm: Rename ... |
327 |
static bool handle_end_event(struct perf_kvm_stat *kvm, |
de332ac40 perf kvm: Move gl... |
328 329 |
struct vcpu_event_record *vcpu_record, struct event_key *key, |
70f7b4a7f perf kvm: Option ... |
330 |
struct perf_sample *sample) |
bcf6edcd6 perf kvm: Events ... |
331 332 333 |
{ struct kvm_event *event; u64 time_begin, time_diff; |
2aa8eab02 perf kvm: Only pr... |
334 335 336 337 338 339 |
int vcpu; if (kvm->trace_vcpu == -1) vcpu = -1; else vcpu = vcpu_record->vcpu_id; |
bcf6edcd6 perf kvm: Events ... |
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
event = vcpu_record->last_event; time_begin = vcpu_record->start_time; /* The begin event is not caught. */ if (!time_begin) return true; /* * In some case, the 'begin event' only records the start timestamp, * the actual event is recognized in the 'end event' (e.g. mmio-event). */ /* Both begin and end events did not get the key. */ if (!event && key->key == INVALID_KEY) return true; if (!event) |
de332ac40 perf kvm: Move gl... |
358 |
event = find_create_kvm_event(kvm, key); |
bcf6edcd6 perf kvm: Events ... |
359 360 361 362 363 364 |
if (!event) return false; vcpu_record->last_event = NULL; vcpu_record->start_time = 0; |
1afe1d148 perf kvm: Add liv... |
365 |
/* seems to happen once in a while during live mode */ |
70f7b4a7f perf kvm: Option ... |
366 |
if (sample->time < time_begin) { |
1afe1d148 perf kvm: Add liv... |
367 368 369 370 |
pr_debug("End time before begin time; skipping event. "); return true; } |
bcf6edcd6 perf kvm: Events ... |
371 |
|
70f7b4a7f perf kvm: Option ... |
372 373 374 |
time_diff = sample->time - time_begin; if (kvm->duration && time_diff > kvm->duration) { |
162607ea2 perf kvm/{x86,s39... |
375 |
char decode[decode_str_len]; |
70f7b4a7f perf kvm: Option ... |
376 377 |
kvm->events_ops->decode_key(kvm, &event->key, decode); |
54c801ff7 perf kvm: Add ski... |
378 |
if (!skip_event(decode)) { |
70f7b4a7f perf kvm: Option ... |
379 380 381 |
pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec ", sample->time, sample->pid, vcpu_record->vcpu_id, |
c05a6e141 perf kvm: Use NSE... |
382 |
decode, time_diff / NSEC_PER_USEC); |
70f7b4a7f perf kvm: Option ... |
383 384 |
} } |
2aa8eab02 perf kvm: Only pr... |
385 |
return update_kvm_event(event, vcpu, time_diff); |
bcf6edcd6 perf kvm: Events ... |
386 |
} |
14907e738 perf kvm: Use per... |
387 388 |
static struct vcpu_event_record *per_vcpu_record(struct thread *thread, |
32dcd021d perf evsel: Renam... |
389 |
struct evsel *evsel, |
14907e738 perf kvm: Use per... |
390 |
struct perf_sample *sample) |
bcf6edcd6 perf kvm: Events ... |
391 392 |
{ /* Only kvm_entry records vcpu id. */ |
69e865c35 perf kvm: Use thr... |
393 |
if (!thread__priv(thread) && kvm_entry_event(evsel)) { |
bcf6edcd6 perf kvm: Events ... |
394 |
struct vcpu_event_record *vcpu_record; |
14907e738 perf kvm: Use per... |
395 |
vcpu_record = zalloc(sizeof(*vcpu_record)); |
bcf6edcd6 perf kvm: Events ... |
396 |
if (!vcpu_record) { |
14907e738 perf kvm: Use per... |
397 398 |
pr_err("%s: Not enough memory ", __func__); |
bcf6edcd6 perf kvm: Events ... |
399 400 |
return NULL; } |
efc0cdc9e perf evsel: Renam... |
401 |
vcpu_record->vcpu_id = evsel__intval(evsel, sample, vcpu_id_str); |
69e865c35 perf kvm: Use thr... |
402 |
thread__set_priv(thread, vcpu_record); |
bcf6edcd6 perf kvm: Events ... |
403 |
} |
69e865c35 perf kvm: Use thr... |
404 |
return thread__priv(thread); |
bcf6edcd6 perf kvm: Events ... |
405 |
} |
3786063a3 perf kvm: Rename ... |
406 |
static bool handle_kvm_event(struct perf_kvm_stat *kvm, |
de332ac40 perf kvm: Move gl... |
407 |
struct thread *thread, |
32dcd021d perf evsel: Renam... |
408 |
struct evsel *evsel, |
14907e738 perf kvm: Use per... |
409 |
struct perf_sample *sample) |
bcf6edcd6 perf kvm: Events ... |
410 411 |
{ struct vcpu_event_record *vcpu_record; |
3be8e2a0a perf kvm: Add sta... |
412 413 |
struct event_key key = { .key = INVALID_KEY, .exit_reasons = kvm->exit_reasons }; |
bcf6edcd6 perf kvm: Events ... |
414 |
|
14907e738 perf kvm: Use per... |
415 |
vcpu_record = per_vcpu_record(thread, evsel, sample); |
bcf6edcd6 perf kvm: Events ... |
416 417 |
if (!vcpu_record) return true; |
2aa8eab02 perf kvm: Only pr... |
418 419 420 421 |
/* only process events for vcpus user cares about */ if ((kvm->trace_vcpu != -1) && (kvm->trace_vcpu != vcpu_record->vcpu_id)) return true; |
de332ac40 perf kvm: Move gl... |
422 423 |
if (kvm->events_ops->is_begin_event(evsel, sample, &key)) return handle_begin_event(kvm, vcpu_record, &key, sample->time); |
bcf6edcd6 perf kvm: Events ... |
424 |
|
3be8e2a0a perf kvm: Add sta... |
425 426 |
if (is_child_event(kvm, evsel, sample, &key)) return handle_child_event(kvm, vcpu_record, &key, sample); |
de332ac40 perf kvm: Move gl... |
427 |
if (kvm->events_ops->is_end_event(evsel, sample, &key)) |
70f7b4a7f perf kvm: Option ... |
428 |
return handle_end_event(kvm, vcpu_record, &key, sample); |
bcf6edcd6 perf kvm: Events ... |
429 430 431 |
return true; } |
bcf6edcd6 perf kvm: Events ... |
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
#define GET_EVENT_KEY(func, field) \ static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ { \ if (vcpu == -1) \ return event->total.field; \ \ if (vcpu >= event->max_vcpu) \ return 0; \ \ return event->vcpu[vcpu].field; \ } #define COMPARE_EVENT_KEY(func, field) \ GET_EVENT_KEY(func, field) \ static int compare_kvm_event_ ## func(struct kvm_event *one, \ struct kvm_event *two, int vcpu)\ { \ return get_event_ ##func(one, vcpu) > \ get_event_ ##func(two, vcpu); \ } GET_EVENT_KEY(time, time); COMPARE_EVENT_KEY(count, stats.n); COMPARE_EVENT_KEY(mean, stats.mean); |
62d04dbf3 perf kvm: Add min... |
456 457 |
GET_EVENT_KEY(max, stats.max); GET_EVENT_KEY(min, stats.min); |
bcf6edcd6 perf kvm: Events ... |
458 459 460 461 462 463 464 465 466 |
#define DEF_SORT_NAME_KEY(name, compare_key) \ { #name, compare_kvm_event_ ## compare_key } static struct kvm_event_key keys[] = { DEF_SORT_NAME_KEY(sample, count), DEF_SORT_NAME_KEY(time, mean), { NULL, NULL } }; |
3786063a3 perf kvm: Rename ... |
467 |
static bool select_key(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
468 469 470 471 |
{ int i; for (i = 0; keys[i].name; i++) { |
de332ac40 perf kvm: Move gl... |
472 473 |
if (!strcmp(keys[i].name, kvm->sort_key)) { kvm->compare = keys[i].key; |
bcf6edcd6 perf kvm: Events ... |
474 475 476 |
return true; } } |
de332ac40 perf kvm: Move gl... |
477 478 |
pr_err("Unknown compare key:%s ", kvm->sort_key); |
bcf6edcd6 perf kvm: Events ... |
479 480 |
return false; } |
de332ac40 perf kvm: Move gl... |
481 482 |
static void insert_to_result(struct rb_root *result, struct kvm_event *event, key_cmp_fun bigger, int vcpu) |
bcf6edcd6 perf kvm: Events ... |
483 |
{ |
de332ac40 perf kvm: Move gl... |
484 |
struct rb_node **rb = &result->rb_node; |
bcf6edcd6 perf kvm: Events ... |
485 486 487 488 489 490 491 492 493 494 495 496 497 498 |
struct rb_node *parent = NULL; struct kvm_event *p; while (*rb) { p = container_of(*rb, struct kvm_event, rb); parent = *rb; if (bigger(event, p, vcpu)) rb = &(*rb)->rb_left; else rb = &(*rb)->rb_right; } rb_link_node(&event->rb, parent, rb); |
de332ac40 perf kvm: Move gl... |
499 |
rb_insert_color(&event->rb, result); |
bcf6edcd6 perf kvm: Events ... |
500 |
} |
3786063a3 perf kvm: Rename ... |
501 502 |
static void update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event) |
bcf6edcd6 perf kvm: Events ... |
503 |
{ |
de332ac40 perf kvm: Move gl... |
504 505 506 507 |
int vcpu = kvm->trace_vcpu; kvm->total_count += get_event_count(event, vcpu); kvm->total_time += get_event_time(event, vcpu); |
bcf6edcd6 perf kvm: Events ... |
508 509 510 511 512 513 |
} static bool event_is_valid(struct kvm_event *event, int vcpu) { return !!get_event_count(event, vcpu); } |
3786063a3 perf kvm: Rename ... |
514 |
static void sort_result(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
515 516 |
{ unsigned int i; |
de332ac40 perf kvm: Move gl... |
517 |
int vcpu = kvm->trace_vcpu; |
bcf6edcd6 perf kvm: Events ... |
518 |
struct kvm_event *event; |
355afe816 perf kvm: Add bra... |
519 520 |
for (i = 0; i < EVENTS_CACHE_SIZE; i++) { list_for_each_entry(event, &kvm->kvm_events_cache[i], hash_entry) { |
bcf6edcd6 perf kvm: Events ... |
521 |
if (event_is_valid(event, vcpu)) { |
de332ac40 perf kvm: Move gl... |
522 523 524 |
update_total_count(kvm, event); insert_to_result(&kvm->result, event, kvm->compare, vcpu); |
bcf6edcd6 perf kvm: Events ... |
525 |
} |
355afe816 perf kvm: Add bra... |
526 527 |
} } |
bcf6edcd6 perf kvm: Events ... |
528 529 530 |
} /* returns left most element of result, and erase it */ |
de332ac40 perf kvm: Move gl... |
531 |
static struct kvm_event *pop_from_result(struct rb_root *result) |
bcf6edcd6 perf kvm: Events ... |
532 |
{ |
de332ac40 perf kvm: Move gl... |
533 |
struct rb_node *node = rb_first(result); |
bcf6edcd6 perf kvm: Events ... |
534 535 536 |
if (!node) return NULL; |
de332ac40 perf kvm: Move gl... |
537 |
rb_erase(node, result); |
bcf6edcd6 perf kvm: Events ... |
538 539 |
return container_of(node, struct kvm_event, rb); } |
1afe1d148 perf kvm: Add liv... |
540 |
static void print_vcpu_info(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
541 |
{ |
1afe1d148 perf kvm: Add liv... |
542 |
int vcpu = kvm->trace_vcpu; |
bcf6edcd6 perf kvm: Events ... |
543 |
pr_info("Analyze events for "); |
1f3e5b550 perf kvm stat rep... |
544 545 546 547 548 549 |
if (kvm->opts.target.system_wide) pr_info("all VMs, "); else if (kvm->opts.target.pid) pr_info("pid(s) %s, ", kvm->opts.target.pid); else pr_info("dazed and confused on what is monitored, "); |
1afe1d148 perf kvm: Add liv... |
550 |
|
bcf6edcd6 perf kvm: Events ... |
551 552 553 554 555 556 557 558 559 |
if (vcpu == -1) pr_info("all VCPUs: "); else pr_info("VCPU %d: ", vcpu); } |
1afe1d148 perf kvm: Add liv... |
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 |
static void show_timeofday(void) { char date[64]; struct timeval tv; struct tm ltime; gettimeofday(&tv, NULL); if (localtime_r(&tv.tv_sec, <ime)) { strftime(date, sizeof(date), "%H:%M:%S", <ime); pr_info("%s.%06ld", date, tv.tv_usec); } else pr_info("00:00:00.000000"); return; } |
3786063a3 perf kvm: Rename ... |
575 |
static void print_result(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
576 |
{ |
162607ea2 perf kvm/{x86,s39... |
577 |
char decode[decode_str_len]; |
bcf6edcd6 perf kvm: Events ... |
578 |
struct kvm_event *event; |
de332ac40 perf kvm: Move gl... |
579 |
int vcpu = kvm->trace_vcpu; |
bcf6edcd6 perf kvm: Events ... |
580 |
|
1afe1d148 perf kvm: Add liv... |
581 582 583 584 |
if (kvm->live) { puts(CONSOLE_CLEAR); show_timeofday(); } |
bcf6edcd6 perf kvm: Events ... |
585 586 587 |
pr_info(" "); |
1afe1d148 perf kvm: Add liv... |
588 |
print_vcpu_info(kvm); |
162607ea2 perf kvm/{x86,s39... |
589 |
pr_info("%*s ", decode_str_len, kvm->events_ops->name); |
bcf6edcd6 perf kvm: Events ... |
590 591 592 593 |
pr_info("%10s ", "Samples"); pr_info("%9s ", "Samples%"); pr_info("%9s ", "Time%"); |
b048a24cc perf kvm stat: Pr... |
594 595 |
pr_info("%11s ", "Min Time"); pr_info("%11s ", "Max Time"); |
bcf6edcd6 perf kvm: Events ... |
596 597 598 599 |
pr_info("%16s ", "Avg time"); pr_info(" "); |
de332ac40 perf kvm: Move gl... |
600 |
while ((event = pop_from_result(&kvm->result))) { |
62d04dbf3 perf kvm: Add min... |
601 |
u64 ecount, etime, max, min; |
bcf6edcd6 perf kvm: Events ... |
602 603 604 |
ecount = get_event_count(event, vcpu); etime = get_event_time(event, vcpu); |
62d04dbf3 perf kvm: Add min... |
605 606 |
max = get_event_max(event, vcpu); min = get_event_min(event, vcpu); |
bcf6edcd6 perf kvm: Events ... |
607 |
|
de332ac40 perf kvm: Move gl... |
608 |
kvm->events_ops->decode_key(kvm, &event->key, decode); |
162607ea2 perf kvm/{x86,s39... |
609 |
pr_info("%*s ", decode_str_len, decode); |
bcf6edcd6 perf kvm: Events ... |
610 |
pr_info("%10llu ", (unsigned long long)ecount); |
de332ac40 perf kvm: Move gl... |
611 612 |
pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100); pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100); |
c05a6e141 perf kvm: Use NSE... |
613 614 615 |
pr_info("%9.2fus ", (double)min / NSEC_PER_USEC); pr_info("%9.2fus ", (double)max / NSEC_PER_USEC); pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount / NSEC_PER_USEC, |
bcf6edcd6 perf kvm: Events ... |
616 617 618 619 |
kvm_event_rel_stddev(vcpu, event)); pr_info(" "); } |
e4f7637f8 perf kvm: Total c... |
620 621 622 623 |
pr_info(" Total Samples:%" PRIu64 ", Total events handled time:%.2fus. ", |
c05a6e141 perf kvm: Use NSE... |
624 |
kvm->total_count, kvm->total_time / (double)NSEC_PER_USEC); |
1afe1d148 perf kvm: Add liv... |
625 626 627 628 629 630 631 |
if (kvm->lost_events) pr_info(" Lost events: %" PRIu64 " ", kvm->lost_events); } |
87419c9af perf kvm: Disable... |
632 |
#ifdef HAVE_TIMERFD_SUPPORT |
1afe1d148 perf kvm: Add liv... |
633 634 635 636 637 638 639 640 641 |
static int process_lost_event(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, struct machine *machine __maybe_unused) { struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool); kvm->lost_events++; return 0; |
bcf6edcd6 perf kvm: Events ... |
642 |
} |
87419c9af perf kvm: Disable... |
643 |
#endif |
bcf6edcd6 perf kvm: Events ... |
644 |
|
2e73f00fe perf kvm stat rep... |
645 646 647 648 649 650 651 652 |
static bool skip_sample(struct perf_kvm_stat *kvm, struct perf_sample *sample) { if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL) return true; return false; } |
de332ac40 perf kvm: Move gl... |
653 |
static int process_sample_event(struct perf_tool *tool, |
bcf6edcd6 perf kvm: Events ... |
654 655 |
union perf_event *event, struct perf_sample *sample, |
32dcd021d perf evsel: Renam... |
656 |
struct evsel *evsel, |
bcf6edcd6 perf kvm: Events ... |
657 658 |
struct machine *machine) { |
b91fc39f4 perf machine: Pro... |
659 |
int err = 0; |
2e73f00fe perf kvm stat rep... |
660 |
struct thread *thread; |
3786063a3 perf kvm: Rename ... |
661 662 |
struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool); |
bcf6edcd6 perf kvm: Events ... |
663 |
|
2e73f00fe perf kvm stat rep... |
664 665 |
if (skip_sample(kvm, sample)) return 0; |
314add6b1 perf tools: chang... |
666 |
thread = machine__findnew_thread(machine, sample->pid, sample->tid); |
bcf6edcd6 perf kvm: Events ... |
667 668 669 670 671 672 |
if (thread == NULL) { pr_debug("problem processing %d event, skipping it. ", event->header.type); return -1; } |
de332ac40 perf kvm: Move gl... |
673 |
if (!handle_kvm_event(kvm, thread, evsel, sample)) |
b91fc39f4 perf machine: Pro... |
674 |
err = -1; |
bcf6edcd6 perf kvm: Events ... |
675 |
|
b91fc39f4 perf machine: Pro... |
676 677 |
thread__put(thread); return err; |
bcf6edcd6 perf kvm: Events ... |
678 |
} |
1afe1d148 perf kvm: Add liv... |
679 |
static int cpu_isa_config(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
680 |
{ |
f67001a4a perf tools: Propa... |
681 |
char buf[128], *cpuid; |
65c647a65 perf kvm: Refacto... |
682 |
int err; |
1afe1d148 perf kvm: Add liv... |
683 684 685 686 |
if (kvm->live) { err = get_cpuid(buf, sizeof(buf)); if (err != 0) { |
f67001a4a perf tools: Propa... |
687 688 689 690 |
pr_err("Failed to look up CPU type: %s ", str_error_r(err, buf, sizeof(buf))); return -err; |
1afe1d148 perf kvm: Add liv... |
691 692 693 694 |
} cpuid = buf; } else cpuid = kvm->session->header.env.cpuid; |
bcf6edcd6 perf kvm: Events ... |
695 |
|
65c647a65 perf kvm: Refacto... |
696 697 698 699 |
if (!cpuid) { pr_err("Failed to look up CPU type "); return -EINVAL; |
1afe1d148 perf kvm: Add liv... |
700 |
} |
65c647a65 perf kvm: Refacto... |
701 702 703 704 |
err = cpu_isa_init(kvm, cpuid); if (err == -ENOTSUP) pr_err("CPU %s is not supported. ", cpuid); |
1afe1d148 perf kvm: Add liv... |
705 |
|
65c647a65 perf kvm: Refacto... |
706 |
return err; |
1afe1d148 perf kvm: Add liv... |
707 708 709 710 711 712 713 714 715 716 717 718 |
} static bool verify_vcpu(int vcpu) { if (vcpu != -1 && vcpu < 0) { pr_err("Invalid vcpu:%d. ", vcpu); return false; } return true; } |
87419c9af perf kvm: Disable... |
719 |
#ifdef HAVE_TIMERFD_SUPPORT |
1afe1d148 perf kvm: Add liv... |
720 721 722 723 724 725 726 727 |
/* keeping the max events to a modest level to keep * the processing of samples per mmap smooth. */ #define PERF_KVM__MAX_EVENTS_PER_MMAP 25 static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx, u64 *mmap_time) { |
63503dba8 perf evlist: Rena... |
728 |
struct evlist *evlist = kvm->evlist; |
1afe1d148 perf kvm: Add liv... |
729 |
union perf_event *event; |
a58305329 perf tools: Renam... |
730 |
struct mmap *md; |
93d10af26 perf tools: Optim... |
731 |
u64 timestamp; |
1afe1d148 perf kvm: Add liv... |
732 733 734 735 |
s64 n = 0; int err; *mmap_time = ULLONG_MAX; |
53172f905 perf kvm: Switch ... |
736 |
md = &evlist->mmap[idx]; |
7c4d41824 libperf: Adopt pe... |
737 |
err = perf_mmap__read_init(&md->core); |
53172f905 perf kvm: Switch ... |
738 739 |
if (err < 0) return (err == -EAGAIN) ? 0 : -1; |
151ed5d70 libperf: Adopt pe... |
740 |
while ((event = perf_mmap__read_event(&md->core)) != NULL) { |
53172f905 perf kvm: Switch ... |
741 |
err = perf_evlist__parse_sample_timestamp(evlist, event, ×tamp); |
1afe1d148 perf kvm: Add liv... |
742 |
if (err) { |
7728fa0cf libperf: Adopt pe... |
743 |
perf_mmap__consume(&md->core); |
1afe1d148 perf kvm: Add liv... |
744 745 746 747 |
pr_err("Failed to parse sample "); return -1; } |
93d10af26 perf tools: Optim... |
748 |
err = perf_session__queue_event(kvm->session, event, timestamp, 0); |
8e50d384c perf tools: Fixup... |
749 |
/* |
b7b61cbeb perf ordered_even... |
750 |
* FIXME: Here we can't consume the event, as perf_session__queue_event will |
8e50d384c perf tools: Fixup... |
751 752 |
* point to it, and it'll get possibly overwritten by the kernel. */ |
7728fa0cf libperf: Adopt pe... |
753 |
perf_mmap__consume(&md->core); |
8e50d384c perf tools: Fixup... |
754 |
|
1afe1d148 perf kvm: Add liv... |
755 756 757 758 759 760 761 762 |
if (err) { pr_err("Failed to enqueue sample: %d ", err); return -1; } /* save time stamp of our first sample for this mmap */ if (n == 0) |
93d10af26 perf tools: Optim... |
763 |
*mmap_time = timestamp; |
1afe1d148 perf kvm: Add liv... |
764 765 766 767 768 769 |
/* limit events per mmap handled all at once */ n++; if (n == PERF_KVM__MAX_EVENTS_PER_MMAP) break; } |
32fdc2ca7 libperf: Adopt pe... |
770 |
perf_mmap__read_done(&md->core); |
1afe1d148 perf kvm: Add liv... |
771 772 773 774 775 776 777 778 |
return n; } static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm) { int i, err, throttled = 0; s64 n, ntotal = 0; u64 flush_time = ULLONG_MAX, mmap_time; |
c976ee11a libperf: Move 'nr... |
779 |
for (i = 0; i < kvm->evlist->core.nr_mmaps; i++) { |
1afe1d148 perf kvm: Add liv... |
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 |
n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time); if (n < 0) return -1; /* flush time is going to be the minimum of all the individual * mmap times. Essentially, we flush all the samples queued up * from the last pass under our minimal start time -- that leaves * a very small race for samples to come in with a lower timestamp. * The ioctl to return the perf_clock timestamp should close the * race entirely. */ if (mmap_time < flush_time) flush_time = mmap_time; ntotal += n; if (n == PERF_KVM__MAX_EVENTS_PER_MMAP) throttled = 1; } /* flush queue after each round in which we processed events */ if (ntotal) { |
d704ebdae perf tools: tool-... |
801 802 803 804 |
struct ordered_events *oe = &kvm->session->ordered_events; oe->next_flush = flush_time; err = ordered_events__flush(oe, OE_FLUSH__ROUND); |
1afe1d148 perf kvm: Add liv... |
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
if (err) { if (kvm->lost_events) pr_info(" Lost events: %" PRIu64 " ", kvm->lost_events); return err; } } return throttled; } static volatile int done; static void sig_handler(int sig __maybe_unused) { done = 1; } static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm) { struct itimerspec new_value; int rc = -1; kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK); if (kvm->timerfd < 0) { pr_err("timerfd_create failed "); goto out; } new_value.it_value.tv_sec = kvm->display_time; new_value.it_value.tv_nsec = 0; new_value.it_interval.tv_sec = kvm->display_time; new_value.it_interval.tv_nsec = 0; if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) { pr_err("timerfd_settime failed: %d ", errno); close(kvm->timerfd); goto out; } rc = 0; out: return rc; } static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm) { uint64_t c; int rc; rc = read(kvm->timerfd, &c, sizeof(uint64_t)); if (rc < 0) { if (errno == EAGAIN) return 0; pr_err("Failed to read timer fd: %d ", errno); return -1; } if (rc != sizeof(uint64_t)) { pr_err("Error reading timer fd - invalid size returned "); return -1; } if (c != 1) pr_debug("Missed timer beats: %" PRIu64 " ", c-1); /* update display */ sort_result(kvm); print_result(kvm); /* reset counts */ clear_events_cache_stats(kvm->kvm_events_cache); kvm->total_count = 0; kvm->total_time = 0; kvm->lost_events = 0; return 0; } static int fd_set_nonblock(int fd) { long arg = 0; arg = fcntl(fd, F_GETFL); if (arg < 0) { pr_err("Failed to get current flags for fd %d ", fd); return -1; } if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) { pr_err("Failed to set non-block option on fd %d ", fd); return -1; } return 0; } |
d5b4130ae perf kvm: Fix std... |
912 |
static int perf_kvm__handle_stdin(void) |
1afe1d148 perf kvm: Add liv... |
913 914 |
{ int c; |
1afe1d148 perf kvm: Add liv... |
915 |
c = getc(stdin); |
1afe1d148 perf kvm: Add liv... |
916 917 918 919 920 921 922 923 |
if (c == 'q') return 1; return 0; } static int kvm_events_live_report(struct perf_kvm_stat *kvm) { |
1ca72260e perf kvm stat liv... |
924 |
int nr_stdin, ret, err = -EINVAL; |
d5b4130ae perf kvm: Fix std... |
925 |
struct termios save; |
1afe1d148 perf kvm: Add liv... |
926 927 928 929 930 931 932 933 934 935 936 937 938 |
/* live flag must be set first */ kvm->live = true; ret = cpu_isa_config(kvm); if (ret < 0) return ret; if (!verify_vcpu(kvm->trace_vcpu) || !select_key(kvm) || !register_kvm_events_ops(kvm)) { goto out; } |
d5b4130ae perf kvm: Fix std... |
939 |
set_term_quiet_input(&save); |
1afe1d148 perf kvm: Add liv... |
940 |
init_kvm_event_record(kvm); |
1afe1d148 perf kvm: Add liv... |
941 942 |
signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); |
1afe1d148 perf kvm: Add liv... |
943 944 945 946 947 |
/* add timer fd */ if (perf_kvm__timerfd_create(kvm) < 0) { err = -1; goto out; } |
f4009e7bf libperf: Add perf... |
948 |
if (evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0) |
0a04c9e0b perf kvm stat liv... |
949 |
goto out; |
f4009e7bf libperf: Add perf... |
950 |
nr_stdin = evlist__add_pollfd(kvm->evlist, fileno(stdin)); |
0cae013cf perf kvm stat liv... |
951 |
if (nr_stdin < 0) |
0a04c9e0b perf kvm stat liv... |
952 |
goto out; |
1afe1d148 perf kvm: Add liv... |
953 954 955 956 |
if (fd_set_nonblock(fileno(stdin)) != 0) goto out; /* everything is good - enable the events and process */ |
1c87f1654 perf evlist: Rena... |
957 |
evlist__enable(kvm->evlist); |
1afe1d148 perf kvm: Add liv... |
958 959 |
while (!done) { |
40cb2d514 libperf: Move 'po... |
960 |
struct fdarray *fda = &kvm->evlist->core.pollfd; |
1afe1d148 perf kvm: Add liv... |
961 962 963 964 965 966 967 968 969 |
int rc; rc = perf_kvm__mmap_read(kvm); if (rc < 0) break; err = perf_kvm__handle_timerfd(kvm); if (err) goto out; |
1ca72260e perf kvm stat liv... |
970 |
if (fda->entries[nr_stdin].revents & POLLIN) |
d5b4130ae perf kvm: Fix std... |
971 |
done = perf_kvm__handle_stdin(); |
1afe1d148 perf kvm: Add liv... |
972 973 |
if (!rc && !done) |
4bfbcf3ee perf kvm: Use evl... |
974 |
err = evlist__poll(kvm->evlist, 100); |
1afe1d148 perf kvm: Add liv... |
975 |
} |
e74676deb perf evlist: Rena... |
976 |
evlist__disable(kvm->evlist); |
1afe1d148 perf kvm: Add liv... |
977 978 979 980 981 982 983 984 985 |
if (err == 0) { sort_result(kvm); print_result(kvm); } out: if (kvm->timerfd >= 0) close(kvm->timerfd); |
d5b4130ae perf kvm: Fix std... |
986 |
tcsetattr(0, TCSAFLUSH, &save); |
1afe1d148 perf kvm: Add liv... |
987 988 989 990 991 992 |
return err; } static int kvm_live_open_events(struct perf_kvm_stat *kvm) { int err, rc = -1; |
32dcd021d perf evsel: Renam... |
993 |
struct evsel *pos; |
63503dba8 perf evlist: Rena... |
994 |
struct evlist *evlist = kvm->evlist; |
f9f33fdba perf kvm: Use str... |
995 |
char sbuf[STRERR_BUFSIZE]; |
1afe1d148 perf kvm: Add liv... |
996 |
|
e68ae9cf7 perf evsel: Do no... |
997 |
perf_evlist__config(evlist, &kvm->opts, NULL); |
1afe1d148 perf kvm: Add liv... |
998 999 1000 1001 1002 |
/* * Note: exclude_{guest,host} do not apply here. * This command processes KVM tracepoints from host only */ |
e5cadb93d perf evlist: Rena... |
1003 |
evlist__for_each_entry(evlist, pos) { |
1fc632cef libperf: Move per... |
1004 |
struct perf_event_attr *attr = &pos->core.attr; |
1afe1d148 perf kvm: Add liv... |
1005 1006 |
/* make sure these *are* set */ |
862b2f8fb perf evsel: Renam... |
1007 1008 1009 1010 |
evsel__set_sample_bit(pos, TID); evsel__set_sample_bit(pos, TIME); evsel__set_sample_bit(pos, CPU); evsel__set_sample_bit(pos, RAW); |
1afe1d148 perf kvm: Add liv... |
1011 |
/* make sure these are *not*; want as small a sample as possible */ |
862b2f8fb perf evsel: Renam... |
1012 1013 1014 1015 1016 |
evsel__reset_sample_bit(pos, PERIOD); evsel__reset_sample_bit(pos, IP); evsel__reset_sample_bit(pos, CALLCHAIN); evsel__reset_sample_bit(pos, ADDR); evsel__reset_sample_bit(pos, READ); |
1afe1d148 perf kvm: Add liv... |
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 |
attr->mmap = 0; attr->comm = 0; attr->task = 0; attr->sample_period = 1; attr->watermark = 0; attr->wakeup_events = 1000; /* will enable all once we are ready */ attr->disabled = 1; } |
474ddc4c4 perf evlist: Rena... |
1029 |
err = evlist__open(evlist); |
1afe1d148 perf kvm: Add liv... |
1030 |
if (err < 0) { |
f9f33fdba perf kvm: Use str... |
1031 1032 |
printf("Couldn't create the events: %s ", |
c8b5f2c96 tools: Introduce ... |
1033 |
str_error_r(errno, sbuf, sizeof(sbuf))); |
1afe1d148 perf kvm: Add liv... |
1034 |
goto out; |
bcf6edcd6 perf kvm: Events ... |
1035 |
} |
9521b5f2d perf tools: Renam... |
1036 |
if (evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) { |
f9f33fdba perf kvm: Use str... |
1037 1038 |
ui__error("Failed to mmap the events: %s ", |
c8b5f2c96 tools: Introduce ... |
1039 |
str_error_r(errno, sbuf, sizeof(sbuf))); |
750b4edeb perf evlist: Rena... |
1040 |
evlist__close(evlist); |
1afe1d148 perf kvm: Add liv... |
1041 1042 1043 1044 1045 1046 1047 |
goto out; } rc = 0; out: return rc; |
bcf6edcd6 perf kvm: Events ... |
1048 |
} |
87419c9af perf kvm: Disable... |
1049 |
#endif |
bcf6edcd6 perf kvm: Events ... |
1050 |
|
3786063a3 perf kvm: Rename ... |
1051 |
static int read_events(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
1052 |
{ |
bcf6edcd6 perf kvm: Events ... |
1053 |
int ret; |
de332ac40 perf kvm: Move gl... |
1054 1055 1056 |
struct perf_tool eops = { .sample = process_sample_event, .comm = perf_event__process_comm, |
f3b3614a2 perf tools: Add P... |
1057 |
.namespaces = perf_event__process_namespaces, |
0a8cb85c2 perf tools: Renam... |
1058 |
.ordered_events = true, |
de332ac40 perf kvm: Move gl... |
1059 |
}; |
8ceb41d7e perf tools: Renam... |
1060 |
struct perf_data file = { |
2d4f27999 perf data: Add gl... |
1061 1062 1063 |
.path = kvm->file_name, .mode = PERF_DATA_MODE_READ, .force = kvm->force, |
f5fc14124 perf tools: Add d... |
1064 |
}; |
de332ac40 perf kvm: Move gl... |
1065 1066 |
kvm->tool = eops; |
f5fc14124 perf tools: Add d... |
1067 |
kvm->session = perf_session__new(&file, false, &kvm->tool); |
6ef81c55a perf session: Ret... |
1068 |
if (IS_ERR(kvm->session)) { |
bcf6edcd6 perf kvm: Events ... |
1069 1070 |
pr_err("Initializing perf session failed "); |
6ef81c55a perf session: Ret... |
1071 |
return PTR_ERR(kvm->session); |
bcf6edcd6 perf kvm: Events ... |
1072 |
} |
0a7e6d1b6 perf tools: Check... |
1073 |
symbol__init(&kvm->session->header.env); |
14d37f38e perf kvm: Move ca... |
1074 |
|
41b983609 perf kvm: Fill in... |
1075 1076 1077 1078 |
if (!perf_session__has_traces(kvm->session, "kvm record")) { ret = -EINVAL; goto out_delete; } |
bcf6edcd6 perf kvm: Events ... |
1079 1080 1081 1082 1083 |
/* * Do not use 'isa' recorded in kvm_exit tracepoint since it is not * traced in the old kernel. */ |
1afe1d148 perf kvm: Add liv... |
1084 |
ret = cpu_isa_config(kvm); |
bcf6edcd6 perf kvm: Events ... |
1085 |
if (ret < 0) |
41b983609 perf kvm: Fill in... |
1086 1087 1088 |
goto out_delete; ret = perf_session__process_events(kvm->session); |
bcf6edcd6 perf kvm: Events ... |
1089 |
|
41b983609 perf kvm: Fill in... |
1090 1091 1092 |
out_delete: perf_session__delete(kvm->session); return ret; |
bcf6edcd6 perf kvm: Events ... |
1093 |
} |
2e73f00fe perf kvm stat rep... |
1094 1095 |
static int parse_target_str(struct perf_kvm_stat *kvm) { |
3ae4a76ac perf kvm stat rep... |
1096 1097 |
if (kvm->opts.target.pid) { kvm->pid_list = intlist__new(kvm->opts.target.pid); |
2e73f00fe perf kvm stat rep... |
1098 1099 1100 1101 1102 1103 1104 1105 1106 |
if (kvm->pid_list == NULL) { pr_err("Error parsing process id string "); return -EINVAL; } } return 0; } |
3786063a3 perf kvm: Rename ... |
1107 |
static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm) |
bcf6edcd6 perf kvm: Events ... |
1108 1109 |
{ int ret = -EINVAL; |
de332ac40 perf kvm: Move gl... |
1110 |
int vcpu = kvm->trace_vcpu; |
bcf6edcd6 perf kvm: Events ... |
1111 |
|
2e73f00fe perf kvm stat rep... |
1112 1113 |
if (parse_target_str(kvm) != 0) goto exit; |
bcf6edcd6 perf kvm: Events ... |
1114 1115 |
if (!verify_vcpu(vcpu)) goto exit; |
de332ac40 perf kvm: Move gl... |
1116 |
if (!select_key(kvm)) |
bcf6edcd6 perf kvm: Events ... |
1117 |
goto exit; |
de332ac40 perf kvm: Move gl... |
1118 |
if (!register_kvm_events_ops(kvm)) |
bcf6edcd6 perf kvm: Events ... |
1119 |
goto exit; |
de332ac40 perf kvm: Move gl... |
1120 |
init_kvm_event_record(kvm); |
bcf6edcd6 perf kvm: Events ... |
1121 |
setup_pager(); |
de332ac40 perf kvm: Move gl... |
1122 |
ret = read_events(kvm); |
bcf6edcd6 perf kvm: Events ... |
1123 1124 |
if (ret) goto exit; |
de332ac40 perf kvm: Move gl... |
1125 1126 |
sort_result(kvm); print_result(kvm); |
bcf6edcd6 perf kvm: Events ... |
1127 1128 1129 |
exit: return ret; } |
bcf6edcd6 perf kvm: Events ... |
1130 1131 1132 1133 1134 1135 1136 |
#define STRDUP_FAIL_EXIT(s) \ ({ char *_p; \ _p = strdup(s); \ if (!_p) \ return -ENOMEM; \ _p; \ }) |
066d3593e perf kvm/powerpc:... |
1137 1138 1139 1140 |
int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused) { return 0; } |
3786063a3 perf kvm: Rename ... |
1141 1142 |
static int kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv) |
bcf6edcd6 perf kvm: Events ... |
1143 |
{ |
9daa81239 perf kvm: Move ar... |
1144 |
unsigned int rec_argc, i, j, events_tp_size; |
bcf6edcd6 perf kvm: Events ... |
1145 |
const char **rec_argv; |
8fdd84c44 perf kvm: Split o... |
1146 1147 1148 |
const char * const record_args[] = { "record", "-R", |
8fdd84c44 perf kvm: Split o... |
1149 1150 1151 |
"-m", "1024", "-c", "1", }; |
f45d20ffb perf kvm: Print k... |
1152 1153 1154 1155 |
const char * const kvm_stat_record_usage[] = { "perf kvm stat record [<options>]", NULL }; |
9daa81239 perf kvm: Move ar... |
1156 |
const char * const *events_tp; |
066d3593e perf kvm/powerpc:... |
1157 |
int ret; |
9daa81239 perf kvm: Move ar... |
1158 |
events_tp_size = 0; |
066d3593e perf kvm/powerpc:... |
1159 1160 1161 1162 1163 1164 |
ret = setup_kvm_events_tp(kvm); if (ret < 0) { pr_err("Unable to setup the kvm tracepoints "); return ret; } |
9daa81239 perf kvm: Move ar... |
1165 1166 1167 |
for (events_tp = kvm_events_tp; *events_tp; events_tp++) events_tp_size++; |
bcf6edcd6 perf kvm: Events ... |
1168 |
|
8fdd84c44 perf kvm: Split o... |
1169 |
rec_argc = ARRAY_SIZE(record_args) + argc + 2 + |
9daa81239 perf kvm: Move ar... |
1170 |
2 * events_tp_size; |
bcf6edcd6 perf kvm: Events ... |
1171 1172 1173 1174 1175 1176 1177 |
rec_argv = calloc(rec_argc + 1, sizeof(char *)); if (rec_argv == NULL) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(record_args); i++) rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); |
9daa81239 perf kvm: Move ar... |
1178 |
for (j = 0; j < events_tp_size; j++) { |
8fdd84c44 perf kvm: Split o... |
1179 1180 1181 |
rec_argv[i++] = "-e"; rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]); } |
bcf6edcd6 perf kvm: Events ... |
1182 |
rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); |
de332ac40 perf kvm: Move gl... |
1183 |
rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name); |
bcf6edcd6 perf kvm: Events ... |
1184 1185 1186 |
for (j = 1; j < (unsigned int)argc; j++, i++) rec_argv[i] = argv[j]; |
f45d20ffb perf kvm: Print k... |
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN); set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN); set_option_flag(record_options, 'R', "raw-samples", PARSE_OPT_HIDDEN); set_option_flag(record_options, 'F', "freq", PARSE_OPT_DISABLED); set_option_flag(record_options, 0, "group", PARSE_OPT_DISABLED); set_option_flag(record_options, 'g', NULL, PARSE_OPT_DISABLED); set_option_flag(record_options, 0, "call-graph", PARSE_OPT_DISABLED); set_option_flag(record_options, 'd', "data", PARSE_OPT_DISABLED); set_option_flag(record_options, 'T', "timestamp", PARSE_OPT_DISABLED); set_option_flag(record_options, 'P', "period", PARSE_OPT_DISABLED); set_option_flag(record_options, 'n', "no-samples", PARSE_OPT_DISABLED); set_option_flag(record_options, 'N', "no-buildid-cache", PARSE_OPT_DISABLED); set_option_flag(record_options, 'B', "no-buildid", PARSE_OPT_DISABLED); set_option_flag(record_options, 'G', "cgroup", PARSE_OPT_DISABLED); set_option_flag(record_options, 'b', "branch-any", PARSE_OPT_DISABLED); set_option_flag(record_options, 'j', "branch-filter", PARSE_OPT_DISABLED); set_option_flag(record_options, 'W', "weight", PARSE_OPT_DISABLED); set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED); record_usage = kvm_stat_record_usage; |
b0ad8ea66 perf tools: Remov... |
1208 |
return cmd_record(i, rec_argv); |
bcf6edcd6 perf kvm: Events ... |
1209 |
} |
3786063a3 perf kvm: Rename ... |
1210 1211 |
static int kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) |
de332ac40 perf kvm: Move gl... |
1212 1213 1214 |
{ const struct option kvm_events_report_options[] = { OPT_STRING(0, "event", &kvm->report_event, "report event", |
3be8e2a0a perf kvm: Add sta... |
1215 1216 |
"event for reporting: vmexit, " "mmio (x86 only), ioport (x86 only)"), |
de332ac40 perf kvm: Move gl... |
1217 1218 1219 1220 1221 |
OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, "vcpu id to report"), OPT_STRING('k', "key", &kvm->sort_key, "sort-key", "key for sorting: sample(sort by samples number)" " time (sort by avg time)"), |
3ae4a76ac perf kvm stat rep... |
1222 |
OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", |
2e73f00fe perf kvm stat rep... |
1223 |
"analyze events only for given process id(s)"), |
8cc5ec1f7 perf kvm: Support... |
1224 |
OPT_BOOLEAN('f', "force", &kvm->force, "don't complain, do it"), |
de332ac40 perf kvm: Move gl... |
1225 1226 |
OPT_END() }; |
bcf6edcd6 perf kvm: Events ... |
1227 |
|
de332ac40 perf kvm: Move gl... |
1228 1229 1230 1231 |
const char * const kvm_events_report_usage[] = { "perf kvm stat report [<options>]", NULL }; |
bcf6edcd6 perf kvm: Events ... |
1232 |
|
bcf6edcd6 perf kvm: Events ... |
1233 1234 1235 1236 1237 1238 1239 1240 |
if (argc) { argc = parse_options(argc, argv, kvm_events_report_options, kvm_events_report_usage, 0); if (argc) usage_with_options(kvm_events_report_usage, kvm_events_report_options); } |
f181957c2 perf kvm stat rep... |
1241 1242 |
if (!kvm->opts.target.pid) kvm->opts.target.system_wide = true; |
de332ac40 perf kvm: Move gl... |
1243 |
return kvm_events_report_vcpu(kvm); |
bcf6edcd6 perf kvm: Events ... |
1244 |
} |
87419c9af perf kvm: Disable... |
1245 |
#ifdef HAVE_TIMERFD_SUPPORT |
63503dba8 perf evlist: Rena... |
1246 |
static struct evlist *kvm_live_event_list(void) |
1afe1d148 perf kvm: Add liv... |
1247 |
{ |
63503dba8 perf evlist: Rena... |
1248 |
struct evlist *evlist; |
1afe1d148 perf kvm: Add liv... |
1249 |
char *tp, *name, *sys; |
1afe1d148 perf kvm: Add liv... |
1250 |
int err = -1; |
9daa81239 perf kvm: Move ar... |
1251 |
const char * const *events_tp; |
1afe1d148 perf kvm: Add liv... |
1252 |
|
0f98b11c6 perf evlist: Rena... |
1253 |
evlist = evlist__new(); |
1afe1d148 perf kvm: Add liv... |
1254 1255 |
if (evlist == NULL) return NULL; |
9daa81239 perf kvm: Move ar... |
1256 |
for (events_tp = kvm_events_tp; *events_tp; events_tp++) { |
1afe1d148 perf kvm: Add liv... |
1257 |
|
9daa81239 perf kvm: Move ar... |
1258 |
tp = strdup(*events_tp); |
1afe1d148 perf kvm: Add liv... |
1259 1260 1261 1262 1263 1264 1265 1266 1267 |
if (tp == NULL) goto out; /* split tracepoint into subsystem and name */ sys = tp; name = strchr(tp, ':'); if (name == NULL) { pr_err("Error parsing %s tracepoint: subsystem delimiter not found ", |
9daa81239 perf kvm: Move ar... |
1268 |
*events_tp); |
1afe1d148 perf kvm: Add liv... |
1269 1270 1271 1272 1273 |
free(tp); goto out; } *name = '\0'; name++; |
e251abee8 perf evlist: Fix ... |
1274 |
if (evlist__add_newtp(evlist, sys, name, NULL)) { |
9daa81239 perf kvm: Move ar... |
1275 1276 |
pr_err("Failed to add %s tracepoint to the list ", *events_tp); |
1afe1d148 perf kvm: Add liv... |
1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 |
free(tp); goto out; } free(tp); } err = 0; out: if (err) { |
c12995a55 perf evlist: Rena... |
1288 |
evlist__delete(evlist); |
1afe1d148 perf kvm: Add liv... |
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 |
evlist = NULL; } return evlist; } static int kvm_events_live(struct perf_kvm_stat *kvm, int argc, const char **argv) { char errbuf[BUFSIZ]; int err; const struct option live_options[] = { OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", "record events on existing process id"), |
994a1f78b perf tools: Check... |
1304 1305 1306 |
OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages", "number of mmap data pages", perf_evlist__parse_mmap_pages), |
1afe1d148 perf kvm: Add liv... |
1307 1308 1309 1310 1311 1312 1313 |
OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide, "system-wide collection from all CPUs"), OPT_UINTEGER('d', "display", &kvm->display_time, "time in seconds between display updates"), OPT_STRING(0, "event", &kvm->report_event, "report event", |
99d348a84 perf kvm stat liv... |
1314 1315 |
"event for reporting: " "vmexit, mmio (x86 only), ioport (x86 only)"), |
1afe1d148 perf kvm: Add liv... |
1316 1317 1318 1319 1320 |
OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu, "vcpu id to report"), OPT_STRING('k', "key", &kvm->sort_key, "sort-key", "key for sorting: sample(sort by samples number)" " time (sort by avg time)"), |
70f7b4a7f perf kvm: Option ... |
1321 |
OPT_U64(0, "duration", &kvm->duration, |
3be8e2a0a perf kvm: Add sta... |
1322 1323 1324 |
"show events other than" " HLT (x86 only) or Wait state (s390 only)" " that take longer than duration usecs"), |
3fcb10e49 perf tools: Allow... |
1325 |
OPT_UINTEGER(0, "proc-map-timeout", &proc_map_timeout, |
9d9cad763 perf tools: Confi... |
1326 |
"per thread proc mmap processing timeout in ms"), |
1afe1d148 perf kvm: Add liv... |
1327 1328 1329 1330 1331 1332 |
OPT_END() }; const char * const live_usage[] = { "perf kvm stat live [<options>]", NULL }; |
8ceb41d7e perf tools: Renam... |
1333 |
struct perf_data data = { |
f5fc14124 perf tools: Add d... |
1334 1335 |
.mode = PERF_DATA_MODE_WRITE, }; |
1afe1d148 perf kvm: Add liv... |
1336 1337 1338 1339 1340 1341 1342 1343 |
/* event handling */ kvm->tool.sample = process_sample_event; kvm->tool.comm = perf_event__process_comm; kvm->tool.exit = perf_event__process_exit; kvm->tool.fork = perf_event__process_fork; kvm->tool.lost = process_lost_event; |
f3b3614a2 perf tools: Add P... |
1344 |
kvm->tool.namespaces = perf_event__process_namespaces; |
0a8cb85c2 perf tools: Renam... |
1345 |
kvm->tool.ordered_events = true; |
1afe1d148 perf kvm: Add liv... |
1346 1347 1348 1349 1350 1351 1352 1353 1354 |
perf_tool__fill_defaults(&kvm->tool); /* set defaults */ kvm->display_time = 1; kvm->opts.user_interval = 1; kvm->opts.mmap_pages = 512; kvm->opts.target.uses_mmap = false; kvm->opts.target.uid_str = NULL; kvm->opts.target.uid = UINT_MAX; |
0a7e6d1b6 perf tools: Check... |
1355 |
symbol__init(NULL); |
1afe1d148 perf kvm: Add liv... |
1356 1357 1358 |
disable_buildid_cache(); use_browser = 0; |
1afe1d148 perf kvm: Add liv... |
1359 1360 1361 1362 1363 1364 1365 |
if (argc) { argc = parse_options(argc, argv, live_options, live_usage, 0); if (argc) usage_with_options(live_usage, live_options); } |
70f7b4a7f perf kvm: Option ... |
1366 |
kvm->duration *= NSEC_PER_USEC; /* convert usec to nsec */ |
1afe1d148 perf kvm: Add liv... |
1367 1368 1369 |
/* * target related setups */ |
602ad878d perf target: Shor... |
1370 |
err = target__validate(&kvm->opts.target); |
1afe1d148 perf kvm: Add liv... |
1371 |
if (err) { |
602ad878d perf target: Shor... |
1372 |
target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ); |
1afe1d148 perf kvm: Add liv... |
1373 1374 |
ui__warning("%s", errbuf); } |
602ad878d perf target: Shor... |
1375 |
if (target__none(&kvm->opts.target)) |
1afe1d148 perf kvm: Add liv... |
1376 1377 1378 1379 1380 1381 |
kvm->opts.target.system_wide = true; /* * generate the event list */ |
066d3593e perf kvm/powerpc:... |
1382 1383 1384 1385 1386 1387 |
err = setup_kvm_events_tp(kvm); if (err < 0) { pr_err("Unable to setup the kvm tracepoints "); return err; } |
1afe1d148 perf kvm: Add liv... |
1388 1389 1390 1391 1392 |
kvm->evlist = kvm_live_event_list(); if (kvm->evlist == NULL) { err = -1; goto out; } |
1afe1d148 perf kvm: Add liv... |
1393 1394 1395 1396 1397 1398 |
if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0) usage_with_options(live_usage, live_options); /* * perf session */ |
8ceb41d7e perf tools: Renam... |
1399 |
kvm->session = perf_session__new(&data, false, &kvm->tool); |
6ef81c55a perf session: Ret... |
1400 1401 |
if (IS_ERR(kvm->session)) { err = PTR_ERR(kvm->session); |
1afe1d148 perf kvm: Add liv... |
1402 1403 1404 1405 |
goto out; } kvm->session->evlist = kvm->evlist; perf_session__set_id_hdr_size(kvm->session); |
673d659f5 perf kvm stat liv... |
1406 |
ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true); |
a33fbd56e perf machine: Sim... |
1407 |
machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target, |
03617c22e libperf: Add thre... |
1408 |
kvm->evlist->core.threads, false, 1); |
1afe1d148 perf kvm: Add liv... |
1409 1410 1411 1412 1413 1414 1415 |
err = kvm_live_open_events(kvm); if (err) goto out; err = kvm_events_live_report(kvm); out: |
e1446551e perf session: Des... |
1416 |
perf_session__delete(kvm->session); |
1afe1d148 perf kvm: Add liv... |
1417 |
kvm->session = NULL; |
c12995a55 perf evlist: Rena... |
1418 |
evlist__delete(kvm->evlist); |
1afe1d148 perf kvm: Add liv... |
1419 1420 1421 |
return err; } |
87419c9af perf kvm: Disable... |
1422 |
#endif |
1afe1d148 perf kvm: Add liv... |
1423 |
|
bcf6edcd6 perf kvm: Events ... |
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 |
static void print_kvm_stat_usage(void) { printf("Usage: perf kvm stat <command> "); printf("# Available commands: "); printf("\trecord: record kvm events "); printf("\treport: report statistical data of kvm events "); |
1afe1d148 perf kvm: Add liv... |
1436 1437 |
printf("\tlive: live reporting of statistical data of kvm events "); |
bcf6edcd6 perf kvm: Events ... |
1438 1439 1440 1441 1442 |
printf(" Otherwise, it is the alias of 'perf stat': "); } |
3786063a3 perf kvm: Rename ... |
1443 |
static int kvm_cmd_stat(const char *file_name, int argc, const char **argv) |
bcf6edcd6 perf kvm: Events ... |
1444 |
{ |
3786063a3 perf kvm: Rename ... |
1445 1446 1447 1448 1449 1450 |
struct perf_kvm_stat kvm = { .file_name = file_name, .trace_vcpu = -1, .report_event = "vmexit", .sort_key = "sample", |
3786063a3 perf kvm: Rename ... |
1451 |
}; |
bcf6edcd6 perf kvm: Events ... |
1452 1453 1454 1455 1456 1457 |
if (argc == 1) { print_kvm_stat_usage(); goto perf_stat; } if (!strncmp(argv[1], "rec", 3)) |
3786063a3 perf kvm: Rename ... |
1458 |
return kvm_events_record(&kvm, argc - 1, argv + 1); |
bcf6edcd6 perf kvm: Events ... |
1459 1460 |
if (!strncmp(argv[1], "rep", 3)) |
3786063a3 perf kvm: Rename ... |
1461 |
return kvm_events_report(&kvm, argc - 1 , argv + 1); |
bcf6edcd6 perf kvm: Events ... |
1462 |
|
87419c9af perf kvm: Disable... |
1463 |
#ifdef HAVE_TIMERFD_SUPPORT |
1afe1d148 perf kvm: Add liv... |
1464 1465 |
if (!strncmp(argv[1], "live", 4)) return kvm_events_live(&kvm, argc - 1 , argv + 1); |
87419c9af perf kvm: Disable... |
1466 |
#endif |
1afe1d148 perf kvm: Add liv... |
1467 |
|
bcf6edcd6 perf kvm: Events ... |
1468 |
perf_stat: |
b0ad8ea66 perf tools: Remov... |
1469 |
return cmd_stat(argc, argv); |
bcf6edcd6 perf kvm: Events ... |
1470 |
} |
da50ad697 perf kvm: Introdu... |
1471 |
#endif /* HAVE_KVM_STAT_SUPPORT */ |
bcf6edcd6 perf kvm: Events ... |
1472 |
|
124eb5f82 perf kvm: Add arc... |
1473 1474 1475 1476 1477 |
int __weak kvm_add_default_arch_event(int *argc __maybe_unused, const char **argv __maybe_unused) { return 0; } |
3786063a3 perf kvm: Rename ... |
1478 |
static int __cmd_record(const char *file_name, int argc, const char **argv) |
a1645ce12 perf: 'perf kvm' ... |
1479 |
{ |
124eb5f82 perf kvm: Add arc... |
1480 |
int rec_argc, i = 0, j, ret; |
a1645ce12 perf: 'perf kvm' ... |
1481 |
const char **rec_argv; |
124eb5f82 perf kvm: Add arc... |
1482 1483 1484 |
ret = kvm_add_default_arch_event(&argc, argv); if (ret) return -EINVAL; |
a1645ce12 perf: 'perf kvm' ... |
1485 1486 1487 1488 |
rec_argc = argc + 2; rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("record"); rec_argv[i++] = strdup("-o"); |
3786063a3 perf kvm: Rename ... |
1489 |
rec_argv[i++] = strdup(file_name); |
a1645ce12 perf: 'perf kvm' ... |
1490 1491 1492 1493 |
for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); |
b0ad8ea66 perf tools: Remov... |
1494 |
return cmd_record(i, rec_argv); |
a1645ce12 perf: 'perf kvm' ... |
1495 |
} |
3786063a3 perf kvm: Rename ... |
1496 |
static int __cmd_report(const char *file_name, int argc, const char **argv) |
a1645ce12 perf: 'perf kvm' ... |
1497 1498 1499 1500 1501 1502 1503 1504 |
{ int rec_argc, i = 0, j; const char **rec_argv; rec_argc = argc + 2; rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("report"); rec_argv[i++] = strdup("-i"); |
3786063a3 perf kvm: Rename ... |
1505 |
rec_argv[i++] = strdup(file_name); |
a1645ce12 perf: 'perf kvm' ... |
1506 1507 1508 1509 |
for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); |
b0ad8ea66 perf tools: Remov... |
1510 |
return cmd_report(i, rec_argv); |
a1645ce12 perf: 'perf kvm' ... |
1511 |
} |
3786063a3 perf kvm: Rename ... |
1512 1513 |
static int __cmd_buildid_list(const char *file_name, int argc, const char **argv) |
a1645ce12 perf: 'perf kvm' ... |
1514 1515 1516 1517 1518 1519 1520 1521 |
{ int rec_argc, i = 0, j; const char **rec_argv; rec_argc = argc + 2; rec_argv = calloc(rec_argc + 1, sizeof(char *)); rec_argv[i++] = strdup("buildid-list"); rec_argv[i++] = strdup("-i"); |
3786063a3 perf kvm: Rename ... |
1522 |
rec_argv[i++] = strdup(file_name); |
a1645ce12 perf: 'perf kvm' ... |
1523 1524 1525 1526 |
for (j = 1; j < argc; j++, i++) rec_argv[i] = argv[j]; BUG_ON(i != rec_argc); |
b0ad8ea66 perf tools: Remov... |
1527 |
return cmd_buildid_list(i, rec_argv); |
a1645ce12 perf: 'perf kvm' ... |
1528 |
} |
b0ad8ea66 perf tools: Remov... |
1529 |
int cmd_kvm(int argc, const char **argv) |
a1645ce12 perf: 'perf kvm' ... |
1530 |
{ |
20914ce5b perf kvm: Initial... |
1531 |
const char *file_name = NULL; |
de332ac40 perf kvm: Move gl... |
1532 |
const struct option kvm_options[] = { |
3786063a3 perf kvm: Rename ... |
1533 |
OPT_STRING('i', "input", &file_name, "file", |
de332ac40 perf kvm: Move gl... |
1534 |
"Input file name"), |
3786063a3 perf kvm: Rename ... |
1535 |
OPT_STRING('o', "output", &file_name, "file", |
de332ac40 perf kvm: Move gl... |
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 |
"Output file name"), OPT_BOOLEAN(0, "guest", &perf_guest, "Collect guest os data"), OPT_BOOLEAN(0, "host", &perf_host, "Collect host os data"), OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", "guest mount directory under which every guest os" " instance has a subdir"), OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, "file", "file saving guest os vmlinux"), OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, "file", "file saving guest os /proc/kallsyms"), OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, "file", "file saving guest os /proc/modules"), |
100b90735 perf kvm: Introdu... |
1550 1551 |
OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), |
de332ac40 perf kvm: Move gl... |
1552 1553 |
OPT_END() }; |
09a71b97c perf kvm: introdu... |
1554 1555 1556 |
const char *const kvm_subcommands[] = { "top", "record", "report", "diff", "buildid-list", "stat", NULL }; const char *kvm_usage[] = { NULL, NULL }; |
de332ac40 perf kvm: Move gl... |
1557 |
|
1aed26717 perf kvm: Do gues... |
1558 1559 |
perf_host = 0; perf_guest = 1; |
a1645ce12 perf: 'perf kvm' ... |
1560 |
|
09a71b97c perf kvm: introdu... |
1561 1562 |
argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
a1645ce12 perf: 'perf kvm' ... |
1563 1564 1565 1566 1567 |
if (!argc) usage_with_options(kvm_usage, kvm_options); if (!perf_host) perf_guest = 1; |
3786063a3 perf kvm: Rename ... |
1568 |
if (!file_name) { |
e1a2b174d perf kvm: Move co... |
1569 |
file_name = get_filename_for_perf_kvm(); |
de332ac40 perf kvm: Move gl... |
1570 |
|
3786063a3 perf kvm: Rename ... |
1571 |
if (!file_name) { |
de332ac40 perf kvm: Move gl... |
1572 1573 1574 1575 |
pr_err("Failed to allocate memory for filename "); return -ENOMEM; } |
a1645ce12 perf: 'perf kvm' ... |
1576 1577 1578 |
} if (!strncmp(argv[0], "rec", 3)) |
3786063a3 perf kvm: Rename ... |
1579 |
return __cmd_record(file_name, argc, argv); |
a1645ce12 perf: 'perf kvm' ... |
1580 |
else if (!strncmp(argv[0], "rep", 3)) |
3786063a3 perf kvm: Rename ... |
1581 |
return __cmd_report(file_name, argc, argv); |
a1645ce12 perf: 'perf kvm' ... |
1582 |
else if (!strncmp(argv[0], "diff", 4)) |
b0ad8ea66 perf tools: Remov... |
1583 |
return cmd_diff(argc, argv); |
a1645ce12 perf: 'perf kvm' ... |
1584 |
else if (!strncmp(argv[0], "top", 3)) |
b0ad8ea66 perf tools: Remov... |
1585 |
return cmd_top(argc, argv); |
a1645ce12 perf: 'perf kvm' ... |
1586 |
else if (!strncmp(argv[0], "buildid-list", 12)) |
3786063a3 perf kvm: Rename ... |
1587 |
return __cmd_buildid_list(file_name, argc, argv); |
da50ad697 perf kvm: Introdu... |
1588 |
#ifdef HAVE_KVM_STAT_SUPPORT |
bcf6edcd6 perf kvm: Events ... |
1589 |
else if (!strncmp(argv[0], "stat", 4)) |
3786063a3 perf kvm: Rename ... |
1590 |
return kvm_cmd_stat(file_name, argc, argv); |
7321090f6 perf kvm: Fix bui... |
1591 |
#endif |
a1645ce12 perf: 'perf kvm' ... |
1592 1593 1594 1595 1596 |
else usage_with_options(kvm_usage, kvm_options); return 0; } |