Commit d599db3f authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by Ingo Molnar

perf report: Generalize perf_session__fprintf_hists()

Pull it out of builtin-report - further changes will be made and it
will then be reusable in 'perf diff' as well.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
LKML-Reference: <1260914682-29652-4-git-send-email-acme@infradead.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent c410a338
...@@ -34,9 +34,6 @@ ...@@ -34,9 +34,6 @@
static char const *input_name = "perf.data"; static char const *input_name = "perf.data";
static int force; static int force;
static bool use_callchain;
static int show_nr_samples;
static int show_threads; static int show_threads;
static struct perf_read_values show_threads_values; static struct perf_read_values show_threads_values;
...@@ -44,8 +41,6 @@ static struct perf_read_values show_threads_values; ...@@ -44,8 +41,6 @@ static struct perf_read_values show_threads_values;
static char default_pretty_printing_style[] = "normal"; static char default_pretty_printing_style[] = "normal";
static char *pretty_printing_style = default_pretty_printing_style; static char *pretty_printing_style = default_pretty_printing_style;
static int exclude_other = 1;
static char callchain_default_opt[] = "fractal,0.5"; static char callchain_default_opt[] = "fractal,0.5";
static size_t static size_t
...@@ -305,23 +300,22 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, ...@@ -305,23 +300,22 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
} }
static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self,
struct perf_session *session, struct perf_session *session)
u64 total_samples)
{ {
struct sort_entry *se; struct sort_entry *se;
size_t ret; size_t ret;
if (exclude_other && !self->parent) if (symbol_conf.exclude_other && !self->parent)
return 0; return 0;
if (total_samples) if (session->events_stats.total)
ret = percent_color_fprintf(fp, ret = percent_color_fprintf(fp,
symbol_conf.field_sep ? "%.2f" : " %6.2f%%", symbol_conf.field_sep ? "%.2f" : " %6.2f%%",
(self->count * 100.0) / total_samples); (self->count * 100.0) / session->events_stats.total);
else else
ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count); ret = fprintf(fp, symbol_conf.field_sep ? "%lld" : "%12lld ", self->count);
if (show_nr_samples) { if (symbol_conf.show_nr_samples) {
if (symbol_conf.field_sep) if (symbol_conf.field_sep)
fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count); fprintf(fp, "%c%lld", *symbol_conf.field_sep, self->count);
else else
...@@ -338,7 +332,7 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, ...@@ -338,7 +332,7 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self,
ret += fprintf(fp, "\n"); ret += fprintf(fp, "\n");
if (session->use_callchain) { if (symbol_conf.use_callchain) {
int left_margin = 0; int left_margin = 0;
if (sort__first_dimension == SORT_COMM) { if (sort__first_dimension == SORT_COMM) {
...@@ -348,41 +342,13 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self, ...@@ -348,41 +342,13 @@ static size_t hist_entry__fprintf(FILE *fp, struct hist_entry *self,
left_margin -= thread__comm_len(self->thread); left_margin -= thread__comm_len(self->thread);
} }
hist_entry_callchain__fprintf(fp, self, total_samples, hist_entry_callchain__fprintf(fp, self, session->events_stats.total,
left_margin); left_margin);
} }
return ret; return ret;
} }
static void thread__comm_adjust(struct thread *self)
{
char *comm = self->comm;
if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
(!symbol_conf.comm_list ||
strlist__has_entry(symbol_conf.comm_list, comm))) {
unsigned int slen = strlen(comm);
if (slen > comms__col_width) {
comms__col_width = slen;
threads__col_width = slen + 6;
}
}
}
static int thread__set_comm_adjust(struct thread *self, const char *comm)
{
int ret = thread__set_comm(self, comm);
if (ret)
return ret;
thread__comm_adjust(self);
return 0;
}
/* /*
* collect histogram counts * collect histogram counts
*/ */
...@@ -395,7 +361,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, ...@@ -395,7 +361,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
bool hit; bool hit;
struct hist_entry *he; struct hist_entry *he;
if ((sort__has_parent || self->use_callchain) && chain) if ((sort__has_parent || symbol_conf.use_callchain) && chain)
syms = perf_session__resolve_callchain(self, al->thread, syms = perf_session__resolve_callchain(self, al->thread,
chain, &parent); chain, &parent);
he = __perf_session__add_hist_entry(self, al, parent, count, &hit); he = __perf_session__add_hist_entry(self, al, parent, count, &hit);
...@@ -405,7 +371,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, ...@@ -405,7 +371,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
if (hit) if (hit)
he->count += count; he->count += count;
if (self->use_callchain) { if (symbol_conf.use_callchain) {
if (!hit) if (!hit)
callchain_init(&he->callchain); callchain_init(&he->callchain);
append_chain(&he->callchain, chain, syms); append_chain(&he->callchain, chain, syms);
...@@ -415,8 +381,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, ...@@ -415,8 +381,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
return 0; return 0;
} }
static size_t perf_session__fprintf_hist_entries(struct perf_session *self, static size_t perf_session__fprintf_hists(struct perf_session *self, FILE *fp)
u64 total_samples, FILE *fp)
{ {
struct hist_entry *pos; struct hist_entry *pos;
struct sort_entry *se; struct sort_entry *se;
...@@ -424,17 +389,14 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, ...@@ -424,17 +389,14 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self,
size_t ret = 0; size_t ret = 0;
unsigned int width; unsigned int width;
char *col_width = symbol_conf.col_width_list_str; char *col_width = symbol_conf.col_width_list_str;
int raw_printing_style;
raw_printing_style = !strcmp(pretty_printing_style, "raw");
init_rem_hits(); init_rem_hits();
fprintf(fp, "# Samples: %Ld\n", (u64)total_samples); fprintf(fp, "# Samples: %ld\n", self->events_stats.total);
fprintf(fp, "#\n"); fprintf(fp, "#\n");
fprintf(fp, "# Overhead"); fprintf(fp, "# Overhead");
if (show_nr_samples) { if (symbol_conf.show_nr_samples) {
if (symbol_conf.field_sep) if (symbol_conf.field_sep)
fprintf(fp, "%cSamples", *symbol_conf.field_sep); fprintf(fp, "%cSamples", *symbol_conf.field_sep);
else else
...@@ -467,7 +429,7 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, ...@@ -467,7 +429,7 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self,
goto print_entries; goto print_entries;
fprintf(fp, "# ........"); fprintf(fp, "# ........");
if (show_nr_samples) if (symbol_conf.show_nr_samples)
fprintf(fp, " .........."); fprintf(fp, " ..........");
list_for_each_entry(se, &hist_entry__sort_list, list) { list_for_each_entry(se, &hist_entry__sort_list, list) {
unsigned int i; unsigned int i;
...@@ -490,7 +452,7 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, ...@@ -490,7 +452,7 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self,
print_entries: print_entries:
for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
pos = rb_entry(nd, struct hist_entry, rb_node); pos = rb_entry(nd, struct hist_entry, rb_node);
ret += hist_entry__fprintf(fp, pos, self, total_samples); ret += hist_entry__fprintf(fp, pos, self);
} }
if (sort_order == default_sort_order && if (sort_order == default_sort_order &&
...@@ -503,10 +465,6 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self, ...@@ -503,10 +465,6 @@ static size_t perf_session__fprintf_hist_entries(struct perf_session *self,
free(rem_sq_bracket); free(rem_sq_bracket);
if (show_threads)
perf_read_values_display(fp, &show_threads_values,
raw_printing_style);
return ret; return ret;
} }
...@@ -572,21 +530,6 @@ static int process_sample_event(event_t *event, struct perf_session *session) ...@@ -572,21 +530,6 @@ static int process_sample_event(event_t *event, struct perf_session *session)
return 0; return 0;
} }
static int process_comm_event(event_t *event, struct perf_session *session)
{
struct thread *thread = perf_session__findnew(session, event->comm.pid);
dump_printf(": %s:%d\n", event->comm.comm, event->comm.pid);
if (thread == NULL ||
thread__set_comm_adjust(thread, event->comm.comm)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
return -1;
}
return 0;
}
static int process_read_event(event_t *event, struct perf_session *session __used) static int process_read_event(event_t *event, struct perf_session *session __used)
{ {
struct perf_event_attr *attr; struct perf_event_attr *attr;
...@@ -619,14 +562,14 @@ static int sample_type_check(struct perf_session *session) ...@@ -619,14 +562,14 @@ static int sample_type_check(struct perf_session *session)
" perf record without -g?\n"); " perf record without -g?\n");
return -1; return -1;
} }
if (session->use_callchain) { if (symbol_conf.use_callchain) {
fprintf(stderr, "selected -g but no callchain data." fprintf(stderr, "selected -g but no callchain data."
" Did you call perf record without" " Did you call perf record without"
" -g?\n"); " -g?\n");
return -1; return -1;
} }
} else if (callchain_param.mode != CHAIN_NONE && !session->use_callchain) { } else if (callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) {
session->use_callchain = true; symbol_conf.use_callchain = true;
if (register_callchain_param(&callchain_param) < 0) { if (register_callchain_param(&callchain_param) < 0) {
fprintf(stderr, "Can't register callchain" fprintf(stderr, "Can't register callchain"
" params\n"); " params\n");
...@@ -640,7 +583,7 @@ static int sample_type_check(struct perf_session *session) ...@@ -640,7 +583,7 @@ static int sample_type_check(struct perf_session *session)
static struct perf_event_ops event_ops = { static struct perf_event_ops event_ops = {
.process_sample_event = process_sample_event, .process_sample_event = process_sample_event,
.process_mmap_event = event__process_mmap, .process_mmap_event = event__process_mmap,
.process_comm_event = process_comm_event, .process_comm_event = event__process_mmap,
.process_exit_event = event__process_task, .process_exit_event = event__process_task,
.process_fork_event = event__process_task, .process_fork_event = event__process_task,
.process_lost_event = event__process_lost, .process_lost_event = event__process_lost,
...@@ -658,8 +601,6 @@ static int __cmd_report(void) ...@@ -658,8 +601,6 @@ static int __cmd_report(void)
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
session->use_callchain = use_callchain;
if (show_threads) if (show_threads)
perf_read_values_init(&show_threads_values); perf_read_values_init(&show_threads_values);
...@@ -680,10 +621,13 @@ static int __cmd_report(void) ...@@ -680,10 +621,13 @@ static int __cmd_report(void)
perf_session__collapse_resort(session); perf_session__collapse_resort(session);
perf_session__output_resort(session, session->events_stats.total); perf_session__output_resort(session, session->events_stats.total);
perf_session__fprintf_hist_entries(session, session->events_stats.total, stdout); perf_session__fprintf_hists(session, stdout);
if (show_threads) {
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); perf_read_values_destroy(&show_threads_values);
}
out_delete: out_delete:
perf_session__delete(session); perf_session__delete(session);
return ret; return ret;
...@@ -696,7 +640,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, ...@@ -696,7 +640,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
char *tok; char *tok;
char *endptr; char *endptr;
use_callchain = true; symbol_conf.use_callchain = true;
if (!arg) if (!arg)
return 0; return 0;
...@@ -717,7 +661,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, ...@@ -717,7 +661,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
else if (!strncmp(tok, "none", strlen(arg))) { else if (!strncmp(tok, "none", strlen(arg))) {
callchain_param.mode = CHAIN_NONE; callchain_param.mode = CHAIN_NONE;
use_callchain = true; symbol_conf.use_callchain = true;
return 0; return 0;
} }
...@@ -760,7 +704,7 @@ static const struct option options[] = { ...@@ -760,7 +704,7 @@ static const struct option options[] = {
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"), "load module symbols - WARNING: use only with -k and LIVE kernel"),
OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples, OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
"Show a column with the number of samples"), "Show a column with the number of samples"),
OPT_BOOLEAN('T', "threads", &show_threads, OPT_BOOLEAN('T', "threads", &show_threads,
"Show per-thread event counters"), "Show per-thread event counters"),
...@@ -772,7 +716,7 @@ static const struct option options[] = { ...@@ -772,7 +716,7 @@ static const struct option options[] = {
"Don't shorten the pathnames taking into account the cwd"), "Don't shorten the pathnames taking into account the cwd"),
OPT_STRING('p', "parent", &parent_pattern, "regex", OPT_STRING('p', "parent", &parent_pattern, "regex",
"regex filter to identify parent, see: '--sort parent'"), "regex filter to identify parent, see: '--sort parent'"),
OPT_BOOLEAN('x', "exclude-other", &exclude_other, OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
"Only display entries with parent-match"), "Only display entries with parent-match"),
OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent", 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 and min percent threshold. "
...@@ -817,7 +761,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) ...@@ -817,7 +761,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
sort_dimension__add("parent"); sort_dimension__add("parent");
sort_parent.elide = 1; sort_parent.elide = 1;
} else } else
exclude_other = 0; symbol_conf.exclude_other = false;
/* /*
* Any (unrecognized) arguments left? * Any (unrecognized) arguments left?
......
...@@ -189,13 +189,41 @@ void event__synthesize_threads(int (*process)(event_t *event, ...@@ -189,13 +189,41 @@ void event__synthesize_threads(int (*process)(event_t *event,
closedir(proc); closedir(proc);
} }
static void thread__comm_adjust(struct thread *self)
{
char *comm = self->comm;
if (!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
(!symbol_conf.comm_list ||
strlist__has_entry(symbol_conf.comm_list, comm))) {
unsigned int slen = strlen(comm);
if (slen > comms__col_width) {
comms__col_width = slen;
threads__col_width = slen + 6;
}
}
}
static int thread__set_comm_adjust(struct thread *self, const char *comm)
{
int ret = thread__set_comm(self, comm);
if (ret)
return ret;
thread__comm_adjust(self);
return 0;
}
int event__process_comm(event_t *self, struct perf_session *session) int event__process_comm(event_t *self, struct perf_session *session)
{ {
struct thread *thread = perf_session__findnew(session, self->comm.pid); struct thread *thread = perf_session__findnew(session, self->comm.pid);
dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid); dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
if (thread == NULL || thread__set_comm(thread, self->comm.comm)) { if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
return -1; return -1;
} }
......
...@@ -156,8 +156,7 @@ void perf_session__collapse_resort(struct perf_session *self) ...@@ -156,8 +156,7 @@ void perf_session__collapse_resort(struct perf_session *self)
* reverse the map, sort on count. * reverse the map, sort on count.
*/ */
static void perf_session__insert_output_hist_entry(struct perf_session *self, static void perf_session__insert_output_hist_entry(struct rb_root *root,
struct rb_root *root,
struct hist_entry *he, struct hist_entry *he,
u64 min_callchain_hits) u64 min_callchain_hits)
{ {
...@@ -165,7 +164,7 @@ static void perf_session__insert_output_hist_entry(struct perf_session *self, ...@@ -165,7 +164,7 @@ static void perf_session__insert_output_hist_entry(struct perf_session *self,
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
struct hist_entry *iter; struct hist_entry *iter;
if (self->use_callchain) if (symbol_conf.use_callchain)
callchain_param.sort(&he->sorted_chain, &he->callchain, callchain_param.sort(&he->sorted_chain, &he->callchain,
min_callchain_hits, &callchain_param); min_callchain_hits, &callchain_param);
...@@ -201,7 +200,7 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples) ...@@ -201,7 +200,7 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples)
next = rb_next(&n->rb_node); next = rb_next(&n->rb_node);
rb_erase(&n->rb_node, &self->hists); rb_erase(&n->rb_node, &self->hists);
perf_session__insert_output_hist_entry(self, &tmp, n, perf_session__insert_output_hist_entry(&tmp, n,
min_callchain_hits); min_callchain_hits);
} }
......
...@@ -108,7 +108,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, ...@@ -108,7 +108,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
struct symbol **syms = NULL; struct symbol **syms = NULL;
unsigned int i; unsigned int i;
if (self->use_callchain) { if (symbol_conf.use_callchain) {
syms = calloc(chain->nr, sizeof(*syms)); syms = calloc(chain->nr, sizeof(*syms));
if (!syms) { if (!syms) {
fprintf(stderr, "Can't allocate memory for symbols\n"); fprintf(stderr, "Can't allocate memory for symbols\n");
...@@ -140,7 +140,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self, ...@@ -140,7 +140,7 @@ struct symbol **perf_session__resolve_callchain(struct perf_session *self,
if (sort__has_parent && !*parent && if (sort__has_parent && !*parent &&
symbol__match_parent_regex(al.sym)) symbol__match_parent_regex(al.sym))
*parent = al.sym; *parent = al.sym;
if (!self->use_callchain) if (!symbol_conf.use_callchain)
break; break;
syms[i] = al.sym; syms[i] = al.sym;
} }
......
...@@ -25,7 +25,6 @@ struct perf_session { ...@@ -25,7 +25,6 @@ struct perf_session {
int fd; int fd;
int cwdlen; int cwdlen;
char *cwd; char *cwd;
bool use_callchain;
char filename[0]; char filename[0];
}; };
......
...@@ -38,6 +38,7 @@ static int vmlinux_path__nr_entries; ...@@ -38,6 +38,7 @@ static int vmlinux_path__nr_entries;
static char **vmlinux_path; static char **vmlinux_path;
struct symbol_conf symbol_conf = { struct symbol_conf symbol_conf = {
.exclude_other = true,
.use_modules = true, .use_modules = true,
.try_vmlinux_path = true, .try_vmlinux_path = true,
}; };
......
...@@ -55,7 +55,10 @@ struct symbol_conf { ...@@ -55,7 +55,10 @@ struct symbol_conf {
unsigned short priv_size; unsigned short priv_size;
bool try_vmlinux_path, bool try_vmlinux_path,
use_modules, use_modules,
sort_by_name; sort_by_name,
show_nr_samples,
use_callchain,
exclude_other;
const char *vmlinux_name, const char *vmlinux_name,
*field_sep; *field_sep;
char *dso_list_str, char *dso_list_str,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment