These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / tools / perf / builtin-report.c
index b63aeda..f256fac 100644 (file)
 #include "util/data.h"
 #include "arch/common.h"
 
+#include "util/auxtrace.h"
+
 #include <dlfcn.h>
 #include <linux/bitmap.h>
 
 struct report {
        struct perf_tool        tool;
        struct perf_session     *session;
-       bool                    force, use_tui, use_gtk, use_stdio;
+       bool                    use_tui, use_gtk, use_stdio;
        bool                    hide_unresolved;
        bool                    dont_use_callchains;
        bool                    show_full_info;
@@ -51,6 +53,7 @@ struct report {
        bool                    mem_mode;
        bool                    header;
        bool                    header_only;
+       bool                    nonany_branch_mode;
        int                     max_stack;
        struct perf_read_values show_threads_values;
        const char              *pretty_printing_style;
@@ -59,6 +62,7 @@ struct report {
        float                   min_percent;
        u64                     nr_entries;
        u64                     queue_size;
+       int                     socket_filter;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
@@ -100,6 +104,9 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,
        if (!ui__has_annotation())
                return 0;
 
+       hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
+                            rep->nonany_branch_mode);
+
        if (sort__mode == SORT_MODE__BRANCH) {
                bi = he->branch_info;
                err = addr_map_symbol__inc_samples(&bi->from, evsel->idx);
@@ -137,10 +144,12 @@ static int process_sample_event(struct perf_tool *tool,
        struct report *rep = container_of(tool, struct report, tool);
        struct addr_location al;
        struct hist_entry_iter iter = {
-               .hide_unresolved = rep->hide_unresolved,
-               .add_entry_cb = hist_iter__report_callback,
+               .evsel                  = evsel,
+               .sample                 = sample,
+               .hide_unresolved        = rep->hide_unresolved,
+               .add_entry_cb           = hist_iter__report_callback,
        };
-       int ret;
+       int ret = 0;
 
        if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
                pr_debug("problem processing %d event, skipping it.\n",
@@ -149,28 +158,35 @@ static int process_sample_event(struct perf_tool *tool,
        }
 
        if (rep->hide_unresolved && al.sym == NULL)
-               return 0;
+               goto out_put;
 
        if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
-               return 0;
+               goto out_put;
 
-       if (sort__mode == SORT_MODE__BRANCH)
+       if (sort__mode == SORT_MODE__BRANCH) {
+               /*
+                * A non-synthesized event might not have a branch stack if
+                * branch stacks have been synthesized (using itrace options).
+                */
+               if (!sample->branch_stack)
+                       goto out_put;
                iter.ops = &hist_iter_branch;
-       else if (rep->mem_mode)
+       } else if (rep->mem_mode) {
                iter.ops = &hist_iter_mem;
-       else if (symbol_conf.cumulate_callchain)
+       } else if (symbol_conf.cumulate_callchain) {
                iter.ops = &hist_iter_cumulative;
-       else
+       } else {
                iter.ops = &hist_iter_normal;
+       }
 
        if (al.map != NULL)
                al.map->dso->hit = 1;
 
-       ret = hist_entry_iter__add(&iter, &al, evsel, sample, rep->max_stack,
-                                  rep);
+       ret = hist_entry_iter__add(&iter, &al, rep->max_stack, rep);
        if (ret < 0)
                pr_debug("problem adding hist entry, skipping event\n");
-
+out_put:
+       addr_location__put(&al);
        return ret;
 }
 
@@ -205,6 +221,15 @@ static int report__setup_sample_type(struct report *rep)
        u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
        bool is_pipe = perf_data_file__is_pipe(session->file);
 
+       if (session->itrace_synth_opts->callchain ||
+           (!is_pipe &&
+            perf_header__has_feat(&session->header, HEADER_AUXTRACE) &&
+            !session->itrace_synth_opts->set))
+               sample_type |= PERF_SAMPLE_CALLCHAIN;
+
+       if (session->itrace_synth_opts->last_branch)
+               sample_type |= PERF_SAMPLE_BRANCH_STACK;
+
        if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        ui__error("Selected --sort parent, but no "
@@ -254,6 +279,12 @@ static int report__setup_sample_type(struct report *rep)
                else
                        callchain_param.record_mode = CALLCHAIN_FP;
        }
+
+       /* ??? handle more cases than just ANY? */
+       if (!(perf_evlist__combined_branch_type(session->evlist) &
+                               PERF_SAMPLE_BRANCH_ANY))
+               rep->nonany_branch_mode = true;
+
        return 0;
 }
 
@@ -272,6 +303,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
        struct perf_evsel *evsel = hists_to_evsel(hists);
        char buf[512];
        size_t size = sizeof(buf);
+       int socked_id = hists->socket_filter;
 
        if (symbol_conf.filter_relative) {
                nr_samples = hists->stats.nr_non_filtered_samples;
@@ -302,11 +334,20 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
        if (evname != NULL)
                ret += fprintf(fp, " of event '%s'", evname);
 
+       if (symbol_conf.show_ref_callgraph &&
+           strstr(evname, "call-graph=no")) {
+               ret += fprintf(fp, ", show reference callgraph");
+       }
+
        if (rep->mem_mode) {
                ret += fprintf(fp, "\n# Total weight : %" PRIu64, nr_events);
                ret += fprintf(fp, "\n# Sort order   : %s", sort_order ? : default_mem_sort_order);
        } else
                ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
+
+       if (socked_id > -1)
+               ret += fprintf(fp, "\n# Processor Socket: %d", socked_id);
+
        return ret + fprintf(fp, "\n#\n");
 }
 
@@ -316,6 +357,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 {
        struct perf_evsel *pos;
 
+       fprintf(stdout, "#\n# Total Lost Samples: %" PRIu64 "\n#\n", evlist->stats.total_lost_samples);
        evlist__for_each(evlist, pos) {
                struct hists *hists = evsel__hists(pos);
                const char *evname = perf_evsel__name(pos);
@@ -330,15 +372,14 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
        }
 
        if (sort_order == NULL &&
-           parent_pattern == default_parent_pattern) {
+           parent_pattern == default_parent_pattern)
                fprintf(stdout, "#\n# (%s)\n#\n", help);
 
-               if (rep->show_threads) {
-                       bool style = !strcmp(rep->pretty_printing_style, "raw");
-                       perf_read_values_display(stdout, &rep->show_threads_values,
-                                                style);
-                       perf_read_values_destroy(&rep->show_threads_values);
-               }
+       if (rep->show_threads) {
+               bool style = !strcmp(rep->pretty_printing_style, "raw");
+               perf_read_values_display(stdout, &rep->show_threads_values,
+                                        style);
+               perf_read_values_destroy(&rep->show_threads_values);
        }
 
        return 0;
@@ -346,7 +387,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
 
 static void report__warn_kptr_restrict(const struct report *rep)
 {
-       struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION];
+       struct map *kernel_map = machine__kernel_map(&rep->session->machines.host);
        struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL;
 
        if (kernel_map == NULL ||
@@ -431,6 +472,8 @@ static void report__collapse_hists(struct report *rep)
                if (pos->idx == 0)
                        hists->symbol_filter_str = rep->symbol_filter_str;
 
+               hists->socket_filter = rep->socket_filter;
+
                hists__collapse_resort(hists, &prog);
 
                /* Non-group events are considered as leader */
@@ -582,14 +625,21 @@ parse_percent_limit(const struct option *opt, const char *str,
        return 0;
 }
 
+#define CALLCHAIN_DEFAULT_OPT  "graph,0.5,caller,function"
+
+const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
+                                    CALLCHAIN_REPORT_HELP
+                                    "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT;
+
 int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        struct perf_session *session;
+       struct itrace_synth_opts itrace_synth_opts = { .set = 0, };
        struct stat st;
        bool has_br_stack = false;
        int branch_mode = -1;
        bool branch_call_mode = false;
-       char callchain_default_opt[] = "fractal,0.5,callee";
+       char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT;
        const char * const report_usage[] = {
                "perf report [<options>]",
                NULL
@@ -607,11 +657,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = perf_event__process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
+                       .id_index        = perf_event__process_id_index,
+                       .auxtrace_info   = perf_event__process_auxtrace_info,
+                       .auxtrace        = perf_event__process_auxtrace,
                        .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
                .max_stack               = PERF_MAX_STACK_DEPTH,
                .pretty_printing_style   = "normal",
+               .socket_filter           = -1,
        };
        const struct option options[] = {
        OPT_STRING('i', "input", &input_name, "file",
@@ -624,7 +678,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   "file", "vmlinux pathname"),
        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
                   "file", "kallsyms pathname"),
-       OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
+       OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
        OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
@@ -645,15 +699,18 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                   " Please refer the man page for the complete list."),
        OPT_STRING('F', "fields", &field_order, "key[,keys...]",
                   "output field(s): overhead, period, sample plus all of sort keys"),
-       OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
+       OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization,
                    "Show sample percentage for different cpu modes"),
+       OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
+                   "Show sample percentage for different cpu modes", PARSE_OPT_HIDDEN),
        OPT_STRING('p', "parent", &parent_pattern, "regex",
                   "regex filter to identify parent, see: '--sort parent'"),
        OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
                    "Only display entries with parent-match"),
-       OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
-                    "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
-                    "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
+       OPT_CALLBACK_DEFAULT('g', "call-graph", &report,
+                            "print_type,threshold[,print_limit],order,sort_key[,branch]",
+                            report_callchain_help, &report_parse_callchain_opt,
+                            callchain_default_opt),
        OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
                    "Accumulate callchains of children and show total overhead as well"),
        OPT_INTEGER(0, "max-stack", &report.max_stack,
@@ -717,6 +774,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Don't show entries under that percent", parse_percent_limit),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "how to display percentage of filtered entries", parse_filter_percentage),
+       OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
+                           "Instruction Tracing options",
+                           itrace_parse_synth_opts),
+       OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
+                       "Show full source file name path for source lines"),
+       OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
+                   "Show callgraph from reference event"),
+       OPT_INTEGER(0, "socket-filter", &report.socket_filter,
+                   "only show processor socket that match with this filter"),
        OPT_END()
        };
        struct perf_data_file file = {
@@ -731,6 +797,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 
        argc = parse_options(argc, argv, options, report_usage, 0);
 
+       if (symbol_conf.vmlinux_name &&
+           access(symbol_conf.vmlinux_name, R_OK)) {
+               pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
+               return -EINVAL;
+       }
+       if (symbol_conf.kallsyms_name &&
+           access(symbol_conf.kallsyms_name, R_OK)) {
+               pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
+               return -EINVAL;
+       }
+
        if (report.use_stdio)
                use_browser = 0;
        else if (report.use_tui)
@@ -740,6 +817,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 
        if (report.inverted_callchain)
                callchain_param.order = ORDER_CALLER;
+       if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
+               callchain_param.order = ORDER_CALLER;
+
+       if (itrace_synth_opts.callchain &&
+           (int)itrace_synth_opts.callchain_sz > report.max_stack)
+               report.max_stack = itrace_synth_opts.callchain_sz;
 
        if (!input_name || !strlen(input_name)) {
                if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
@@ -749,7 +832,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
        }
 
        file.path  = input_name;
-       file.force = report.force;
+       file.force = symbol_conf.force;
 
 repeat:
        session = perf_session__new(&file, false, &report.tool);
@@ -761,11 +844,16 @@ repeat:
                                               report.queue_size);
        }
 
+       session->itrace_synth_opts = &itrace_synth_opts;
+
        report.session = session;
 
        has_br_stack = perf_header__has_feat(&session->header,
                                             HEADER_BRANCH_STACK);
 
+       if (itrace_synth_opts.last_branch)
+               has_br_stack = true;
+
        /*
         * Branch mode is a tristate:
         * -1 means default, so decide based on the file having branch data.
@@ -803,8 +891,8 @@ repeat:
                goto error;
        }
 
-       /* Force tty output for header output. */
-       if (report.header || report.header_only)
+       /* Force tty output for header output and per-thread stat. */
+       if (report.header || report.header_only || report.show_threads)
                use_browser = 0;
 
        if (strcmp(input_name, "-") != 0)
@@ -815,8 +903,10 @@ repeat:
        if (report.header || report.header_only) {
                perf_session__fprintf_info(session, stdout,
                                           report.show_full_info);
-               if (report.header_only)
-                       return 0;
+               if (report.header_only) {
+                       ret = 0;
+                       goto error;
+               }
        } else if (use_browser == 0) {
                fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
                      stdout);