On Thu, Sep 03, 2015 at 08:31:03AM -0400, kan.li...@intel.com wrote:
> From: Kan Liang <kan.li...@intel.com>
> 
> Show frequency, CPU Utilization and percent performance for each symbol
> in perf report by --stdio --show-freq-perf
> 
> In sampling group, only group leader do sampling. So only need to print
> group leader's freq in --group.
> 
> Here is an example.
> 
> $ perf report --stdio --group --show-freq-perf

Ithink the --show-freq-perf option should imply --group, so user would type:

  perf record --freq-perf
  perf report --show-freq-perf

I wonder we should use --freq-perf for report as well 'perf report --freq-perf'

jirka

> 
>                                  Overhead   FREQ MHz   CPU%  CORE_BUSY%
> Command      Shared Object     Symbol
>  ........................................  .........  .....  ..........
> ...........  ................  ......................
> 
>     99.54%  99.54%  99.53%  99.53%  99.53%       2301     96         99
> tchain_edit  tchain_edit       [.] f3
>      0.20%   0.20%   0.20%   0.20%   0.20%       2301     98         99
> tchain_edit  tchain_edit       [.] f2
>      0.05%   0.05%   0.05%   0.05%   0.05%       2300     98         99
> tchain_edit  [kernel.vmlinux]  [k] read_tsc
> 
> Signed-off-by: Kan Liang <kan.li...@intel.com>
> ---
>  tools/perf/Documentation/perf-report.txt | 12 ++++++
>  tools/perf/builtin-report.c              | 22 +++++++++-
>  tools/perf/ui/hist.c                     | 71 
> +++++++++++++++++++++++++++++---
>  tools/perf/util/hist.h                   |  3 ++
>  tools/perf/util/session.c                | 33 ++++++++-------
>  tools/perf/util/sort.c                   |  3 ++
>  tools/perf/util/symbol.h                 | 12 +++++-
>  7 files changed, 134 insertions(+), 22 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-report.txt 
> b/tools/perf/Documentation/perf-report.txt
> index 9c7981b..6280e22 100644
> --- a/tools/perf/Documentation/perf-report.txt
> +++ b/tools/perf/Documentation/perf-report.txt
> @@ -306,6 +306,18 @@ OPTIONS
>       special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
>       'perf mem' for simpler access.
>  
> +--show-freq-perf::
> +     Show CPU frequency and performance result from sample read.
> +     To generate the frequency and performance output, the perf.data file
> +     must have been obtained by group read and using special events cycles,
> +     ref-cycles, msr/tsc/, msr/aperf/ or msr/mperf/
> +     Freq MHz: The frequency during the sample interval. Needs cycles and
> +               ref-cycles event.
> +     CPU%: CPU utilization during the sample interval. Needs ref-cycles and
> +           msr/tsc/ events.
> +     CORE_BUSY%: actual percent performance (APERF/MPERF%) during the
> +                 sample interval. Needs msr/aperf/ and msr/mperf/ events.
> +
>  --percent-limit::
>       Do not show entries which have an overhead under that percent.
>       (Default: 0).
> diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> index 7673f1c..ebcbe4c 100644
> --- a/tools/perf/builtin-report.c
> +++ b/tools/perf/builtin-report.c
> @@ -133,7 +133,8 @@ static int hist_iter__report_callback(struct 
> hist_entry_iter *iter,
>       struct branch_info *bi;
>  
>       if ((iter->ops == &hist_iter_normal) &&
> -         perf_evsel__is_group_leader(evsel))
> +         perf_evsel__is_group_leader(evsel) &&
> +         symbol_conf.show_freq_perf)
>               set_he_freq_perf(rep->session, iter);
>  
>       if (!ui__has_annotation())
> @@ -772,6 +773,8 @@ int cmd_report(int argc, const char **argv, const char 
> *prefix __maybe_unused)
>       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
>                   "Enable kernel symbol demangling"),
>       OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
> +     OPT_BOOLEAN(0, "show-freq-perf", &symbol_conf.show_freq_perf,
> +                 "show CPU freqency and performance info"),
>       OPT_CALLBACK(0, "percent-limit", &report, "percent",
>                    "Don't show entries under that percent", 
> parse_percent_limit),
>       OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
> @@ -788,7 +791,9 @@ int cmd_report(int argc, const char **argv, const char 
> *prefix __maybe_unused)
>       struct perf_data_file file = {
>               .mode  = PERF_DATA_MODE_READ,
>       };
> +     struct perf_evsel *pos;
>       int ret = hists__init();
> +     perf_freq_t freq_data_status = { 0 };
>  
>       if (ret < 0)
>               return ret;
> @@ -873,6 +878,21 @@ repeat:
>               symbol_conf.cumulate_callchain = false;
>       }
>  
> +
> +     if (symbol_conf.show_freq_perf) {
> +             symbol_conf.freq_perf_type = 0;
> +             evlist__for_each(session->evlist, pos) {
> +                     perf_freq__init(session->header.env.msr_pmu_type,
> +                                     pos, freq_data_status, 1);
> +             }
> +             if (perf_freq__has_freq(freq_data_status))
> +                     symbol_conf.freq_perf_type |= 1U << DISPLAY_FREQ;
> +             if (perf_freq__has_cpu_util(freq_data_status))
> +                     symbol_conf.freq_perf_type |= 1U << DISPLAY_CPU_UTIL;
> +             if (perf_freq__has_core_busy(freq_data_status))
> +                     symbol_conf.freq_perf_type |= 1U << DISPLAY_CORE_BUSY;
> +     }
> +
>       if (setup_sorting() < 0) {
>               if (sort_order)
>                       parse_options_usage(report_usage, options, "s", 1);
> diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
> index 25d6083..c2be455 100644
> --- a/tools/perf/ui/hist.c
> +++ b/tools/perf/ui/hist.c
> @@ -17,7 +17,7 @@
>  
>  static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
>                     hpp_field_fn get_field, const char *fmt, int len,
> -                   hpp_snprint_fn print_fn, bool fmt_percent)
> +                   hpp_snprint_fn print_fn, bool fmt_percent, bool single)
>  {
>       int ret;
>       struct hists *hists = he->hists;
> @@ -36,7 +36,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct 
> hist_entry *he,
>       } else
>               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, 
> get_field(he));
>  
> -     if (perf_evsel__is_group_event(evsel)) {
> +     if (perf_evsel__is_group_event(evsel) && !single) {
>               int prev_idx, idx_delta;
>               struct hist_entry *pair;
>               int nr_members = evsel->nr_members;
> @@ -109,10 +109,16 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp 
> *hpp,
>            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
>  {
>       int len = fmt->user_len ?: fmt->len;
> +     bool single = false;
> +
> +     if (((fmt == &perf_hpp__format[PERF_HPP__FREQ]) ||
> +          (fmt == &perf_hpp__format[PERF_HPP__CPU_UTIL]) ||
> +          (fmt == &perf_hpp__format[PERF_HPP__CORE_BUSY])))
> +             single = true;
>  
>       if (symbol_conf.field_sep) {
>               return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
> -                               print_fn, fmt_percent);
> +                               print_fn, fmt_percent, single);
>       }
>  
>       if (fmt_percent)
> @@ -120,7 +126,7 @@ int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp 
> *hpp,
>       else
>               len -= 1;
>  
> -     return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, 
> fmt_percent);
> +     return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, 
> fmt_percent, single);
>  }
>  
>  int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
> @@ -234,6 +240,30 @@ static int hpp__header_fn(struct perf_hpp_fmt *fmt, 
> struct perf_hpp *hpp,
>       return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
>  }
>  
> +static int hpp__single_width_fn(struct perf_hpp_fmt *fmt,
> +                      struct perf_hpp *hpp __maybe_unused,
> +                      struct perf_evsel *evsel)
> +{
> +     int len = fmt->user_len ?: fmt->len;
> +
> +     if (symbol_conf.event_group && !symbol_conf.show_freq_perf)
> +             len = max(len, evsel->nr_members * fmt->len);
> +
> +     if (len < (int)strlen(fmt->name))
> +             len = strlen(fmt->name);
> +
> +     return len;
> +}
> +
> +static int hpp__single_header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp 
> *hpp,
> +                       struct perf_evsel *evsel)
> +{
> +     int len = hpp__single_width_fn(fmt, hpp, evsel);
> +
> +     return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
> +}
> +
> +
>  static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
>  {
>       va_list args;
> @@ -363,6 +393,9 @@ HPP_PERCENT_ACC_FNS(overhead_acc, period)
>  
>  HPP_RAW_FNS(samples, nr_events)
>  HPP_RAW_FNS(period, period)
> +HPP_RAW_FNS(freq, freq)
> +HPP_RAW_FNS(cpu_util, cpu_util)
> +HPP_RAW_FNS(core_busy, core_busy)
>  
>  static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
>                           struct hist_entry *a __maybe_unused,
> @@ -395,6 +428,17 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt 
> __maybe_unused,
>               .sort   = hpp__sort_ ## _fn,            \
>       }
>  
> +#define HPP__SINGLE_PRINT_FNS(_name, _fn)            \
> +     {                                               \
> +             .name   = _name,                        \
> +             .header = hpp__single_header_fn,        \
> +             .width  = hpp__single_width_fn,         \
> +             .entry  = hpp__entry_ ## _fn,           \
> +             .cmp    = hpp__nop_cmp,                 \
> +             .collapse = hpp__nop_cmp,               \
> +             .sort   = hpp__sort_ ## _fn,            \
> +     }
> +
>  #define HPP__PRINT_FNS(_name, _fn)                   \
>       {                                               \
>               .name   = _name,                        \
> @@ -414,7 +458,10 @@ struct perf_hpp_fmt perf_hpp__format[] = {
>       HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
>       HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
>       HPP__PRINT_FNS("Samples", samples),
> -     HPP__PRINT_FNS("Period", period)
> +     HPP__PRINT_FNS("Period", period),
> +     HPP__SINGLE_PRINT_FNS("FREQ MHz", freq),
> +     HPP__SINGLE_PRINT_FNS("CPU%", cpu_util),
> +     HPP__SINGLE_PRINT_FNS("CORE_BUSY%", core_busy)
>  };
>  
>  LIST_HEAD(perf_hpp__list);
> @@ -485,6 +532,15 @@ void perf_hpp__init(void)
>       if (symbol_conf.show_total_period)
>               perf_hpp__column_enable(PERF_HPP__PERIOD);
>  
> +     if (symbol_conf.show_freq_perf) {
> +             if (symbol_conf.freq_perf_type & (1U << DISPLAY_FREQ))
> +                     perf_hpp__column_enable(PERF_HPP__FREQ);
> +             if (symbol_conf.freq_perf_type & (1U << DISPLAY_CPU_UTIL))
> +                     perf_hpp__column_enable(PERF_HPP__CPU_UTIL);
> +             if (symbol_conf.freq_perf_type & (1U << DISPLAY_CORE_BUSY))
> +                     perf_hpp__column_enable(PERF_HPP__CORE_BUSY);
> +     }
> +
>       /* prepend overhead field for backward compatiblity.  */
>       list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
>       if (list_empty(list))
> @@ -652,6 +708,9 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, 
> struct hists *hists)
>               return;
>  
>       switch (idx) {
> +     case PERF_HPP__CPU_UTIL:
> +             fmt->len = 5;
> +             break;
>       case PERF_HPP__OVERHEAD:
>       case PERF_HPP__OVERHEAD_SYS:
>       case PERF_HPP__OVERHEAD_US:
> @@ -661,6 +720,8 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, 
> struct hists *hists)
>  
>       case PERF_HPP__OVERHEAD_GUEST_SYS:
>       case PERF_HPP__OVERHEAD_GUEST_US:
> +     case PERF_HPP__FREQ:
> +     case PERF_HPP__CORE_BUSY:
>               fmt->len = 9;
>               break;
>  
> diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
> index de6d58e..df07f28 100644
> --- a/tools/perf/util/hist.h
> +++ b/tools/perf/util/hist.h
> @@ -237,6 +237,9 @@ enum {
>       PERF_HPP__OVERHEAD_ACC,
>       PERF_HPP__SAMPLES,
>       PERF_HPP__PERIOD,
> +     PERF_HPP__FREQ,
> +     PERF_HPP__CPU_UTIL,
> +     PERF_HPP__CORE_BUSY,
>  
>       PERF_HPP__MAX_INDEX
>  };
> diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
> index ba763f7..071fe65 100644
> --- a/tools/perf/util/session.c
> +++ b/tools/perf/util/session.c
> @@ -908,26 +908,29 @@ static void sample_read__printf(struct perf_sample 
> *sample,
>                       printf("..... id %016" PRIx64
>                              ", value %016" PRIx64 "\n",
>                              value->id, value->value);
> -
> -                     sid = perf_evlist__id2sid(evlist, value->id);
> -                     evsel = sid->evsel;
> -                     if (evsel != NULL)
> -                             perf_freq__init(evlist->env->msr_pmu_type,
> -                                             evsel, data, value->value);
> +                     if (symbol_conf.show_freq_perf) {
> +                             sid = perf_evlist__id2sid(evlist, value->id);
> +                             evsel = sid->evsel;
> +                             if (evsel != NULL)
> +                                     
> perf_freq__init(evlist->env->msr_pmu_type,
> +                                                     evsel, data, 
> value->value);
> +                     }
>               }
>       } else
>               printf("..... id %016" PRIx64 ", value %016" PRIx64 "\n",
>                       sample->read.one.id, sample->read.one.value);
>  
> -     if (perf_freq__has_freq(data))
> -             printf("..... Freq %lu MHz\n",
> -                    perf_freq__get_freq(data, cpu_max_freq/1000));
> -     if (perf_freq__has_cpu_util(data))
> -             printf("..... CPU%% %lu%%\n",
> -                    perf_freq__get_cpu_util(data));
> -     if (perf_freq__has_core_busy(data))
> -             printf("..... CORE_BUSY%% %lu%%\n",
> -                    perf_freq__get_core_busy(data));
> +     if (symbol_conf.show_freq_perf) {
> +             if (perf_freq__has_freq(data))
> +                     printf("..... Freq %lu MHz\n",
> +                            perf_freq__get_freq(data, cpu_max_freq/1000));
> +             if (perf_freq__has_cpu_util(data))
> +                     printf("..... CPU%% %lu%%\n",
> +                            perf_freq__get_cpu_util(data));
> +             if (perf_freq__has_core_busy(data))
> +                     printf("..... CORE_BUSY%% %lu%%\n",
> +                            perf_freq__get_core_busy(data));
> +     }
>  }
>  
>  static void dump_event(struct perf_evlist *evlist, union perf_event *event,
> diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
> index a97bcee..1d5c7d8 100644
> --- a/tools/perf/util/sort.c
> +++ b/tools/perf/util/sort.c
> @@ -1303,6 +1303,9 @@ static struct hpp_dimension hpp_sort_dimensions[] = {
>       DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
>       DIM(PERF_HPP__SAMPLES, "sample"),
>       DIM(PERF_HPP__PERIOD, "period"),
> +     DIM(PERF_HPP__FREQ, "freq"),
> +     DIM(PERF_HPP__CPU_UTIL, "cpu_u"),
> +     DIM(PERF_HPP__CORE_BUSY, "core_busy"),
>  };
>  
>  #undef DIM
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 440ba8a..8b21fb4 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -80,6 +80,14 @@ static inline size_t symbol__size(const struct symbol *sym)
>  struct strlist;
>  struct intlist;
>  
> +enum freq_perf_type_index {
> +     DISPLAY_FREQ            = 0,
> +     DISPLAY_CPU_UTIL,
> +     DISPLAY_CORE_BUSY,
> +
> +     DISPLAY_MAX
> +};
> +
>  struct symbol_conf {
>       unsigned short  priv_size;
>       unsigned short  nr_events;
> @@ -107,7 +115,8 @@ struct symbol_conf {
>                       show_hist_headers,
>                       branch_callstack,
>                       has_filter,
> -                     show_ref_callgraph;
> +                     show_ref_callgraph,
> +                     show_freq_perf;
>       const char      *vmlinux_name,
>                       *kallsyms_name,
>                       *source_prefix,
> @@ -132,6 +141,7 @@ struct symbol_conf {
>       struct intlist  *pid_list,
>                       *tid_list;
>       const char      *symfs;
> +     u64             freq_perf_type;
>  };
>  
>  extern struct symbol_conf symbol_conf;
> -- 
> 1.8.3.1
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to