2192 lines · c
1// SPDX-License-Identifier: GPL-2.02#include "builtin.h"3#include "perf.h"4 5#include "util/build-id.h"6#include "util/evsel.h"7#include "util/evlist.h"8#include "util/mmap.h"9#include "util/term.h"10#include "util/symbol.h"11#include "util/thread.h"12#include "util/header.h"13#include "util/session.h"14#include "util/intlist.h"15#include <subcmd/pager.h>16#include <subcmd/parse-options.h>17#include "util/trace-event.h"18#include "util/debug.h"19#include "util/tool.h"20#include "util/stat.h"21#include "util/synthetic-events.h"22#include "util/top.h"23#include "util/data.h"24#include "util/ordered-events.h"25#include "util/kvm-stat.h"26#include "util/util.h"27#include "ui/browsers/hists.h"28#include "ui/progress.h"29#include "ui/ui.h"30#include "util/string2.h"31 32#include <sys/prctl.h>33#ifdef HAVE_TIMERFD_SUPPORT34#include <sys/timerfd.h>35#endif36#include <sys/time.h>37#include <sys/types.h>38#include <sys/stat.h>39#include <fcntl.h>40 41#include <linux/err.h>42#include <linux/kernel.h>43#include <linux/string.h>44#include <linux/time64.h>45#include <linux/zalloc.h>46#include <errno.h>47#include <inttypes.h>48#include <poll.h>49#include <termios.h>50#include <semaphore.h>51#include <signal.h>52#include <math.h>53#include <perf/mmap.h>54 55#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)56#define GET_EVENT_KEY(func, field) \57static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \58{ \59 if (vcpu == -1) \60 return event->total.field; \61 \62 if (vcpu >= event->max_vcpu) \63 return 0; \64 \65 return event->vcpu[vcpu].field; \66}67 68#define COMPARE_EVENT_KEY(func, field) \69GET_EVENT_KEY(func, field) \70static int64_t cmp_event_ ## func(struct kvm_event *one, \71 struct kvm_event *two, int vcpu) \72{ \73 return get_event_ ##func(one, vcpu) - \74 get_event_ ##func(two, vcpu); \75}76 77COMPARE_EVENT_KEY(time, time);78COMPARE_EVENT_KEY(max, stats.max);79COMPARE_EVENT_KEY(min, stats.min);80COMPARE_EVENT_KEY(count, stats.n);81COMPARE_EVENT_KEY(mean, stats.mean);82 83struct kvm_hists {84 struct hists hists;85 struct perf_hpp_list list;86};87 88struct kvm_dimension {89 const char *name;90 const char *header;91 int width;92 int64_t (*cmp)(struct perf_hpp_fmt *fmt, struct hist_entry *left,93 struct hist_entry *right);94 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,95 struct hist_entry *he);96};97 98struct kvm_fmt {99 struct perf_hpp_fmt fmt;100 struct kvm_dimension *dim;101};102 103static struct kvm_hists kvm_hists;104 105static int64_t ev_name_cmp(struct perf_hpp_fmt *fmt __maybe_unused,106 struct hist_entry *left,107 struct hist_entry *right)108{109 /* Return opposite number for sorting in alphabetical order */110 return -strcmp(left->kvm_info->name, right->kvm_info->name);111}112 113static int fmt_width(struct perf_hpp_fmt *fmt,114 struct perf_hpp *hpp __maybe_unused,115 struct hists *hists __maybe_unused);116 117static int ev_name_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,118 struct hist_entry *he)119{120 int width = fmt_width(fmt, hpp, he->hists);121 122 return scnprintf(hpp->buf, hpp->size, "%*s", width, he->kvm_info->name);123}124 125static struct kvm_dimension dim_event = {126 .header = "Event name",127 .name = "ev_name",128 .cmp = ev_name_cmp,129 .entry = ev_name_entry,130 .width = 40,131};132 133#define EV_METRIC_CMP(metric) \134static int64_t ev_cmp_##metric(struct perf_hpp_fmt *fmt __maybe_unused, \135 struct hist_entry *left, \136 struct hist_entry *right) \137{ \138 struct kvm_event *event_left; \139 struct kvm_event *event_right; \140 struct perf_kvm_stat *perf_kvm; \141 \142 event_left = container_of(left, struct kvm_event, he); \143 event_right = container_of(right, struct kvm_event, he); \144 \145 perf_kvm = event_left->perf_kvm; \146 return cmp_event_##metric(event_left, event_right, \147 perf_kvm->trace_vcpu); \148}149 150EV_METRIC_CMP(time)151EV_METRIC_CMP(count)152EV_METRIC_CMP(max)153EV_METRIC_CMP(min)154EV_METRIC_CMP(mean)155 156#define EV_METRIC_ENTRY(metric) \157static int ev_entry_##metric(struct perf_hpp_fmt *fmt, \158 struct perf_hpp *hpp, \159 struct hist_entry *he) \160{ \161 struct kvm_event *event; \162 int width = fmt_width(fmt, hpp, he->hists); \163 struct perf_kvm_stat *perf_kvm; \164 \165 event = container_of(he, struct kvm_event, he); \166 perf_kvm = event->perf_kvm; \167 return scnprintf(hpp->buf, hpp->size, "%*lu", width, \168 get_event_##metric(event, perf_kvm->trace_vcpu)); \169}170 171EV_METRIC_ENTRY(time)172EV_METRIC_ENTRY(count)173EV_METRIC_ENTRY(max)174EV_METRIC_ENTRY(min)175 176static struct kvm_dimension dim_time = {177 .header = "Time (ns)",178 .name = "time",179 .cmp = ev_cmp_time,180 .entry = ev_entry_time,181 .width = 12,182};183 184static struct kvm_dimension dim_count = {185 .header = "Samples",186 .name = "sample",187 .cmp = ev_cmp_count,188 .entry = ev_entry_count,189 .width = 12,190};191 192static struct kvm_dimension dim_max_time = {193 .header = "Max Time (ns)",194 .name = "max_t",195 .cmp = ev_cmp_max,196 .entry = ev_entry_max,197 .width = 14,198};199 200static struct kvm_dimension dim_min_time = {201 .header = "Min Time (ns)",202 .name = "min_t",203 .cmp = ev_cmp_min,204 .entry = ev_entry_min,205 .width = 14,206};207 208static int ev_entry_mean(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,209 struct hist_entry *he)210{211 struct kvm_event *event;212 int width = fmt_width(fmt, hpp, he->hists);213 struct perf_kvm_stat *perf_kvm;214 215 event = container_of(he, struct kvm_event, he);216 perf_kvm = event->perf_kvm;217 return scnprintf(hpp->buf, hpp->size, "%*lu", width,218 get_event_mean(event, perf_kvm->trace_vcpu));219}220 221static struct kvm_dimension dim_mean_time = {222 .header = "Mean Time (ns)",223 .name = "mean_t",224 .cmp = ev_cmp_mean,225 .entry = ev_entry_mean,226 .width = 14,227};228 229#define PERC_STR(__s, __v) \230({ \231 scnprintf(__s, sizeof(__s), "%.2F%%", __v); \232 __s; \233})234 235static double percent(u64 st, u64 tot)236{237 return tot ? 100. * (double) st / (double) tot : 0;238}239 240#define EV_METRIC_PERCENT(metric) \241static int ev_percent_##metric(struct hist_entry *he) \242{ \243 struct kvm_event *event; \244 struct perf_kvm_stat *perf_kvm; \245 \246 event = container_of(he, struct kvm_event, he); \247 perf_kvm = event->perf_kvm; \248 \249 return percent(get_event_##metric(event, perf_kvm->trace_vcpu), \250 perf_kvm->total_##metric); \251}252 253EV_METRIC_PERCENT(time)254EV_METRIC_PERCENT(count)255 256static int ev_entry_time_precent(struct perf_hpp_fmt *fmt,257 struct perf_hpp *hpp,258 struct hist_entry *he)259{260 int width = fmt_width(fmt, hpp, he->hists);261 double per;262 char buf[10];263 264 per = ev_percent_time(he);265 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));266}267 268static int64_t269ev_cmp_time_precent(struct perf_hpp_fmt *fmt __maybe_unused,270 struct hist_entry *left, struct hist_entry *right)271{272 double per_left;273 double per_right;274 275 per_left = ev_percent_time(left);276 per_right = ev_percent_time(right);277 278 return per_left - per_right;279}280 281static struct kvm_dimension dim_time_percent = {282 .header = "Time%",283 .name = "percent_time",284 .cmp = ev_cmp_time_precent,285 .entry = ev_entry_time_precent,286 .width = 12,287};288 289static int ev_entry_count_precent(struct perf_hpp_fmt *fmt,290 struct perf_hpp *hpp,291 struct hist_entry *he)292{293 int width = fmt_width(fmt, hpp, he->hists);294 double per;295 char buf[10];296 297 per = ev_percent_count(he);298 return scnprintf(hpp->buf, hpp->size, "%*s", width, PERC_STR(buf, per));299}300 301static int64_t302ev_cmp_count_precent(struct perf_hpp_fmt *fmt __maybe_unused,303 struct hist_entry *left, struct hist_entry *right)304{305 double per_left;306 double per_right;307 308 per_left = ev_percent_count(left);309 per_right = ev_percent_count(right);310 311 return per_left - per_right;312}313 314static struct kvm_dimension dim_count_percent = {315 .header = "Sample%",316 .name = "percent_sample",317 .cmp = ev_cmp_count_precent,318 .entry = ev_entry_count_precent,319 .width = 12,320};321 322static struct kvm_dimension *dimensions[] = {323 &dim_event,324 &dim_time,325 &dim_time_percent,326 &dim_count,327 &dim_count_percent,328 &dim_max_time,329 &dim_min_time,330 &dim_mean_time,331 NULL,332};333 334static int fmt_width(struct perf_hpp_fmt *fmt,335 struct perf_hpp *hpp __maybe_unused,336 struct hists *hists __maybe_unused)337{338 struct kvm_fmt *kvm_fmt;339 340 kvm_fmt = container_of(fmt, struct kvm_fmt, fmt);341 return kvm_fmt->dim->width;342}343 344static int fmt_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,345 struct hists *hists, int line __maybe_unused,346 int *span __maybe_unused)347{348 struct kvm_fmt *kvm_fmt;349 struct kvm_dimension *dim;350 int width = fmt_width(fmt, hpp, hists);351 352 kvm_fmt = container_of(fmt, struct kvm_fmt, fmt);353 dim = kvm_fmt->dim;354 355 return scnprintf(hpp->buf, hpp->size, "%*s", width, dim->header);356}357 358static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)359{360 struct kvm_fmt *kvm_fmt_a = container_of(a, struct kvm_fmt, fmt);361 struct kvm_fmt *kvm_fmt_b = container_of(b, struct kvm_fmt, fmt);362 363 return kvm_fmt_a->dim == kvm_fmt_b->dim;364}365 366static void fmt_free(struct perf_hpp_fmt *fmt)367{368 struct kvm_fmt *kvm_fmt;369 370 kvm_fmt = container_of(fmt, struct kvm_fmt, fmt);371 free(kvm_fmt);372}373 374static struct kvm_dimension *get_dimension(const char *name)375{376 unsigned int i;377 378 for (i = 0; dimensions[i] != NULL; i++) {379 if (!strcmp(dimensions[i]->name, name))380 return dimensions[i];381 }382 383 return NULL;384}385 386static struct kvm_fmt *get_format(const char *name)387{388 struct kvm_dimension *dim = get_dimension(name);389 struct kvm_fmt *kvm_fmt;390 struct perf_hpp_fmt *fmt;391 392 if (!dim)393 return NULL;394 395 kvm_fmt = zalloc(sizeof(*kvm_fmt));396 if (!kvm_fmt)397 return NULL;398 399 kvm_fmt->dim = dim;400 401 fmt = &kvm_fmt->fmt;402 INIT_LIST_HEAD(&fmt->list);403 INIT_LIST_HEAD(&fmt->sort_list);404 fmt->cmp = dim->cmp;405 fmt->sort = dim->cmp;406 fmt->color = NULL;407 fmt->entry = dim->entry;408 fmt->header = fmt_header;409 fmt->width = fmt_width;410 fmt->collapse = dim->cmp;411 fmt->equal = fmt_equal;412 fmt->free = fmt_free;413 414 return kvm_fmt;415}416 417static int kvm_hists__init_output(struct perf_hpp_list *hpp_list, char *name)418{419 struct kvm_fmt *kvm_fmt = get_format(name);420 421 if (!kvm_fmt) {422 pr_warning("Fail to find format for output field %s.\n", name);423 return -EINVAL;424 }425 426 perf_hpp_list__column_register(hpp_list, &kvm_fmt->fmt);427 return 0;428}429 430static int kvm_hists__init_sort(struct perf_hpp_list *hpp_list, char *name)431{432 struct kvm_fmt *kvm_fmt = get_format(name);433 434 if (!kvm_fmt) {435 pr_warning("Fail to find format for sorting %s.\n", name);436 return -EINVAL;437 }438 439 perf_hpp_list__register_sort_field(hpp_list, &kvm_fmt->fmt);440 return 0;441}442 443static int kvm_hpp_list__init(char *list,444 struct perf_hpp_list *hpp_list,445 int (*fn)(struct perf_hpp_list *hpp_list,446 char *name))447{448 char *tmp, *tok;449 int ret;450 451 if (!list || !fn)452 return 0;453 454 for (tok = strtok_r(list, ", ", &tmp); tok;455 tok = strtok_r(NULL, ", ", &tmp)) {456 ret = fn(hpp_list, tok);457 if (!ret)458 continue;459 460 /* Handle errors */461 if (ret == -EINVAL)462 pr_err("Invalid field key: '%s'", tok);463 else if (ret == -ESRCH)464 pr_err("Unknown field key: '%s'", tok);465 else466 pr_err("Fail to initialize for field key: '%s'", tok);467 468 break;469 }470 471 return ret;472}473 474static int kvm_hpp_list__parse(struct perf_hpp_list *hpp_list,475 const char *output_, const char *sort_)476{477 char *output = output_ ? strdup(output_) : NULL;478 char *sort = sort_ ? strdup(sort_) : NULL;479 int ret;480 481 ret = kvm_hpp_list__init(output, hpp_list, kvm_hists__init_output);482 if (ret)483 goto out;484 485 ret = kvm_hpp_list__init(sort, hpp_list, kvm_hists__init_sort);486 if (ret)487 goto out;488 489 /* Copy sort keys to output fields */490 perf_hpp__setup_output_field(hpp_list);491 492 /* and then copy output fields to sort keys */493 perf_hpp__append_sort_keys(hpp_list);494out:495 free(output);496 free(sort);497 return ret;498}499 500static int kvm_hists__init(void)501{502 kvm_hists.list.nr_header_lines = 1;503 __hists__init(&kvm_hists.hists, &kvm_hists.list);504 perf_hpp_list__init(&kvm_hists.list);505 return kvm_hpp_list__parse(&kvm_hists.list, NULL, "ev_name");506}507 508static int kvm_hists__reinit(const char *output, const char *sort)509{510 perf_hpp__reset_output_field(&kvm_hists.list);511 return kvm_hpp_list__parse(&kvm_hists.list, output, sort);512}513static void print_result(struct perf_kvm_stat *kvm);514 515#ifdef HAVE_SLANG_SUPPORT516static void kvm_browser__update_nr_entries(struct hist_browser *hb)517{518 struct rb_node *nd = rb_first_cached(&hb->hists->entries);519 u64 nr_entries = 0;520 521 for (; nd; nd = rb_next(nd)) {522 struct hist_entry *he = rb_entry(nd, struct hist_entry,523 rb_node);524 525 if (!he->filtered)526 nr_entries++;527 }528 529 hb->nr_non_filtered_entries = nr_entries;530}531 532static int kvm_browser__title(struct hist_browser *browser,533 char *buf, size_t size)534{535 scnprintf(buf, size, "KVM event statistics (%lu entries)",536 browser->nr_non_filtered_entries);537 return 0;538}539 540static struct hist_browser*541perf_kvm_browser__new(struct hists *hists)542{543 struct hist_browser *browser = hist_browser__new(hists);544 545 if (browser)546 browser->title = kvm_browser__title;547 548 return browser;549}550 551static int kvm__hists_browse(struct hists *hists)552{553 struct hist_browser *browser;554 int key = -1;555 556 browser = perf_kvm_browser__new(hists);557 if (browser == NULL)558 return -1;559 560 /* reset abort key so that it can get Ctrl-C as a key */561 SLang_reset_tty();562 SLang_init_tty(0, 0, 0);563 564 kvm_browser__update_nr_entries(browser);565 566 while (1) {567 key = hist_browser__run(browser, "? - help", true, 0);568 569 switch (key) {570 case 'q':571 goto out;572 default:573 break;574 }575 }576 577out:578 hist_browser__delete(browser);579 return 0;580}581 582static void kvm_display(struct perf_kvm_stat *kvm)583{584 if (!use_browser)585 print_result(kvm);586 else587 kvm__hists_browse(&kvm_hists.hists);588}589 590#else591 592static void kvm_display(struct perf_kvm_stat *kvm)593{594 use_browser = 0;595 print_result(kvm);596}597 598#endif /* HAVE_SLANG_SUPPORT */599 600#endif // defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)601 602static const char *get_filename_for_perf_kvm(void)603{604 const char *filename;605 606 if (perf_host && !perf_guest)607 filename = strdup("perf.data.host");608 else if (!perf_host && perf_guest)609 filename = strdup("perf.data.guest");610 else611 filename = strdup("perf.data.kvm");612 613 return filename;614}615 616#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)617 618void exit_event_get_key(struct evsel *evsel,619 struct perf_sample *sample,620 struct event_key *key)621{622 key->info = 0;623 key->key = evsel__intval(evsel, sample, kvm_exit_reason);624}625 626bool kvm_exit_event(struct evsel *evsel)627{628 return evsel__name_is(evsel, kvm_exit_trace);629}630 631bool exit_event_begin(struct evsel *evsel,632 struct perf_sample *sample, struct event_key *key)633{634 if (kvm_exit_event(evsel)) {635 exit_event_get_key(evsel, sample, key);636 return true;637 }638 639 return false;640}641 642bool kvm_entry_event(struct evsel *evsel)643{644 return evsel__name_is(evsel, kvm_entry_trace);645}646 647bool exit_event_end(struct evsel *evsel,648 struct perf_sample *sample __maybe_unused,649 struct event_key *key __maybe_unused)650{651 return kvm_entry_event(evsel);652}653 654static const char *get_exit_reason(struct perf_kvm_stat *kvm,655 struct exit_reasons_table *tbl,656 u64 exit_code)657{658 while (tbl->reason != NULL) {659 if (tbl->exit_code == exit_code)660 return tbl->reason;661 tbl++;662 }663 664 pr_err("unknown kvm exit code:%lld on %s\n",665 (unsigned long long)exit_code, kvm->exit_reasons_isa);666 return "UNKNOWN";667}668 669void exit_event_decode_key(struct perf_kvm_stat *kvm,670 struct event_key *key,671 char *decode)672{673 const char *exit_reason = get_exit_reason(kvm, key->exit_reasons,674 key->key);675 676 scnprintf(decode, KVM_EVENT_NAME_LEN, "%s", exit_reason);677}678 679static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)680{681 struct kvm_reg_events_ops *events_ops = kvm_reg_events_ops;682 683 for (events_ops = kvm_reg_events_ops; events_ops->name; events_ops++) {684 if (!strcmp(events_ops->name, kvm->report_event)) {685 kvm->events_ops = events_ops->ops;686 return true;687 }688 }689 690 return false;691}692 693struct vcpu_event_record {694 int vcpu_id;695 u64 start_time;696 struct kvm_event *last_event;697};698 699#ifdef HAVE_TIMERFD_SUPPORT700static void clear_events_cache_stats(void)701{702 struct rb_root_cached *root;703 struct rb_node *nd;704 struct kvm_event *event;705 int i;706 707 if (hists__has(&kvm_hists.hists, need_collapse))708 root = &kvm_hists.hists.entries_collapsed;709 else710 root = kvm_hists.hists.entries_in;711 712 for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) {713 struct hist_entry *he;714 715 he = rb_entry(nd, struct hist_entry, rb_node_in);716 event = container_of(he, struct kvm_event, he);717 718 /* reset stats for event */719 event->total.time = 0;720 init_stats(&event->total.stats);721 722 for (i = 0; i < event->max_vcpu; ++i) {723 event->vcpu[i].time = 0;724 init_stats(&event->vcpu[i].stats);725 }726 }727}728#endif729 730static bool kvm_event_expand(struct kvm_event *event, int vcpu_id)731{732 int old_max_vcpu = event->max_vcpu;733 void *prev;734 735 if (vcpu_id < event->max_vcpu)736 return true;737 738 while (event->max_vcpu <= vcpu_id)739 event->max_vcpu += DEFAULT_VCPU_NUM;740 741 prev = event->vcpu;742 event->vcpu = realloc(event->vcpu,743 event->max_vcpu * sizeof(*event->vcpu));744 if (!event->vcpu) {745 free(prev);746 pr_err("Not enough memory\n");747 return false;748 }749 750 memset(event->vcpu + old_max_vcpu, 0,751 (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu));752 return true;753}754 755static void *kvm_he_zalloc(size_t size)756{757 struct kvm_event *kvm_ev;758 759 kvm_ev = zalloc(size + sizeof(*kvm_ev));760 if (!kvm_ev)761 return NULL;762 763 init_stats(&kvm_ev->total.stats);764 hists__inc_nr_samples(&kvm_hists.hists, 0);765 return &kvm_ev->he;766}767 768static void kvm_he_free(void *he)769{770 struct kvm_event *kvm_ev;771 772 kvm_ev = container_of(he, struct kvm_event, he);773 free(kvm_ev);774}775 776static struct hist_entry_ops kvm_ev_entry_ops = {777 .new = kvm_he_zalloc,778 .free = kvm_he_free,779};780 781static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,782 struct event_key *key,783 struct perf_sample *sample)784{785 struct kvm_event *event;786 struct hist_entry *he;787 struct kvm_info *ki;788 789 BUG_ON(key->key == INVALID_KEY);790 791 ki = kvm_info__new();792 if (!ki) {793 pr_err("Failed to allocate kvm info\n");794 return NULL;795 }796 797 kvm->events_ops->decode_key(kvm, key, ki->name);798 he = hists__add_entry_ops(&kvm_hists.hists, &kvm_ev_entry_ops,799 &kvm->al, NULL, NULL, NULL, ki, sample, true);800 if (he == NULL) {801 pr_err("Failed to allocate hist entry\n");802 free(ki);803 return NULL;804 }805 806 event = container_of(he, struct kvm_event, he);807 if (!event->perf_kvm) {808 event->perf_kvm = kvm;809 event->key = *key;810 }811 812 return event;813}814 815static bool handle_begin_event(struct perf_kvm_stat *kvm,816 struct vcpu_event_record *vcpu_record,817 struct event_key *key,818 struct perf_sample *sample)819{820 struct kvm_event *event = NULL;821 822 if (key->key != INVALID_KEY)823 event = find_create_kvm_event(kvm, key, sample);824 825 vcpu_record->last_event = event;826 vcpu_record->start_time = sample->time;827 return true;828}829 830static void831kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff)832{833 kvm_stats->time += time_diff;834 update_stats(&kvm_stats->stats, time_diff);835}836 837static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event)838{839 struct kvm_event_stats *kvm_stats = &event->total;840 841 if (vcpu_id != -1)842 kvm_stats = &event->vcpu[vcpu_id];843 844 return rel_stddev_stats(stddev_stats(&kvm_stats->stats),845 avg_stats(&kvm_stats->stats));846}847 848static bool update_kvm_event(struct perf_kvm_stat *kvm,849 struct kvm_event *event, int vcpu_id,850 u64 time_diff)851{852 /* Update overall statistics */853 kvm->total_count++;854 kvm->total_time += time_diff;855 856 if (vcpu_id == -1) {857 kvm_update_event_stats(&event->total, time_diff);858 return true;859 }860 861 if (!kvm_event_expand(event, vcpu_id))862 return false;863 864 kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff);865 return true;866}867 868static bool is_child_event(struct perf_kvm_stat *kvm,869 struct evsel *evsel,870 struct perf_sample *sample,871 struct event_key *key)872{873 struct child_event_ops *child_ops;874 875 child_ops = kvm->events_ops->child_ops;876 877 if (!child_ops)878 return false;879 880 for (; child_ops->name; child_ops++) {881 if (evsel__name_is(evsel, child_ops->name)) {882 child_ops->get_key(evsel, sample, key);883 return true;884 }885 }886 887 return false;888}889 890static bool handle_child_event(struct perf_kvm_stat *kvm,891 struct vcpu_event_record *vcpu_record,892 struct event_key *key,893 struct perf_sample *sample)894{895 struct kvm_event *event = NULL;896 897 if (key->key != INVALID_KEY)898 event = find_create_kvm_event(kvm, key, sample);899 900 vcpu_record->last_event = event;901 902 return true;903}904 905static bool skip_event(const char *event)906{907 const char * const *skip_events;908 909 for (skip_events = kvm_skip_events; *skip_events; skip_events++)910 if (!strcmp(event, *skip_events))911 return true;912 913 return false;914}915 916static bool handle_end_event(struct perf_kvm_stat *kvm,917 struct vcpu_event_record *vcpu_record,918 struct event_key *key,919 struct perf_sample *sample)920{921 struct kvm_event *event;922 u64 time_begin, time_diff;923 int vcpu;924 925 if (kvm->trace_vcpu == -1)926 vcpu = -1;927 else928 vcpu = vcpu_record->vcpu_id;929 930 event = vcpu_record->last_event;931 time_begin = vcpu_record->start_time;932 933 /* The begin event is not caught. */934 if (!time_begin)935 return true;936 937 /*938 * In some case, the 'begin event' only records the start timestamp,939 * the actual event is recognized in the 'end event' (e.g. mmio-event).940 */941 942 /* Both begin and end events did not get the key. */943 if (!event && key->key == INVALID_KEY)944 return true;945 946 if (!event)947 event = find_create_kvm_event(kvm, key, sample);948 949 if (!event)950 return false;951 952 vcpu_record->last_event = NULL;953 vcpu_record->start_time = 0;954 955 /* seems to happen once in a while during live mode */956 if (sample->time < time_begin) {957 pr_debug("End time before begin time; skipping event.\n");958 return true;959 }960 961 time_diff = sample->time - time_begin;962 963 if (kvm->duration && time_diff > kvm->duration) {964 char decode[KVM_EVENT_NAME_LEN];965 966 kvm->events_ops->decode_key(kvm, &event->key, decode);967 if (!skip_event(decode)) {968 pr_info("%" PRIu64 " VM %d, vcpu %d: %s event took %" PRIu64 "usec\n",969 sample->time, sample->pid, vcpu_record->vcpu_id,970 decode, time_diff / NSEC_PER_USEC);971 }972 }973 974 return update_kvm_event(kvm, event, vcpu, time_diff);975}976 977static978struct vcpu_event_record *per_vcpu_record(struct thread *thread,979 struct evsel *evsel,980 struct perf_sample *sample)981{982 /* Only kvm_entry records vcpu id. */983 if (!thread__priv(thread) && kvm_entry_event(evsel)) {984 struct vcpu_event_record *vcpu_record;985 986 vcpu_record = zalloc(sizeof(*vcpu_record));987 if (!vcpu_record) {988 pr_err("%s: Not enough memory\n", __func__);989 return NULL;990 }991 992 vcpu_record->vcpu_id = evsel__intval(evsel, sample, vcpu_id_str);993 thread__set_priv(thread, vcpu_record);994 }995 996 return thread__priv(thread);997}998 999static bool handle_kvm_event(struct perf_kvm_stat *kvm,1000 struct thread *thread,1001 struct evsel *evsel,1002 struct perf_sample *sample)1003{1004 struct vcpu_event_record *vcpu_record;1005 struct event_key key = { .key = INVALID_KEY,1006 .exit_reasons = kvm->exit_reasons };1007 1008 vcpu_record = per_vcpu_record(thread, evsel, sample);1009 if (!vcpu_record)1010 return true;1011 1012 /* only process events for vcpus user cares about */1013 if ((kvm->trace_vcpu != -1) &&1014 (kvm->trace_vcpu != vcpu_record->vcpu_id))1015 return true;1016 1017 if (kvm->events_ops->is_begin_event(evsel, sample, &key))1018 return handle_begin_event(kvm, vcpu_record, &key, sample);1019 1020 if (is_child_event(kvm, evsel, sample, &key))1021 return handle_child_event(kvm, vcpu_record, &key, sample);1022 1023 if (kvm->events_ops->is_end_event(evsel, sample, &key))1024 return handle_end_event(kvm, vcpu_record, &key, sample);1025 1026 return true;1027}1028 1029static bool is_valid_key(struct perf_kvm_stat *kvm)1030{1031 static const char *key_array[] = {1032 "ev_name", "sample", "time", "max_t", "min_t", "mean_t",1033 };1034 unsigned int i;1035 1036 for (i = 0; i < ARRAY_SIZE(key_array); i++)1037 if (!strcmp(key_array[i], kvm->sort_key))1038 return true;1039 1040 pr_err("Unsupported sort key: %s\n", kvm->sort_key);1041 return false;1042}1043 1044static bool event_is_valid(struct kvm_event *event, int vcpu)1045{1046 return !!get_event_count(event, vcpu);1047}1048 1049static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)1050{1051 struct kvm_event *event;1052 struct perf_kvm_stat *perf_kvm;1053 1054 event = container_of(he, struct kvm_event, he);1055 perf_kvm = event->perf_kvm;1056 if (!event_is_valid(event, perf_kvm->trace_vcpu))1057 he->filtered = 1;1058 else1059 he->filtered = 0;1060 return 0;1061}1062 1063static void sort_result(struct perf_kvm_stat *kvm)1064{1065 struct ui_progress prog;1066 const char *output_columns = "ev_name,sample,percent_sample,"1067 "time,percent_time,max_t,min_t,mean_t";1068 1069 kvm_hists__reinit(output_columns, kvm->sort_key);1070 ui_progress__init(&prog, kvm_hists.hists.nr_entries, "Sorting...");1071 hists__collapse_resort(&kvm_hists.hists, NULL);1072 hists__output_resort_cb(&kvm_hists.hists, NULL, filter_cb);1073 ui_progress__finish();1074}1075 1076static void print_vcpu_info(struct perf_kvm_stat *kvm)1077{1078 int vcpu = kvm->trace_vcpu;1079 1080 pr_info("Analyze events for ");1081 1082 if (kvm->opts.target.system_wide)1083 pr_info("all VMs, ");1084 else if (kvm->opts.target.pid)1085 pr_info("pid(s) %s, ", kvm->opts.target.pid);1086 else1087 pr_info("dazed and confused on what is monitored, ");1088 1089 if (vcpu == -1)1090 pr_info("all VCPUs:\n\n");1091 else1092 pr_info("VCPU %d:\n\n", vcpu);1093}1094 1095static void show_timeofday(void)1096{1097 char date[64];1098 struct timeval tv;1099 struct tm ltime;1100 1101 gettimeofday(&tv, NULL);1102 if (localtime_r(&tv.tv_sec, <ime)) {1103 strftime(date, sizeof(date), "%H:%M:%S", <ime);1104 pr_info("%s.%06ld", date, tv.tv_usec);1105 } else1106 pr_info("00:00:00.000000");1107 1108 return;1109}1110 1111static void print_result(struct perf_kvm_stat *kvm)1112{1113 char decode[KVM_EVENT_NAME_LEN];1114 struct kvm_event *event;1115 int vcpu = kvm->trace_vcpu;1116 struct rb_node *nd;1117 1118 if (kvm->live) {1119 puts(CONSOLE_CLEAR);1120 show_timeofday();1121 }1122 1123 pr_info("\n\n");1124 print_vcpu_info(kvm);1125 pr_info("%*s ", KVM_EVENT_NAME_LEN, kvm->events_ops->name);1126 pr_info("%10s ", "Samples");1127 pr_info("%9s ", "Samples%");1128 1129 pr_info("%9s ", "Time%");1130 pr_info("%11s ", "Min Time");1131 pr_info("%11s ", "Max Time");1132 pr_info("%16s ", "Avg time");1133 pr_info("\n\n");1134 1135 for (nd = rb_first_cached(&kvm_hists.hists.entries); nd; nd = rb_next(nd)) {1136 struct hist_entry *he;1137 u64 ecount, etime, max, min;1138 1139 he = rb_entry(nd, struct hist_entry, rb_node);1140 if (he->filtered)1141 continue;1142 1143 event = container_of(he, struct kvm_event, he);1144 ecount = get_event_count(event, vcpu);1145 etime = get_event_time(event, vcpu);1146 max = get_event_max(event, vcpu);1147 min = get_event_min(event, vcpu);1148 1149 kvm->events_ops->decode_key(kvm, &event->key, decode);1150 pr_info("%*s ", KVM_EVENT_NAME_LEN, decode);1151 pr_info("%10llu ", (unsigned long long)ecount);1152 pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);1153 pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);1154 pr_info("%9.2fus ", (double)min / NSEC_PER_USEC);1155 pr_info("%9.2fus ", (double)max / NSEC_PER_USEC);1156 pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount / NSEC_PER_USEC,1157 kvm_event_rel_stddev(vcpu, event));1158 pr_info("\n");1159 }1160 1161 pr_info("\nTotal Samples:%" PRIu64 ", Total events handled time:%.2fus.\n\n",1162 kvm->total_count, kvm->total_time / (double)NSEC_PER_USEC);1163 1164 if (kvm->lost_events)1165 pr_info("\nLost events: %" PRIu64 "\n\n", kvm->lost_events);1166}1167 1168#if defined(HAVE_TIMERFD_SUPPORT) && defined(HAVE_LIBTRACEEVENT)1169static int process_lost_event(const struct perf_tool *tool,1170 union perf_event *event __maybe_unused,1171 struct perf_sample *sample __maybe_unused,1172 struct machine *machine __maybe_unused)1173{1174 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat, tool);1175 1176 kvm->lost_events++;1177 return 0;1178}1179#endif1180 1181static bool skip_sample(struct perf_kvm_stat *kvm,1182 struct perf_sample *sample)1183{1184 if (kvm->pid_list && intlist__find(kvm->pid_list, sample->pid) == NULL)1185 return true;1186 1187 return false;1188}1189 1190static int process_sample_event(const struct perf_tool *tool,1191 union perf_event *event,1192 struct perf_sample *sample,1193 struct evsel *evsel,1194 struct machine *machine)1195{1196 int err = 0;1197 struct thread *thread;1198 struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,1199 tool);1200 1201 if (skip_sample(kvm, sample))1202 return 0;1203 1204 if (machine__resolve(machine, &kvm->al, sample) < 0) {1205 pr_warning("Fail to resolve address location, skip sample.\n");1206 return 0;1207 }1208 1209 thread = machine__findnew_thread(machine, sample->pid, sample->tid);1210 if (thread == NULL) {1211 pr_debug("problem processing %d event, skipping it.\n",1212 event->header.type);1213 return -1;1214 }1215 1216 if (!handle_kvm_event(kvm, thread, evsel, sample))1217 err = -1;1218 1219 thread__put(thread);1220 return err;1221}1222 1223static int cpu_isa_config(struct perf_kvm_stat *kvm)1224{1225 char buf[128], *cpuid;1226 int err;1227 1228 if (kvm->live) {1229 err = get_cpuid(buf, sizeof(buf));1230 if (err != 0) {1231 pr_err("Failed to look up CPU type: %s\n",1232 str_error_r(err, buf, sizeof(buf)));1233 return -err;1234 }1235 cpuid = buf;1236 } else1237 cpuid = kvm->session->header.env.cpuid;1238 1239 if (!cpuid) {1240 pr_err("Failed to look up CPU type\n");1241 return -EINVAL;1242 }1243 1244 err = cpu_isa_init(kvm, cpuid);1245 if (err == -ENOTSUP)1246 pr_err("CPU %s is not supported.\n", cpuid);1247 1248 return err;1249}1250 1251static bool verify_vcpu(int vcpu)1252{1253 if (vcpu != -1 && vcpu < 0) {1254 pr_err("Invalid vcpu:%d.\n", vcpu);1255 return false;1256 }1257 1258 return true;1259}1260 1261#if defined(HAVE_TIMERFD_SUPPORT) && defined(HAVE_LIBTRACEEVENT)1262/* keeping the max events to a modest level to keep1263 * the processing of samples per mmap smooth.1264 */1265#define PERF_KVM__MAX_EVENTS_PER_MMAP 251266 1267static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,1268 u64 *mmap_time)1269{1270 struct evlist *evlist = kvm->evlist;1271 union perf_event *event;1272 struct mmap *md;1273 u64 timestamp;1274 s64 n = 0;1275 int err;1276 1277 *mmap_time = ULLONG_MAX;1278 md = &evlist->mmap[idx];1279 err = perf_mmap__read_init(&md->core);1280 if (err < 0)1281 return (err == -EAGAIN) ? 0 : -1;1282 1283 while ((event = perf_mmap__read_event(&md->core)) != NULL) {1284 err = evlist__parse_sample_timestamp(evlist, event, ×tamp);1285 if (err) {1286 perf_mmap__consume(&md->core);1287 pr_err("Failed to parse sample\n");1288 return -1;1289 }1290 1291 err = perf_session__queue_event(kvm->session, event, timestamp, 0, NULL);1292 /*1293 * FIXME: Here we can't consume the event, as perf_session__queue_event will1294 * point to it, and it'll get possibly overwritten by the kernel.1295 */1296 perf_mmap__consume(&md->core);1297 1298 if (err) {1299 pr_err("Failed to enqueue sample: %d\n", err);1300 return -1;1301 }1302 1303 /* save time stamp of our first sample for this mmap */1304 if (n == 0)1305 *mmap_time = timestamp;1306 1307 /* limit events per mmap handled all at once */1308 n++;1309 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)1310 break;1311 }1312 1313 perf_mmap__read_done(&md->core);1314 return n;1315}1316 1317static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)1318{1319 int i, err, throttled = 0;1320 s64 n, ntotal = 0;1321 u64 flush_time = ULLONG_MAX, mmap_time;1322 1323 for (i = 0; i < kvm->evlist->core.nr_mmaps; i++) {1324 n = perf_kvm__mmap_read_idx(kvm, i, &mmap_time);1325 if (n < 0)1326 return -1;1327 1328 /* flush time is going to be the minimum of all the individual1329 * mmap times. Essentially, we flush all the samples queued up1330 * from the last pass under our minimal start time -- that leaves1331 * a very small race for samples to come in with a lower timestamp.1332 * The ioctl to return the perf_clock timestamp should close the1333 * race entirely.1334 */1335 if (mmap_time < flush_time)1336 flush_time = mmap_time;1337 1338 ntotal += n;1339 if (n == PERF_KVM__MAX_EVENTS_PER_MMAP)1340 throttled = 1;1341 }1342 1343 /* flush queue after each round in which we processed events */1344 if (ntotal) {1345 struct ordered_events *oe = &kvm->session->ordered_events;1346 1347 oe->next_flush = flush_time;1348 err = ordered_events__flush(oe, OE_FLUSH__ROUND);1349 if (err) {1350 if (kvm->lost_events)1351 pr_info("\nLost events: %" PRIu64 "\n\n",1352 kvm->lost_events);1353 return err;1354 }1355 }1356 1357 return throttled;1358}1359 1360static volatile int done;1361 1362static void sig_handler(int sig __maybe_unused)1363{1364 done = 1;1365}1366 1367static int perf_kvm__timerfd_create(struct perf_kvm_stat *kvm)1368{1369 struct itimerspec new_value;1370 int rc = -1;1371 1372 kvm->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);1373 if (kvm->timerfd < 0) {1374 pr_err("timerfd_create failed\n");1375 goto out;1376 }1377 1378 new_value.it_value.tv_sec = kvm->display_time;1379 new_value.it_value.tv_nsec = 0;1380 new_value.it_interval.tv_sec = kvm->display_time;1381 new_value.it_interval.tv_nsec = 0;1382 1383 if (timerfd_settime(kvm->timerfd, 0, &new_value, NULL) != 0) {1384 pr_err("timerfd_settime failed: %d\n", errno);1385 close(kvm->timerfd);1386 goto out;1387 }1388 1389 rc = 0;1390out:1391 return rc;1392}1393 1394static int perf_kvm__handle_timerfd(struct perf_kvm_stat *kvm)1395{1396 uint64_t c;1397 int rc;1398 1399 rc = read(kvm->timerfd, &c, sizeof(uint64_t));1400 if (rc < 0) {1401 if (errno == EAGAIN)1402 return 0;1403 1404 pr_err("Failed to read timer fd: %d\n", errno);1405 return -1;1406 }1407 1408 if (rc != sizeof(uint64_t)) {1409 pr_err("Error reading timer fd - invalid size returned\n");1410 return -1;1411 }1412 1413 if (c != 1)1414 pr_debug("Missed timer beats: %" PRIu64 "\n", c-1);1415 1416 /* update display */1417 sort_result(kvm);1418 print_result(kvm);1419 1420 /* Reset sort list to "ev_name" */1421 kvm_hists__reinit(NULL, "ev_name");1422 1423 /* reset counts */1424 clear_events_cache_stats();1425 kvm->total_count = 0;1426 kvm->total_time = 0;1427 kvm->lost_events = 0;1428 1429 return 0;1430}1431 1432static int fd_set_nonblock(int fd)1433{1434 long arg = 0;1435 1436 arg = fcntl(fd, F_GETFL);1437 if (arg < 0) {1438 pr_err("Failed to get current flags for fd %d\n", fd);1439 return -1;1440 }1441 1442 if (fcntl(fd, F_SETFL, arg | O_NONBLOCK) < 0) {1443 pr_err("Failed to set non-block option on fd %d\n", fd);1444 return -1;1445 }1446 1447 return 0;1448}1449 1450static int perf_kvm__handle_stdin(void)1451{1452 int c;1453 1454 c = getc(stdin);1455 if (c == 'q')1456 return 1;1457 1458 return 0;1459}1460 1461static int kvm_events_live_report(struct perf_kvm_stat *kvm)1462{1463 int nr_stdin, ret, err = -EINVAL;1464 struct termios save;1465 1466 /* live flag must be set first */1467 kvm->live = true;1468 1469 ret = cpu_isa_config(kvm);1470 if (ret < 0)1471 return ret;1472 1473 if (!verify_vcpu(kvm->trace_vcpu) ||1474 !is_valid_key(kvm) ||1475 !register_kvm_events_ops(kvm)) {1476 goto out;1477 }1478 1479 set_term_quiet_input(&save);1480 1481 kvm_hists__init();1482 1483 signal(SIGINT, sig_handler);1484 signal(SIGTERM, sig_handler);1485 1486 /* add timer fd */1487 if (perf_kvm__timerfd_create(kvm) < 0) {1488 err = -1;1489 goto out;1490 }1491 1492 if (evlist__add_pollfd(kvm->evlist, kvm->timerfd) < 0)1493 goto out;1494 1495 nr_stdin = evlist__add_pollfd(kvm->evlist, fileno(stdin));1496 if (nr_stdin < 0)1497 goto out;1498 1499 if (fd_set_nonblock(fileno(stdin)) != 0)1500 goto out;1501 1502 /* everything is good - enable the events and process */1503 evlist__enable(kvm->evlist);1504 1505 while (!done) {1506 struct fdarray *fda = &kvm->evlist->core.pollfd;1507 int rc;1508 1509 rc = perf_kvm__mmap_read(kvm);1510 if (rc < 0)1511 break;1512 1513 err = perf_kvm__handle_timerfd(kvm);1514 if (err)1515 goto out;1516 1517 if (fda->entries[nr_stdin].revents & POLLIN)1518 done = perf_kvm__handle_stdin();1519 1520 if (!rc && !done)1521 err = evlist__poll(kvm->evlist, 100);1522 }1523 1524 evlist__disable(kvm->evlist);1525 1526 if (err == 0) {1527 sort_result(kvm);1528 print_result(kvm);1529 }1530 1531out:1532 hists__delete_entries(&kvm_hists.hists);1533 1534 if (kvm->timerfd >= 0)1535 close(kvm->timerfd);1536 1537 tcsetattr(0, TCSAFLUSH, &save);1538 return err;1539}1540 1541static int kvm_live_open_events(struct perf_kvm_stat *kvm)1542{1543 int err, rc = -1;1544 struct evsel *pos;1545 struct evlist *evlist = kvm->evlist;1546 char sbuf[STRERR_BUFSIZE];1547 1548 evlist__config(evlist, &kvm->opts, NULL);1549 1550 /*1551 * Note: exclude_{guest,host} do not apply here.1552 * This command processes KVM tracepoints from host only1553 */1554 evlist__for_each_entry(evlist, pos) {1555 struct perf_event_attr *attr = &pos->core.attr;1556 1557 /* make sure these *are* set */1558 evsel__set_sample_bit(pos, TID);1559 evsel__set_sample_bit(pos, TIME);1560 evsel__set_sample_bit(pos, CPU);1561 evsel__set_sample_bit(pos, RAW);1562 /* make sure these are *not*; want as small a sample as possible */1563 evsel__reset_sample_bit(pos, PERIOD);1564 evsel__reset_sample_bit(pos, IP);1565 evsel__reset_sample_bit(pos, CALLCHAIN);1566 evsel__reset_sample_bit(pos, ADDR);1567 evsel__reset_sample_bit(pos, READ);1568 attr->mmap = 0;1569 attr->comm = 0;1570 attr->task = 0;1571 1572 attr->sample_period = 1;1573 1574 attr->watermark = 0;1575 attr->wakeup_events = 1000;1576 1577 /* will enable all once we are ready */1578 attr->disabled = 1;1579 }1580 1581 err = evlist__open(evlist);1582 if (err < 0) {1583 printf("Couldn't create the events: %s\n",1584 str_error_r(errno, sbuf, sizeof(sbuf)));1585 goto out;1586 }1587 1588 if (evlist__mmap(evlist, kvm->opts.mmap_pages) < 0) {1589 ui__error("Failed to mmap the events: %s\n",1590 str_error_r(errno, sbuf, sizeof(sbuf)));1591 evlist__close(evlist);1592 goto out;1593 }1594 1595 rc = 0;1596 1597out:1598 return rc;1599}1600#endif1601 1602static int read_events(struct perf_kvm_stat *kvm)1603{1604 int ret;1605 1606 struct perf_data file = {1607 .path = kvm->file_name,1608 .mode = PERF_DATA_MODE_READ,1609 .force = kvm->force,1610 };1611 1612 perf_tool__init(&kvm->tool, /*ordered_events=*/true);1613 kvm->tool.sample = process_sample_event;1614 kvm->tool.comm = perf_event__process_comm;1615 kvm->tool.namespaces = perf_event__process_namespaces;1616 1617 kvm->session = perf_session__new(&file, &kvm->tool);1618 if (IS_ERR(kvm->session)) {1619 pr_err("Initializing perf session failed\n");1620 return PTR_ERR(kvm->session);1621 }1622 1623 symbol__init(&kvm->session->header.env);1624 1625 if (!perf_session__has_traces(kvm->session, "kvm record")) {1626 ret = -EINVAL;1627 goto out_delete;1628 }1629 1630 /*1631 * Do not use 'isa' recorded in kvm_exit tracepoint since it is not1632 * traced in the old kernel.1633 */1634 ret = cpu_isa_config(kvm);1635 if (ret < 0)1636 goto out_delete;1637 1638 ret = perf_session__process_events(kvm->session);1639 1640out_delete:1641 perf_session__delete(kvm->session);1642 return ret;1643}1644 1645static int parse_target_str(struct perf_kvm_stat *kvm)1646{1647 if (kvm->opts.target.pid) {1648 kvm->pid_list = intlist__new(kvm->opts.target.pid);1649 if (kvm->pid_list == NULL) {1650 pr_err("Error parsing process id string\n");1651 return -EINVAL;1652 }1653 }1654 1655 return 0;1656}1657 1658static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)1659{1660 int ret = -EINVAL;1661 int vcpu = kvm->trace_vcpu;1662 1663 if (parse_target_str(kvm) != 0)1664 goto exit;1665 1666 if (!verify_vcpu(vcpu))1667 goto exit;1668 1669 if (!is_valid_key(kvm))1670 goto exit;1671 1672 if (!register_kvm_events_ops(kvm))1673 goto exit;1674 1675 if (kvm->use_stdio) {1676 use_browser = 0;1677 setup_pager();1678 } else {1679 use_browser = 1;1680 }1681 1682 setup_browser(false);1683 1684 kvm_hists__init();1685 1686 ret = read_events(kvm);1687 if (ret)1688 goto exit;1689 1690 sort_result(kvm);1691 kvm_display(kvm);1692 1693exit:1694 hists__delete_entries(&kvm_hists.hists);1695 return ret;1696}1697 1698#define STRDUP_FAIL_EXIT(s) \1699 ({ char *_p; \1700 _p = strdup(s); \1701 if (!_p) \1702 return -ENOMEM; \1703 _p; \1704 })1705 1706int __weak setup_kvm_events_tp(struct perf_kvm_stat *kvm __maybe_unused)1707{1708 return 0;1709}1710 1711static int1712kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)1713{1714 unsigned int rec_argc, i, j, events_tp_size;1715 const char **rec_argv;1716 const char * const record_args[] = {1717 "record",1718 "-R",1719 "-m", "1024",1720 "-c", "1",1721 };1722 const char * const kvm_stat_record_usage[] = {1723 "perf kvm stat record [<options>]",1724 NULL1725 };1726 const char * const *events_tp;1727 int ret;1728 1729 events_tp_size = 0;1730 ret = setup_kvm_events_tp(kvm);1731 if (ret < 0) {1732 pr_err("Unable to setup the kvm tracepoints\n");1733 return ret;1734 }1735 1736 for (events_tp = kvm_events_tp; *events_tp; events_tp++)1737 events_tp_size++;1738 1739 rec_argc = ARRAY_SIZE(record_args) + argc + 2 +1740 2 * events_tp_size;1741 rec_argv = calloc(rec_argc + 1, sizeof(char *));1742 1743 if (rec_argv == NULL)1744 return -ENOMEM;1745 1746 for (i = 0; i < ARRAY_SIZE(record_args); i++)1747 rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]);1748 1749 for (j = 0; j < events_tp_size; j++) {1750 rec_argv[i++] = "-e";1751 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm_events_tp[j]);1752 }1753 1754 rec_argv[i++] = STRDUP_FAIL_EXIT("-o");1755 rec_argv[i++] = STRDUP_FAIL_EXIT(kvm->file_name);1756 1757 for (j = 1; j < (unsigned int)argc; j++, i++)1758 rec_argv[i] = argv[j];1759 1760 set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN);1761 set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN);1762 set_option_flag(record_options, 'R', "raw-samples", PARSE_OPT_HIDDEN);1763 1764 set_option_flag(record_options, 'F', "freq", PARSE_OPT_DISABLED);1765 set_option_flag(record_options, 0, "group", PARSE_OPT_DISABLED);1766 set_option_flag(record_options, 'g', NULL, PARSE_OPT_DISABLED);1767 set_option_flag(record_options, 0, "call-graph", PARSE_OPT_DISABLED);1768 set_option_flag(record_options, 'd', "data", PARSE_OPT_DISABLED);1769 set_option_flag(record_options, 'T', "timestamp", PARSE_OPT_DISABLED);1770 set_option_flag(record_options, 'P', "period", PARSE_OPT_DISABLED);1771 set_option_flag(record_options, 'n', "no-samples", PARSE_OPT_DISABLED);1772 set_option_flag(record_options, 'N', "no-buildid-cache", PARSE_OPT_DISABLED);1773 set_option_flag(record_options, 'B', "no-buildid", PARSE_OPT_DISABLED);1774 set_option_flag(record_options, 'G', "cgroup", PARSE_OPT_DISABLED);1775 set_option_flag(record_options, 'b', "branch-any", PARSE_OPT_DISABLED);1776 set_option_flag(record_options, 'j', "branch-filter", PARSE_OPT_DISABLED);1777 set_option_flag(record_options, 'W', "weight", PARSE_OPT_DISABLED);1778 set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);1779 1780 record_usage = kvm_stat_record_usage;1781 return cmd_record(i, rec_argv);1782}1783 1784static int1785kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)1786{1787 const struct option kvm_events_report_options[] = {1788 OPT_STRING(0, "event", &kvm->report_event, "report event",1789 "event for reporting: vmexit, "1790 "mmio (x86 only), ioport (x86 only)"),1791 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,1792 "vcpu id to report"),1793 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",1794 "key for sorting: sample(sort by samples number)"1795 " time (sort by avg time)"),1796 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",1797 "analyze events only for given process id(s)"),1798 OPT_BOOLEAN('f', "force", &kvm->force, "don't complain, do it"),1799 OPT_BOOLEAN(0, "stdio", &kvm->use_stdio, "use the stdio interface"),1800 OPT_END()1801 };1802 1803 const char * const kvm_events_report_usage[] = {1804 "perf kvm stat report [<options>]",1805 NULL1806 };1807 1808 if (argc) {1809 argc = parse_options(argc, argv,1810 kvm_events_report_options,1811 kvm_events_report_usage, 0);1812 if (argc)1813 usage_with_options(kvm_events_report_usage,1814 kvm_events_report_options);1815 }1816 1817#ifndef HAVE_SLANG_SUPPORT1818 kvm->use_stdio = true;1819#endif1820 1821 if (!kvm->opts.target.pid)1822 kvm->opts.target.system_wide = true;1823 1824 return kvm_events_report_vcpu(kvm);1825}1826 1827#if defined(HAVE_TIMERFD_SUPPORT) && defined(HAVE_LIBTRACEEVENT)1828static struct evlist *kvm_live_event_list(void)1829{1830 struct evlist *evlist;1831 char *tp, *name, *sys;1832 int err = -1;1833 const char * const *events_tp;1834 1835 evlist = evlist__new();1836 if (evlist == NULL)1837 return NULL;1838 1839 for (events_tp = kvm_events_tp; *events_tp; events_tp++) {1840 1841 tp = strdup(*events_tp);1842 if (tp == NULL)1843 goto out;1844 1845 /* split tracepoint into subsystem and name */1846 sys = tp;1847 name = strchr(tp, ':');1848 if (name == NULL) {1849 pr_err("Error parsing %s tracepoint: subsystem delimiter not found\n",1850 *events_tp);1851 free(tp);1852 goto out;1853 }1854 *name = '\0';1855 name++;1856 1857 if (evlist__add_newtp(evlist, sys, name, NULL)) {1858 pr_err("Failed to add %s tracepoint to the list\n", *events_tp);1859 free(tp);1860 goto out;1861 }1862 1863 free(tp);1864 }1865 1866 err = 0;1867 1868out:1869 if (err) {1870 evlist__delete(evlist);1871 evlist = NULL;1872 }1873 1874 return evlist;1875}1876 1877static int kvm_events_live(struct perf_kvm_stat *kvm,1878 int argc, const char **argv)1879{1880 char errbuf[BUFSIZ];1881 int err;1882 1883 const struct option live_options[] = {1884 OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid",1885 "record events on existing process id"),1886 OPT_CALLBACK('m', "mmap-pages", &kvm->opts.mmap_pages, "pages",1887 "number of mmap data pages", evlist__parse_mmap_pages),1888 OPT_INCR('v', "verbose", &verbose,1889 "be more verbose (show counter open errors, etc)"),1890 OPT_BOOLEAN('a', "all-cpus", &kvm->opts.target.system_wide,1891 "system-wide collection from all CPUs"),1892 OPT_UINTEGER('d', "display", &kvm->display_time,1893 "time in seconds between display updates"),1894 OPT_STRING(0, "event", &kvm->report_event, "report event",1895 "event for reporting: "1896 "vmexit, mmio (x86 only), ioport (x86 only)"),1897 OPT_INTEGER(0, "vcpu", &kvm->trace_vcpu,1898 "vcpu id to report"),1899 OPT_STRING('k', "key", &kvm->sort_key, "sort-key",1900 "key for sorting: sample(sort by samples number)"1901 " time (sort by avg time)"),1902 OPT_U64(0, "duration", &kvm->duration,1903 "show events other than"1904 " HLT (x86 only) or Wait state (s390 only)"1905 " that take longer than duration usecs"),1906 OPT_UINTEGER(0, "proc-map-timeout", &proc_map_timeout,1907 "per thread proc mmap processing timeout in ms"),1908 OPT_END()1909 };1910 const char * const live_usage[] = {1911 "perf kvm stat live [<options>]",1912 NULL1913 };1914 struct perf_data data = {1915 .mode = PERF_DATA_MODE_WRITE,1916 };1917 1918 1919 /* event handling */1920 perf_tool__init(&kvm->tool, /*ordered_events=*/true);1921 kvm->tool.sample = process_sample_event;1922 kvm->tool.comm = perf_event__process_comm;1923 kvm->tool.exit = perf_event__process_exit;1924 kvm->tool.fork = perf_event__process_fork;1925 kvm->tool.lost = process_lost_event;1926 kvm->tool.namespaces = perf_event__process_namespaces;1927 1928 /* set defaults */1929 kvm->display_time = 1;1930 kvm->opts.user_interval = 1;1931 kvm->opts.mmap_pages = 512;1932 kvm->opts.target.uses_mmap = false;1933 kvm->opts.target.uid_str = NULL;1934 kvm->opts.target.uid = UINT_MAX;1935 1936 symbol__init(NULL);1937 disable_buildid_cache();1938 1939 use_browser = 0;1940 1941 if (argc) {1942 argc = parse_options(argc, argv, live_options,1943 live_usage, 0);1944 if (argc)1945 usage_with_options(live_usage, live_options);1946 }1947 1948 kvm->duration *= NSEC_PER_USEC; /* convert usec to nsec */1949 1950 /*1951 * target related setups1952 */1953 err = target__validate(&kvm->opts.target);1954 if (err) {1955 target__strerror(&kvm->opts.target, err, errbuf, BUFSIZ);1956 ui__warning("%s", errbuf);1957 }1958 1959 if (target__none(&kvm->opts.target))1960 kvm->opts.target.system_wide = true;1961 1962 1963 /*1964 * generate the event list1965 */1966 err = setup_kvm_events_tp(kvm);1967 if (err < 0) {1968 pr_err("Unable to setup the kvm tracepoints\n");1969 return err;1970 }1971 1972 kvm->evlist = kvm_live_event_list();1973 if (kvm->evlist == NULL) {1974 err = -1;1975 goto out;1976 }1977 1978 if (evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0)1979 usage_with_options(live_usage, live_options);1980 1981 /*1982 * perf session1983 */1984 kvm->session = perf_session__new(&data, &kvm->tool);1985 if (IS_ERR(kvm->session)) {1986 err = PTR_ERR(kvm->session);1987 goto out;1988 }1989 kvm->session->evlist = kvm->evlist;1990 perf_session__set_id_hdr_size(kvm->session);1991 ordered_events__set_copy_on_queue(&kvm->session->ordered_events, true);1992 machine__synthesize_threads(&kvm->session->machines.host, &kvm->opts.target,1993 kvm->evlist->core.threads, true, false, 1);1994 err = kvm_live_open_events(kvm);1995 if (err)1996 goto out;1997 1998 err = kvm_events_live_report(kvm);1999 2000out:2001 perf_session__delete(kvm->session);2002 kvm->session = NULL;2003 evlist__delete(kvm->evlist);2004 2005 return err;2006}2007#endif2008 2009static void print_kvm_stat_usage(void)2010{2011 printf("Usage: perf kvm stat <command>\n\n");2012 2013 printf("# Available commands:\n");2014 printf("\trecord: record kvm events\n");2015 printf("\treport: report statistical data of kvm events\n");2016 printf("\tlive: live reporting of statistical data of kvm events\n");2017 2018 printf("\nOtherwise, it is the alias of 'perf stat':\n");2019}2020 2021static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)2022{2023 struct perf_kvm_stat kvm = {2024 .file_name = file_name,2025 2026 .trace_vcpu = -1,2027 .report_event = "vmexit",2028 .sort_key = "sample",2029 2030 };2031 2032 if (argc == 1) {2033 print_kvm_stat_usage();2034 goto perf_stat;2035 }2036 2037 if (strlen(argv[1]) > 2 && strstarts("record", argv[1]))2038 return kvm_events_record(&kvm, argc - 1, argv + 1);2039 2040 if (strlen(argv[1]) > 2 && strstarts("report", argv[1]))2041 return kvm_events_report(&kvm, argc - 1 , argv + 1);2042 2043#if defined(HAVE_TIMERFD_SUPPORT) && defined(HAVE_LIBTRACEEVENT)2044 if (!strncmp(argv[1], "live", 4))2045 return kvm_events_live(&kvm, argc - 1 , argv + 1);2046#endif2047 2048perf_stat:2049 return cmd_stat(argc, argv);2050}2051#endif /* HAVE_KVM_STAT_SUPPORT */2052 2053int __weak kvm_add_default_arch_event(int *argc __maybe_unused,2054 const char **argv __maybe_unused)2055{2056 return 0;2057}2058 2059static int __cmd_record(const char *file_name, int argc, const char **argv)2060{2061 int rec_argc, i = 0, j, ret;2062 const char **rec_argv;2063 2064 ret = kvm_add_default_arch_event(&argc, argv);2065 if (ret)2066 return -EINVAL;2067 2068 rec_argc = argc + 2;2069 rec_argv = calloc(rec_argc + 1, sizeof(char *));2070 rec_argv[i++] = strdup("record");2071 rec_argv[i++] = strdup("-o");2072 rec_argv[i++] = strdup(file_name);2073 for (j = 1; j < argc; j++, i++)2074 rec_argv[i] = argv[j];2075 2076 BUG_ON(i != rec_argc);2077 2078 return cmd_record(i, rec_argv);2079}2080 2081static int __cmd_report(const char *file_name, int argc, const char **argv)2082{2083 int rec_argc, i = 0, j;2084 const char **rec_argv;2085 2086 rec_argc = argc + 2;2087 rec_argv = calloc(rec_argc + 1, sizeof(char *));2088 rec_argv[i++] = strdup("report");2089 rec_argv[i++] = strdup("-i");2090 rec_argv[i++] = strdup(file_name);2091 for (j = 1; j < argc; j++, i++)2092 rec_argv[i] = argv[j];2093 2094 BUG_ON(i != rec_argc);2095 2096 return cmd_report(i, rec_argv);2097}2098 2099static int2100__cmd_buildid_list(const char *file_name, int argc, const char **argv)2101{2102 int rec_argc, i = 0, j;2103 const char **rec_argv;2104 2105 rec_argc = argc + 2;2106 rec_argv = calloc(rec_argc + 1, sizeof(char *));2107 rec_argv[i++] = strdup("buildid-list");2108 rec_argv[i++] = strdup("-i");2109 rec_argv[i++] = strdup(file_name);2110 for (j = 1; j < argc; j++, i++)2111 rec_argv[i] = argv[j];2112 2113 BUG_ON(i != rec_argc);2114 2115 return cmd_buildid_list(i, rec_argv);2116}2117 2118int cmd_kvm(int argc, const char **argv)2119{2120 const char *file_name = NULL;2121 const struct option kvm_options[] = {2122 OPT_STRING('i', "input", &file_name, "file",2123 "Input file name"),2124 OPT_STRING('o', "output", &file_name, "file",2125 "Output file name"),2126 OPT_BOOLEAN(0, "guest", &perf_guest,2127 "Collect guest os data"),2128 OPT_BOOLEAN(0, "host", &perf_host,2129 "Collect host os data"),2130 OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",2131 "guest mount directory under which every guest os"2132 " instance has a subdir"),2133 OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,2134 "file", "file saving guest os vmlinux"),2135 OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,2136 "file", "file saving guest os /proc/kallsyms"),2137 OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,2138 "file", "file saving guest os /proc/modules"),2139 OPT_BOOLEAN(0, "guest-code", &symbol_conf.guest_code,2140 "Guest code can be found in hypervisor process"),2141 OPT_INCR('v', "verbose", &verbose,2142 "be more verbose (show counter open errors, etc)"),2143 OPT_END()2144 };2145 2146 const char *const kvm_subcommands[] = { "top", "record", "report", "diff",2147 "buildid-list", "stat", NULL };2148 const char *kvm_usage[] = { NULL, NULL };2149 2150 perf_host = 0;2151 perf_guest = 1;2152 2153 argc = parse_options_subcommand(argc, argv, kvm_options, kvm_subcommands, kvm_usage,2154 PARSE_OPT_STOP_AT_NON_OPTION);2155 if (!argc)2156 usage_with_options(kvm_usage, kvm_options);2157 2158 if (!perf_host)2159 perf_guest = 1;2160 2161 if (!file_name) {2162 file_name = get_filename_for_perf_kvm();2163 2164 if (!file_name) {2165 pr_err("Failed to allocate memory for filename\n");2166 return -ENOMEM;2167 }2168 }2169 2170 if (strlen(argv[0]) > 2 && strstarts("record", argv[0]))2171 return __cmd_record(file_name, argc, argv);2172 else if (strlen(argv[0]) > 2 && strstarts("report", argv[0]))2173 return __cmd_report(file_name, argc, argv);2174 else if (strlen(argv[0]) > 2 && strstarts("diff", argv[0]))2175 return cmd_diff(argc, argv);2176 else if (!strcmp(argv[0], "top"))2177 return cmd_top(argc, argv);2178 else if (strlen(argv[0]) > 2 && strstarts("buildid-list", argv[0]))2179 return __cmd_buildid_list(file_name, argc, argv);2180#if defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT)2181 else if (strlen(argv[0]) > 2 && strstarts("stat", argv[0]))2182 return kvm_cmd_stat(file_name, argc, argv);2183#endif2184 else2185 usage_with_options(kvm_usage, kvm_options);2186 2187 /* free usage string allocated by parse_options_subcommand */2188 free((void *)kvm_usage[0]);2189 2190 return 0;2191}2192