diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 9bfde8b7ac65..4c205df5106f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -23,6 +23,8 @@ #include "util/data.h" #include "util/ordered-events.h" #include "util/kvm-stat.h" +#include "ui/browsers/hists.h" +#include "ui/progress.h" #include "ui/ui.h" #include "util/string2.h" @@ -496,6 +498,7 @@ out: static int kvm_hists__init(void) { + kvm_hists.list.nr_header_lines = 1; __hists__init(&kvm_hists.hists, &kvm_hists.list); perf_hpp_list__init(&kvm_hists.list); return kvm_hpp_list__parse(&kvm_hists.list, NULL, "ev_name"); @@ -506,6 +509,93 @@ static int kvm_hists__reinit(const char *output, const char *sort) perf_hpp__reset_output_field(&kvm_hists.list); return kvm_hpp_list__parse(&kvm_hists.list, output, sort); } +static void print_result(struct perf_kvm_stat *kvm); + +#ifdef HAVE_SLANG_SUPPORT +static void kvm_browser__update_nr_entries(struct hist_browser *hb) +{ + struct rb_node *nd = rb_first_cached(&hb->hists->entries); + u64 nr_entries = 0; + + for (; nd; nd = rb_next(nd)) { + struct hist_entry *he = rb_entry(nd, struct hist_entry, + rb_node); + + if (!he->filtered) + nr_entries++; + } + + hb->nr_non_filtered_entries = nr_entries; +} + +static int kvm_browser__title(struct hist_browser *browser, + char *buf, size_t size) +{ + scnprintf(buf, size, "KVM event statistics (%lu entries)", + browser->nr_non_filtered_entries); + return 0; +} + +static struct hist_browser* +perf_kvm_browser__new(struct hists *hists) +{ + struct hist_browser *browser = hist_browser__new(hists); + + if (browser) + browser->title = kvm_browser__title; + + return browser; +} + +static int kvm__hists_browse(struct hists *hists) +{ + struct hist_browser *browser; + int key = -1; + + browser = perf_kvm_browser__new(hists); + if (browser == NULL) + return -1; + + /* reset abort key so that it can get Ctrl-C as a key */ + SLang_reset_tty(); + SLang_init_tty(0, 0, 0); + + kvm_browser__update_nr_entries(browser); + + while (1) { + key = hist_browser__run(browser, "? - help", true, 0); + + switch (key) { + case 'q': + goto out; + default: + break; + } + } + +out: + hist_browser__delete(browser); + return 0; +} + +static void kvm_display(struct perf_kvm_stat *kvm) +{ + if (!use_browser) + print_result(kvm); + else + kvm__hists_browse(&kvm_hists.hists); +} + +#else + +static void kvm_display(struct perf_kvm_stat *kvm) +{ + use_browser = 0; + print_result(kvm); +} + +#endif /* HAVE_SLANG_SUPPORT */ + #endif // defined(HAVE_KVM_STAT_SUPPORT) && defined(HAVE_LIBTRACEEVENT) static const char *get_filename_for_perf_kvm(void) @@ -972,12 +1062,15 @@ static int filter_cb(struct hist_entry *he, void *arg __maybe_unused) static void sort_result(struct perf_kvm_stat *kvm) { + struct ui_progress prog; const char *output_columns = "ev_name,sample,percent_sample," "time,percent_time,max_t,min_t,mean_t"; kvm_hists__reinit(output_columns, kvm->sort_key); + ui_progress__init(&prog, kvm_hists.hists.nr_entries, "Sorting..."); hists__collapse_resort(&kvm_hists.hists, NULL); hists__output_resort_cb(&kvm_hists.hists, NULL, filter_cb); + ui_progress__finish(); } static void print_vcpu_info(struct perf_kvm_stat *kvm) @@ -1579,7 +1672,14 @@ static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm) if (!register_kvm_events_ops(kvm)) goto exit; - setup_pager(); + if (kvm->use_stdio) { + use_browser = 0; + setup_pager(); + } else { + use_browser = 1; + } + + setup_browser(false); kvm_hists__init(); @@ -1588,7 +1688,7 @@ static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm) goto exit; sort_result(kvm); - print_result(kvm); + kvm_display(kvm); exit: return ret; @@ -1695,6 +1795,7 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) OPT_STRING('p', "pid", &kvm->opts.target.pid, "pid", "analyze events only for given process id(s)"), OPT_BOOLEAN('f', "force", &kvm->force, "don't complain, do it"), + OPT_BOOLEAN(0, "stdio", &kvm->use_stdio, "use the stdio interface"), OPT_END() }; @@ -1712,6 +1813,10 @@ kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv) kvm_events_report_options); } +#ifndef HAVE_SLANG_SUPPORT + kvm->use_stdio = true; +#endif + if (!kvm->opts.target.pid) kvm->opts.target.system_wide = true; diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 35d03894fac3..bc6c8e38ef50 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -103,6 +103,7 @@ struct perf_kvm_stat { unsigned int display_time; bool live; bool force; + bool use_stdio; }; struct kvm_reg_events_ops {