1 #include "builtin.h" 2 #include "perf.h" 3 4 #include "util/evsel.h" 5 #include "util/util.h" 6 #include "util/cache.h" 7 #include "util/symbol.h" 8 #include "util/thread.h" 9 #include "util/header.h" 10 #include "util/session.h" 11 12 #include "util/parse-options.h" 13 #include "util/trace-event.h" 14 #include "util/debug.h" 15 #include "util/debugfs.h" 16 #include "util/tool.h" 17 #include "util/stat.h" 18 19 #include <sys/prctl.h> 20 21 #include <semaphore.h> 22 #include <pthread.h> 23 #include <math.h> 24 25 #include "../../arch/x86/include/asm/svm.h" 26 #include "../../arch/x86/include/asm/vmx.h" 27 #include "../../arch/x86/include/asm/kvm.h" 28 29 struct event_key { 30 #define INVALID_KEY (~0ULL) 31 u64 key; 32 int info; 33 }; 34 35 struct kvm_events_ops { 36 bool (*is_begin_event)(struct perf_evsel *evsel, 37 struct perf_sample *sample, 38 struct event_key *key); 39 bool (*is_end_event)(struct perf_evsel *evsel, 40 struct perf_sample *sample, struct event_key *key); 41 void (*decode_key)(struct event_key *key, char decode[20]); 42 const char *name; 43 }; 44 45 static void exit_event_get_key(struct perf_evsel *evsel, 46 struct perf_sample *sample, 47 struct event_key *key) 48 { 49 key->info = 0; 50 key->key = perf_evsel__intval(evsel, sample, "exit_reason"); 51 } 52 53 static bool kvm_exit_event(struct perf_evsel *evsel) 54 { 55 return !strcmp(evsel->name, "kvm:kvm_exit"); 56 } 57 58 static bool exit_event_begin(struct perf_evsel *evsel, 59 struct perf_sample *sample, struct event_key *key) 60 { 61 if (kvm_exit_event(evsel)) { 62 exit_event_get_key(evsel, sample, key); 63 return true; 64 } 65 66 return false; 67 } 68 69 static bool kvm_entry_event(struct perf_evsel *evsel) 70 { 71 return !strcmp(evsel->name, "kvm:kvm_entry"); 72 } 73 74 static bool exit_event_end(struct perf_evsel *evsel, 75 struct perf_sample *sample __maybe_unused, 76 struct event_key *key __maybe_unused) 77 { 78 return kvm_entry_event(evsel); 79 } 80 81 struct exit_reasons_table { 82 unsigned long exit_code; 83 const char *reason; 84 }; 85 86 struct exit_reasons_table vmx_exit_reasons[] = { 87 VMX_EXIT_REASONS 88 }; 89 90 struct exit_reasons_table svm_exit_reasons[] = { 91 SVM_EXIT_REASONS 92 }; 93 94 static int cpu_isa; 95 96 static const char *get_exit_reason(u64 exit_code) 97 { 98 int table_size = ARRAY_SIZE(svm_exit_reasons); 99 struct exit_reasons_table *table = svm_exit_reasons; 100 101 if (cpu_isa == 1) { 102 table = vmx_exit_reasons; 103 table_size = ARRAY_SIZE(vmx_exit_reasons); 104 } 105 106 while (table_size--) { 107 if (table->exit_code == exit_code) 108 return table->reason; 109 table++; 110 } 111 112 pr_err("unknown kvm exit code:%lld on %s\n", 113 (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); 114 return "UNKNOWN"; 115 } 116 117 static void exit_event_decode_key(struct event_key *key, char decode[20]) 118 { 119 const char *exit_reason = get_exit_reason(key->key); 120 121 scnprintf(decode, 20, "%s", exit_reason); 122 } 123 124 static struct kvm_events_ops exit_events = { 125 .is_begin_event = exit_event_begin, 126 .is_end_event = exit_event_end, 127 .decode_key = exit_event_decode_key, 128 .name = "VM-EXIT" 129 }; 130 131 /* 132 * For the mmio events, we treat: 133 * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry 134 * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). 135 */ 136 static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample, 137 struct event_key *key) 138 { 139 key->key = perf_evsel__intval(evsel, sample, "gpa"); 140 key->info = perf_evsel__intval(evsel, sample, "type"); 141 } 142 143 #define KVM_TRACE_MMIO_READ_UNSATISFIED 0 144 #define KVM_TRACE_MMIO_READ 1 145 #define KVM_TRACE_MMIO_WRITE 2 146 147 static bool mmio_event_begin(struct perf_evsel *evsel, 148 struct perf_sample *sample, struct event_key *key) 149 { 150 /* MMIO read begin event in kernel. */ 151 if (kvm_exit_event(evsel)) 152 return true; 153 154 /* MMIO write begin event in kernel. */ 155 if (!strcmp(evsel->name, "kvm:kvm_mmio") && 156 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) { 157 mmio_event_get_key(evsel, sample, key); 158 return true; 159 } 160 161 return false; 162 } 163 164 static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample, 165 struct event_key *key) 166 { 167 /* MMIO write end event in kernel. */ 168 if (kvm_entry_event(evsel)) 169 return true; 170 171 /* MMIO read end event in kernel.*/ 172 if (!strcmp(evsel->name, "kvm:kvm_mmio") && 173 perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) { 174 mmio_event_get_key(evsel, sample, key); 175 return true; 176 } 177 178 return false; 179 } 180 181 static void mmio_event_decode_key(struct event_key *key, char decode[20]) 182 { 183 scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, 184 key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); 185 } 186 187 static struct kvm_events_ops mmio_events = { 188 .is_begin_event = mmio_event_begin, 189 .is_end_event = mmio_event_end, 190 .decode_key = mmio_event_decode_key, 191 .name = "MMIO Access" 192 }; 193 194 /* The time of emulation pio access is from kvm_pio to kvm_entry. */ 195 static void ioport_event_get_key(struct perf_evsel *evsel, 196 struct perf_sample *sample, 197 struct event_key *key) 198 { 199 key->key = perf_evsel__intval(evsel, sample, "port"); 200 key->info = perf_evsel__intval(evsel, sample, "rw"); 201 } 202 203 static bool ioport_event_begin(struct perf_evsel *evsel, 204 struct perf_sample *sample, 205 struct event_key *key) 206 { 207 if (!strcmp(evsel->name, "kvm:kvm_pio")) { 208 ioport_event_get_key(evsel, sample, key); 209 return true; 210 } 211 212 return false; 213 } 214 215 static bool ioport_event_end(struct perf_evsel *evsel, 216 struct perf_sample *sample __maybe_unused, 217 struct event_key *key __maybe_unused) 218 { 219 return kvm_entry_event(evsel); 220 } 221 222 static void ioport_event_decode_key(struct event_key *key, char decode[20]) 223 { 224 scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, 225 key->info ? "POUT" : "PIN"); 226 } 227 228 static struct kvm_events_ops ioport_events = { 229 .is_begin_event = ioport_event_begin, 230 .is_end_event = ioport_event_end, 231 .decode_key = ioport_event_decode_key, 232 .name = "IO Port Access" 233 }; 234 235 static const char *report_event = "vmexit"; 236 struct kvm_events_ops *events_ops; 237 238 static bool register_kvm_events_ops(void) 239 { 240 bool ret = true; 241 242 if (!strcmp(report_event, "vmexit")) 243 events_ops = &exit_events; 244 else if (!strcmp(report_event, "mmio")) 245 events_ops = &mmio_events; 246 else if (!strcmp(report_event, "ioport")) 247 events_ops = &ioport_events; 248 else { 249 pr_err("Unknown report event:%s\n", report_event); 250 ret = false; 251 } 252 253 return ret; 254 } 255 256 struct kvm_event_stats { 257 u64 time; 258 struct stats stats; 259 }; 260 261 struct kvm_event { 262 struct list_head hash_entry; 263 struct rb_node rb; 264 265 struct event_key key; 266 267 struct kvm_event_stats total; 268 269 #define DEFAULT_VCPU_NUM 8 270 int max_vcpu; 271 struct kvm_event_stats *vcpu; 272 }; 273 274 struct vcpu_event_record { 275 int vcpu_id; 276 u64 start_time; 277 struct kvm_event *last_event; 278 }; 279 280 #define EVENTS_BITS 12 281 #define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) 282 283 static u64 total_time; 284 static u64 total_count; 285 static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; 286 287 static void init_kvm_event_record(void) 288 { 289 int i; 290 291 for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) 292 INIT_LIST_HEAD(&kvm_events_cache[i]); 293 } 294 295 static int kvm_events_hash_fn(u64 key) 296 { 297 return key & (EVENTS_CACHE_SIZE - 1); 298 } 299 300 static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) 301 { 302 int old_max_vcpu = event->max_vcpu; 303 304 if (vcpu_id < event->max_vcpu) 305 return true; 306 307 while (event->max_vcpu <= vcpu_id) 308 event->max_vcpu += DEFAULT_VCPU_NUM; 309 310 event->vcpu = realloc(event->vcpu, 311 event->max_vcpu * sizeof(*event->vcpu)); 312 if (!event->vcpu) { 313 pr_err("Not enough memory\n"); 314 return false; 315 } 316 317 memset(event->vcpu + old_max_vcpu, 0, 318 (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu)); 319 return true; 320 } 321 322 static struct kvm_event *kvm_alloc_init_event(struct event_key *key) 323 { 324 struct kvm_event *event; 325 326 event = zalloc(sizeof(*event)); 327 if (!event) { 328 pr_err("Not enough memory\n"); 329 return NULL; 330 } 331 332 event->key = *key; 333 return event; 334 } 335 336 static struct kvm_event *find_create_kvm_event(struct event_key *key) 337 { 338 struct kvm_event *event; 339 struct list_head *head; 340 341 BUG_ON(key->key == INVALID_KEY); 342 343 head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; 344 list_for_each_entry(event, head, hash_entry) 345 if (event->key.key == key->key && event->key.info == key->info) 346 return event; 347 348 event = kvm_alloc_init_event(key); 349 if (!event) 350 return NULL; 351 352 list_add(&event->hash_entry, head); 353 return event; 354 } 355 356 static bool handle_begin_event(struct vcpu_event_record *vcpu_record, 357 struct event_key *key, u64 timestamp) 358 { 359 struct kvm_event *event = NULL; 360 361 if (key->key != INVALID_KEY) 362 event = find_create_kvm_event(key); 363 364 vcpu_record->last_event = event; 365 vcpu_record->start_time = timestamp; 366 return true; 367 } 368 369 static void 370 kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff) 371 { 372 kvm_stats->time += time_diff; 373 update_stats(&kvm_stats->stats, time_diff); 374 } 375 376 static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event) 377 { 378 struct kvm_event_stats *kvm_stats = &event->total; 379 380 if (vcpu_id != -1) 381 kvm_stats = &event->vcpu[vcpu_id]; 382 383 return rel_stddev_stats(stddev_stats(&kvm_stats->stats), 384 avg_stats(&kvm_stats->stats)); 385 } 386 387 static bool update_kvm_event(struct kvm_event *event, int vcpu_id, 388 u64 time_diff) 389 { 390 kvm_update_event_stats(&event->total, time_diff); 391 392 if (!kvm_event_expand(event, vcpu_id)) 393 return false; 394 395 kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff); 396 return true; 397 } 398 399 static bool handle_end_event(struct vcpu_event_record *vcpu_record, 400 struct event_key *key, u64 timestamp) 401 { 402 struct kvm_event *event; 403 u64 time_begin, time_diff; 404 405 event = vcpu_record->last_event; 406 time_begin = vcpu_record->start_time; 407 408 /* The begin event is not caught. */ 409 if (!time_begin) 410 return true; 411 412 /* 413 * In some case, the 'begin event' only records the start timestamp, 414 * the actual event is recognized in the 'end event' (e.g. mmio-event). 415 */ 416 417 /* Both begin and end events did not get the key. */ 418 if (!event && key->key == INVALID_KEY) 419 return true; 420 421 if (!event) 422 event = find_create_kvm_event(key); 423 424 if (!event) 425 return false; 426 427 vcpu_record->last_event = NULL; 428 vcpu_record->start_time = 0; 429 430 BUG_ON(timestamp < time_begin); 431 432 time_diff = timestamp - time_begin; 433 return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); 434 } 435 436 static 437 struct vcpu_event_record *per_vcpu_record(struct thread *thread, 438 struct perf_evsel *evsel, 439 struct perf_sample *sample) 440 { 441 /* Only kvm_entry records vcpu id. */ 442 if (!thread->priv && kvm_entry_event(evsel)) { 443 struct vcpu_event_record *vcpu_record; 444 445 vcpu_record = zalloc(sizeof(*vcpu_record)); 446 if (!vcpu_record) { 447 pr_err("%s: Not enough memory\n", __func__); 448 return NULL; 449 } 450 451 vcpu_record->vcpu_id = perf_evsel__intval(evsel, sample, "vcpu_id"); 452 thread->priv = vcpu_record; 453 } 454 455 return thread->priv; 456 } 457 458 static bool handle_kvm_event(struct thread *thread, struct perf_evsel *evsel, 459 struct perf_sample *sample) 460 { 461 struct vcpu_event_record *vcpu_record; 462 struct event_key key = {.key = INVALID_KEY}; 463 464 vcpu_record = per_vcpu_record(thread, evsel, sample); 465 if (!vcpu_record) 466 return true; 467 468 if (events_ops->is_begin_event(evsel, sample, &key)) 469 return handle_begin_event(vcpu_record, &key, sample->time); 470 471 if (events_ops->is_end_event(evsel, sample, &key)) 472 return handle_end_event(vcpu_record, &key, sample->time); 473 474 return true; 475 } 476 477 typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); 478 struct kvm_event_key { 479 const char *name; 480 key_cmp_fun key; 481 }; 482 483 static int trace_vcpu = -1; 484 #define GET_EVENT_KEY(func, field) \ 485 static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ 486 { \ 487 if (vcpu == -1) \ 488 return event->total.field; \ 489 \ 490 if (vcpu >= event->max_vcpu) \ 491 return 0; \ 492 \ 493 return event->vcpu[vcpu].field; \ 494 } 495 496 #define COMPARE_EVENT_KEY(func, field) \ 497 GET_EVENT_KEY(func, field) \ 498 static int compare_kvm_event_ ## func(struct kvm_event *one, \ 499 struct kvm_event *two, int vcpu)\ 500 { \ 501 return get_event_ ##func(one, vcpu) > \ 502 get_event_ ##func(two, vcpu); \ 503 } 504 505 GET_EVENT_KEY(time, time); 506 COMPARE_EVENT_KEY(count, stats.n); 507 COMPARE_EVENT_KEY(mean, stats.mean); 508 509 #define DEF_SORT_NAME_KEY(name, compare_key) \ 510 { #name, compare_kvm_event_ ## compare_key } 511 512 static struct kvm_event_key keys[] = { 513 DEF_SORT_NAME_KEY(sample, count), 514 DEF_SORT_NAME_KEY(time, mean), 515 { NULL, NULL } 516 }; 517 518 static const char *sort_key = "sample"; 519 static key_cmp_fun compare; 520 521 static bool select_key(void) 522 { 523 int i; 524 525 for (i = 0; keys[i].name; i++) { 526 if (!strcmp(keys[i].name, sort_key)) { 527 compare = keys[i].key; 528 return true; 529 } 530 } 531 532 pr_err("Unknown compare key:%s\n", sort_key); 533 return false; 534 } 535 536 static struct rb_root result; 537 static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, 538 int vcpu) 539 { 540 struct rb_node **rb = &result.rb_node; 541 struct rb_node *parent = NULL; 542 struct kvm_event *p; 543 544 while (*rb) { 545 p = container_of(*rb, struct kvm_event, rb); 546 parent = *rb; 547 548 if (bigger(event, p, vcpu)) 549 rb = &(*rb)->rb_left; 550 else 551 rb = &(*rb)->rb_right; 552 } 553 554 rb_link_node(&event->rb, parent, rb); 555 rb_insert_color(&event->rb, &result); 556 } 557 558 static void update_total_count(struct kvm_event *event, int vcpu) 559 { 560 total_count += get_event_count(event, vcpu); 561 total_time += get_event_time(event, vcpu); 562 } 563 564 static bool event_is_valid(struct kvm_event *event, int vcpu) 565 { 566 return !!get_event_count(event, vcpu); 567 } 568 569 static void sort_result(int vcpu) 570 { 571 unsigned int i; 572 struct kvm_event *event; 573 574 for (i = 0; i < EVENTS_CACHE_SIZE; i++) 575 list_for_each_entry(event, &kvm_events_cache[i], hash_entry) 576 if (event_is_valid(event, vcpu)) { 577 update_total_count(event, vcpu); 578 insert_to_result(event, compare, vcpu); 579 } 580 } 581 582 /* returns left most element of result, and erase it */ 583 static struct kvm_event *pop_from_result(void) 584 { 585 struct rb_node *node = rb_first(&result); 586 587 if (!node) 588 return NULL; 589 590 rb_erase(node, &result); 591 return container_of(node, struct kvm_event, rb); 592 } 593 594 static void print_vcpu_info(int vcpu) 595 { 596 pr_info("Analyze events for "); 597 598 if (vcpu == -1) 599 pr_info("all VCPUs:\n\n"); 600 else 601 pr_info("VCPU %d:\n\n", vcpu); 602 } 603 604 static void print_result(int vcpu) 605 { 606 char decode[20]; 607 struct kvm_event *event; 608 609 pr_info("\n\n"); 610 print_vcpu_info(vcpu); 611 pr_info("%20s ", events_ops->name); 612 pr_info("%10s ", "Samples"); 613 pr_info("%9s ", "Samples%"); 614 615 pr_info("%9s ", "Time%"); 616 pr_info("%16s ", "Avg time"); 617 pr_info("\n\n"); 618 619 while ((event = pop_from_result())) { 620 u64 ecount, etime; 621 622 ecount = get_event_count(event, vcpu); 623 etime = get_event_time(event, vcpu); 624 625 events_ops->decode_key(&event->key, decode); 626 pr_info("%20s ", decode); 627 pr_info("%10llu ", (unsigned long long)ecount); 628 pr_info("%8.2f%% ", (double)ecount / total_count * 100); 629 pr_info("%8.2f%% ", (double)etime / total_time * 100); 630 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, 631 kvm_event_rel_stddev(vcpu, event)); 632 pr_info("\n"); 633 } 634 635 pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", 636 (unsigned long long)total_count, total_time / 1e3); 637 } 638 639 static int process_sample_event(struct perf_tool *tool __maybe_unused, 640 union perf_event *event, 641 struct perf_sample *sample, 642 struct perf_evsel *evsel, 643 struct machine *machine) 644 { 645 struct thread *thread = machine__findnew_thread(machine, sample->tid); 646 647 if (thread == NULL) { 648 pr_debug("problem processing %d event, skipping it.\n", 649 event->header.type); 650 return -1; 651 } 652 653 if (!handle_kvm_event(thread, evsel, sample)) 654 return -1; 655 656 return 0; 657 } 658 659 static struct perf_tool eops = { 660 .sample = process_sample_event, 661 .comm = perf_event__process_comm, 662 .ordered_samples = true, 663 }; 664 665 static int get_cpu_isa(struct perf_session *session) 666 { 667 char *cpuid = session->header.env.cpuid; 668 int isa; 669 670 if (strstr(cpuid, "Intel")) 671 isa = 1; 672 else if (strstr(cpuid, "AMD")) 673 isa = 0; 674 else { 675 pr_err("CPU %s is not supported.\n", cpuid); 676 isa = -ENOTSUP; 677 } 678 679 return isa; 680 } 681 682 static const char *file_name; 683 684 static int read_events(void) 685 { 686 struct perf_session *kvm_session; 687 int ret; 688 689 kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); 690 if (!kvm_session) { 691 pr_err("Initializing perf session failed\n"); 692 return -EINVAL; 693 } 694 695 if (!perf_session__has_traces(kvm_session, "kvm record")) 696 return -EINVAL; 697 698 /* 699 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not 700 * traced in the old kernel. 701 */ 702 ret = get_cpu_isa(kvm_session); 703 704 if (ret < 0) 705 return ret; 706 707 cpu_isa = ret; 708 709 return perf_session__process_events(kvm_session, &eops); 710 } 711 712 static bool verify_vcpu(int vcpu) 713 { 714 if (vcpu != -1 && vcpu < 0) { 715 pr_err("Invalid vcpu:%d.\n", vcpu); 716 return false; 717 } 718 719 return true; 720 } 721 722 static int kvm_events_report_vcpu(int vcpu) 723 { 724 int ret = -EINVAL; 725 726 if (!verify_vcpu(vcpu)) 727 goto exit; 728 729 if (!select_key()) 730 goto exit; 731 732 if (!register_kvm_events_ops()) 733 goto exit; 734 735 init_kvm_event_record(); 736 setup_pager(); 737 738 ret = read_events(); 739 if (ret) 740 goto exit; 741 742 sort_result(vcpu); 743 print_result(vcpu); 744 exit: 745 return ret; 746 } 747 748 static const char * const record_args[] = { 749 "record", 750 "-R", 751 "-f", 752 "-m", "1024", 753 "-c", "1", 754 "-e", "kvm:kvm_entry", 755 "-e", "kvm:kvm_exit", 756 "-e", "kvm:kvm_mmio", 757 "-e", "kvm:kvm_pio", 758 }; 759 760 #define STRDUP_FAIL_EXIT(s) \ 761 ({ char *_p; \ 762 _p = strdup(s); \ 763 if (!_p) \ 764 return -ENOMEM; \ 765 _p; \ 766 }) 767 768 static int kvm_events_record(int argc, const char **argv) 769 { 770 unsigned int rec_argc, i, j; 771 const char **rec_argv; 772 773 rec_argc = ARRAY_SIZE(record_args) + argc + 2; 774 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 775 776 if (rec_argv == NULL) 777 return -ENOMEM; 778 779 for (i = 0; i < ARRAY_SIZE(record_args); i++) 780 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); 781 782 rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); 783 rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); 784 785 for (j = 1; j < (unsigned int)argc; j++, i++) 786 rec_argv[i] = argv[j]; 787 788 return cmd_record(i, rec_argv, NULL); 789 } 790 791 static const char * const kvm_events_report_usage[] = { 792 "perf kvm stat report [<options>]", 793 NULL 794 }; 795 796 static const struct option kvm_events_report_options[] = { 797 OPT_STRING(0, "event", &report_event, "report event", 798 "event for reporting: vmexit, mmio, ioport"), 799 OPT_INTEGER(0, "vcpu", &trace_vcpu, 800 "vcpu id to report"), 801 OPT_STRING('k', "key", &sort_key, "sort-key", 802 "key for sorting: sample(sort by samples number)" 803 " time (sort by avg time)"), 804 OPT_END() 805 }; 806 807 static int kvm_events_report(int argc, const char **argv) 808 { 809 symbol__init(); 810 811 if (argc) { 812 argc = parse_options(argc, argv, 813 kvm_events_report_options, 814 kvm_events_report_usage, 0); 815 if (argc) 816 usage_with_options(kvm_events_report_usage, 817 kvm_events_report_options); 818 } 819 820 return kvm_events_report_vcpu(trace_vcpu); 821 } 822 823 static void print_kvm_stat_usage(void) 824 { 825 printf("Usage: perf kvm stat <command>\n\n"); 826 827 printf("# Available commands:\n"); 828 printf("\trecord: record kvm events\n"); 829 printf("\treport: report statistical data of kvm events\n"); 830 831 printf("\nOtherwise, it is the alias of 'perf stat':\n"); 832 } 833 834 static int kvm_cmd_stat(int argc, const char **argv) 835 { 836 if (argc == 1) { 837 print_kvm_stat_usage(); 838 goto perf_stat; 839 } 840 841 if (!strncmp(argv[1], "rec", 3)) 842 return kvm_events_record(argc - 1, argv + 1); 843 844 if (!strncmp(argv[1], "rep", 3)) 845 return kvm_events_report(argc - 1 , argv + 1); 846 847 perf_stat: 848 return cmd_stat(argc, argv, NULL); 849 } 850 851 static char name_buffer[256]; 852 853 static const char * const kvm_usage[] = { 854 "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", 855 NULL 856 }; 857 858 static const struct option kvm_options[] = { 859 OPT_STRING('i', "input", &file_name, "file", 860 "Input file name"), 861 OPT_STRING('o', "output", &file_name, "file", 862 "Output file name"), 863 OPT_BOOLEAN(0, "guest", &perf_guest, 864 "Collect guest os data"), 865 OPT_BOOLEAN(0, "host", &perf_host, 866 "Collect host os data"), 867 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", 868 "guest mount directory under which every guest os" 869 " instance has a subdir"), 870 OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name, 871 "file", "file saving guest os vmlinux"), 872 OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms, 873 "file", "file saving guest os /proc/kallsyms"), 874 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules, 875 "file", "file saving guest os /proc/modules"), 876 OPT_END() 877 }; 878 879 static int __cmd_record(int argc, const char **argv) 880 { 881 int rec_argc, i = 0, j; 882 const char **rec_argv; 883 884 rec_argc = argc + 2; 885 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 886 rec_argv[i++] = strdup("record"); 887 rec_argv[i++] = strdup("-o"); 888 rec_argv[i++] = strdup(file_name); 889 for (j = 1; j < argc; j++, i++) 890 rec_argv[i] = argv[j]; 891 892 BUG_ON(i != rec_argc); 893 894 return cmd_record(i, rec_argv, NULL); 895 } 896 897 static int __cmd_report(int argc, const char **argv) 898 { 899 int rec_argc, i = 0, j; 900 const char **rec_argv; 901 902 rec_argc = argc + 2; 903 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 904 rec_argv[i++] = strdup("report"); 905 rec_argv[i++] = strdup("-i"); 906 rec_argv[i++] = strdup(file_name); 907 for (j = 1; j < argc; j++, i++) 908 rec_argv[i] = argv[j]; 909 910 BUG_ON(i != rec_argc); 911 912 return cmd_report(i, rec_argv, NULL); 913 } 914 915 static int __cmd_buildid_list(int argc, const char **argv) 916 { 917 int rec_argc, i = 0, j; 918 const char **rec_argv; 919 920 rec_argc = argc + 2; 921 rec_argv = calloc(rec_argc + 1, sizeof(char *)); 922 rec_argv[i++] = strdup("buildid-list"); 923 rec_argv[i++] = strdup("-i"); 924 rec_argv[i++] = strdup(file_name); 925 for (j = 1; j < argc; j++, i++) 926 rec_argv[i] = argv[j]; 927 928 BUG_ON(i != rec_argc); 929 930 return cmd_buildid_list(i, rec_argv, NULL); 931 } 932 933 int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) 934 { 935 perf_host = 0; 936 perf_guest = 1; 937 938 argc = parse_options(argc, argv, kvm_options, kvm_usage, 939 PARSE_OPT_STOP_AT_NON_OPTION); 940 if (!argc) 941 usage_with_options(kvm_usage, kvm_options); 942 943 if (!perf_host) 944 perf_guest = 1; 945 946 if (!file_name) { 947 if (perf_host && !perf_guest) 948 sprintf(name_buffer, "perf.data.host"); 949 else if (!perf_host && perf_guest) 950 sprintf(name_buffer, "perf.data.guest"); 951 else 952 sprintf(name_buffer, "perf.data.kvm"); 953 file_name = name_buffer; 954 } 955 956 if (!strncmp(argv[0], "rec", 3)) 957 return __cmd_record(argc, argv); 958 else if (!strncmp(argv[0], "rep", 3)) 959 return __cmd_report(argc, argv); 960 else if (!strncmp(argv[0], "diff", 4)) 961 return cmd_diff(argc, argv, NULL); 962 else if (!strncmp(argv[0], "top", 3)) 963 return cmd_top(argc, argv, NULL); 964 else if (!strncmp(argv[0], "buildid-list", 12)) 965 return __cmd_buildid_list(argc, argv); 966 else if (!strncmp(argv[0], "stat", 4)) 967 return kvm_cmd_stat(argc, argv); 968 else 969 usage_with_options(kvm_usage, kvm_options); 970 971 return 0; 972 } 973