X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=tools%2Fperf%2Fbuiltin-report.c;h=196473b51257544473885b1c3973fdaaffe9a0d3;hb=e157eb8341e7885ff2d9f1620155e3da6e0c8f56;hp=508934b0140a5f4155410e0ea5d558cdff0f1bd6;hpb=55aa640f54280da25046acd2075842d464f451e6;p=safe%2Fjmp%2Flinux-2.6 diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 508934b..196473b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -14,7 +14,6 @@ #include "util/cache.h" #include #include "util/symbol.h" -#include "util/string.h" #include "util/callchain.h" #include "util/strlist.h" #include "util/values.h" @@ -33,9 +32,11 @@ static char const *input_name = "perf.data"; -static int force; +static bool force; +static bool hide_unresolved; +static bool dont_use_callchains; -static int show_threads; +static bool show_threads; static struct perf_read_values show_threads_values; static char default_pretty_printing_style[] = "normal"; @@ -43,29 +44,80 @@ static char *pretty_printing_style = default_pretty_printing_style; static char callchain_default_opt[] = "fractal,0.5"; +static struct event_stat_id *get_stats(struct perf_session *self, + u64 event_stream, u32 type, u64 config) +{ + struct rb_node **p = &self->stats_by_id.rb_node; + struct rb_node *parent = NULL; + struct event_stat_id *iter, *new; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct event_stat_id, rb_node); + if (iter->config == config) + return iter; + + + if (config > iter->config) + p = &(*p)->rb_right; + else + p = &(*p)->rb_left; + } + + new = malloc(sizeof(struct event_stat_id)); + if (new == NULL) + return NULL; + memset(new, 0, sizeof(struct event_stat_id)); + new->event_stream = event_stream; + new->config = config; + new->type = type; + rb_link_node(&new->rb_node, parent, p); + rb_insert_color(&new->rb_node, &self->stats_by_id); + return new; +} + static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, - struct ip_callchain *chain, u64 count) + struct sample_data *data) { - struct symbol **syms = NULL, *parent = NULL; + struct map_symbol *syms = NULL; + struct symbol *parent = NULL; bool hit; + int err; struct hist_entry *he; + struct event_stat_id *stats; + struct perf_event_attr *attr; - if ((sort__has_parent || symbol_conf.use_callchain) && chain) + if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { syms = perf_session__resolve_callchain(self, al->thread, - chain, &parent); - he = __perf_session__add_hist_entry(self, al, parent, count, &hit); + data->callchain, &parent); + if (syms == NULL) + return -ENOMEM; + } + + attr = perf_header__find_attr(data->id, &self->header); + if (attr) + stats = get_stats(self, data->id, attr->type, attr->config); + else + stats = get_stats(self, data->id, 0, 0); + if (stats == NULL) + return -ENOMEM; + he = __perf_session__add_hist_entry(&stats->hists, al, parent, + data->period, &hit); if (he == NULL) return -ENOMEM; if (hit) - he->count += count; + __perf_session__add_count(he, al, data->period); if (symbol_conf.use_callchain) { if (!hit) - callchain_init(&he->callchain); - append_chain(&he->callchain, chain, syms); + callchain_init(he->callchain); + err = append_chain(he->callchain, data->callchain, syms); free(syms); + + if (err) + return err; } return 0; @@ -84,18 +136,35 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) return 0; } +static int add_event_total(struct perf_session *session, + struct sample_data *data, + struct perf_event_attr *attr) +{ + struct event_stat_id *stats; + + if (attr) + stats = get_stats(session, data->id, attr->type, attr->config); + else + stats = get_stats(session, data->id, 0, 0); + + if (!stats) + return -ENOMEM; + + stats->stats.total += data->period; + session->events_stats.total += data->period; + return 0; +} + static int process_sample_event(event_t *event, struct perf_session *session) { struct sample_data data = { .period = 1, }; struct addr_location al; + struct perf_event_attr *attr; event__parse_sample(event, session->sample_type, &data); - dump_printf("(IP, %d): %d/%d: %p period: %Ld\n", - event->header.misc, - data.pid, data.tid, - (void *)(long)data.ip, - (long long)data.period); + dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc, + data.pid, data.tid, data.ip, data.period); if (session->sample_type & PERF_SAMPLE_CALLCHAIN) { unsigned int i; @@ -121,15 +190,21 @@ static int process_sample_event(event_t *event, struct perf_session *session) return -1; } - if (al.filtered) + if (al.filtered || (hide_unresolved && al.sym == NULL)) return 0; - if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { + if (perf_session__add_hist_entry(session, &al, &data)) { pr_debug("problem incrementing symbol count, skipping event\n"); return -1; } - session->events_stats.total += data.period; + attr = perf_header__find_attr(data.id, &session->header); + + if (add_event_total(session, &data, attr)) { + pr_debug("problem adding event count\n"); + return -1; + } + return 0; } @@ -171,7 +246,8 @@ static int perf_session__setup_sample_type(struct perf_session *self) " -g?\n"); return -1; } - } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { + } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && + !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (register_callchain_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" @@ -191,14 +267,29 @@ static struct perf_event_ops event_ops = { .fork = event__process_task, .lost = event__process_lost, .read = process_read_event, + .attr = event__process_attr, + .event_type = event__process_event_type, + .tracing_data = event__process_tracing_data, + .build_id = event__process_build_id, }; +extern volatile int session_done; + +static void sig_handler(int sig __attribute__((__unused__))) +{ + session_done = 1; +} + static int __cmd_report(void) { int ret = -EINVAL; struct perf_session *session; + struct rb_node *next; + const char *help = "For a higher level overview, try: perf report --sort comm,dso"; + + signal(SIGINT, sig_handler); - session = perf_session__new(input_name, O_RDONLY, force); + session = perf_session__new(input_name, O_RDONLY, force, false); if (session == NULL) return -ENOMEM; @@ -222,21 +313,49 @@ static int __cmd_report(void) perf_session__fprintf(session, stdout); if (verbose > 2) - dsos__fprintf(stdout); + perf_session__fprintf_dsos(session, stdout); + + next = rb_first(&session->stats_by_id); + while (next) { + struct event_stat_id *stats; + u64 nr_hists; + + stats = rb_entry(next, struct event_stat_id, rb_node); + perf_session__collapse_resort(&stats->hists); + nr_hists = perf_session__output_resort(&stats->hists, + stats->stats.total); + if (use_browser) + perf_session__browse_hists(&stats->hists, nr_hists, + stats->stats.total, help, + input_name); + else { + if (rb_first(&session->stats_by_id) == + rb_last(&session->stats_by_id)) + fprintf(stdout, "# Samples: %Ld\n#\n", + stats->stats.total); + else + fprintf(stdout, "# Samples: %Ld %s\n#\n", + stats->stats.total, + __event_name(stats->type, stats->config)); + + perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, + stats->stats.total); + fprintf(stdout, "\n\n"); + } - perf_session__collapse_resort(session); - perf_session__output_resort(session, session->events_stats.total); - fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); - perf_session__fprintf_hists(session, NULL, false, stdout); - if (sort_order == default_sort_order && - parent_pattern == default_parent_pattern) - fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); + next = rb_next(&stats->rb_node); + } - if (show_threads) { - bool raw_printing_style = !strcmp(pretty_printing_style, "raw"); - perf_read_values_display(stdout, &show_threads_values, - raw_printing_style); - perf_read_values_destroy(&show_threads_values); + if (!use_browser && sort_order == default_sort_order && + parent_pattern == default_parent_pattern) { + fprintf(stdout, "#\n# (%s)\n#\n", help); + + if (show_threads) { + bool style = !strcmp(pretty_printing_style, "raw"); + perf_read_values_display(stdout, &show_threads_values, + style); + perf_read_values_destroy(&show_threads_values); + } } out_delete: perf_session__delete(session); @@ -245,11 +364,19 @@ out_delete: static int parse_callchain_opt(const struct option *opt __used, const char *arg, - int unset __used) + int unset) { char *tok; char *endptr; + /* + * --no-call-graph + */ + if (unset) { + dont_use_callchains = true; + return 0; + } + symbol_conf.use_callchain = true; if (!arg) @@ -271,7 +398,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, else if (!strncmp(tok, "none", strlen(arg))) { callchain_param.mode = CHAIN_NONE; - symbol_conf.use_callchain = true; + symbol_conf.use_callchain = false; return 0; } @@ -304,7 +431,7 @@ static const char * const report_usage[] = { static const struct option options[] = { OPT_STRING('i', "input", &input_name, "file", "input file name"), - OPT_BOOLEAN('v', "verbose", &verbose, + OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), @@ -323,12 +450,14 @@ static const struct option options[] = { "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths, "Don't shorten the pathnames taking into account the cwd"), + OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, + "Show sample percentage for different cpu modes"), 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", NULL, "output_type,min_percent", - "Display callchains using output_type and min percent threshold. " + "Display callchains using output_type (graph, flat, fractal, or none) and min percent threshold. " "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), @@ -342,6 +471,8 @@ static const struct option options[] = { OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), + OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, + "Only display entries resolved to a symbol"), OPT_END() }; @@ -349,7 +480,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) { argc = parse_options(argc, argv, options, report_usage, 0); - setup_pager(); + if (strcmp(input_name, "-") != 0) + setup_browser(); if (symbol__init() < 0) return -1; @@ -357,7 +489,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) setup_sorting(report_usage, options); if (parent_pattern != default_parent_pattern) { - sort_dimension__add("parent"); + if (sort_dimension__add("parent") < 0) + return -1; sort_parent.elide = 1; } else symbol_conf.exclude_other = false;