Skip to content

Commit

Permalink
perf hists browser: Implement printing snapshots to files
Browse files Browse the repository at this point in the history
To avoid having to resort to --stdio, that expands everything, instead
allow the user to go on expanding the relevant callchains and then press
'P' to print that view.

As the hists browser is used for both static (report) and dynamic (top)
views, it prints to a 'perf.hists.N' sequence, i.e. multiple snapshots
can be taken in report and top.

Cc: David Ahern <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: Jiri Olsa <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Stephane Eranian <[email protected]>
Link: http://lkml.kernel.org/n/[email protected]
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
  • Loading branch information
acmel committed Jun 19, 2012
1 parent cb1a28a commit aff3f3f
Showing 1 changed file with 195 additions and 0 deletions.
195 changes: 195 additions & 0 deletions tools/perf/ui/browsers/hists.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct hist_browser {
struct hists *hists;
struct hist_entry *he_selection;
struct map_symbol *selection;
int print_seq;
bool has_symbols;
};

Expand Down Expand Up @@ -800,6 +801,196 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
}
}

static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser,
struct callchain_node *chain_node,
u64 total, int level,
FILE *fp)
{
struct rb_node *node;
int offset = level * LEVEL_OFFSET_STEP;
u64 new_total, remaining;
int printed = 0;

if (callchain_param.mode == CHAIN_GRAPH_REL)
new_total = chain_node->children_hit;
else
new_total = total;

remaining = new_total;
node = rb_first(&chain_node->rb_root);
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
struct rb_node *next = rb_next(node);
u64 cumul = callchain_cumul_hits(child);
struct callchain_list *chain;
char folded_sign = ' ';
int first = true;
int extra_offset = 0;

remaining -= cumul;

list_for_each_entry(chain, &child->val, list) {
char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
const char *str;
bool was_first = first;

if (first)
first = false;
else
extra_offset = LEVEL_OFFSET_STEP;

folded_sign = callchain_list__folded(chain);

alloc_str = NULL;
str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
if (was_first) {
double percent = cumul * 100.0 / new_total;

if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
str = "Not enough memory!";
else
str = alloc_str;
}

printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str);
free(alloc_str);
if (folded_sign == '+')
break;
}

if (folded_sign == '-') {
const int new_level = level + (extra_offset ? 2 : 1);
printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total,
new_level, fp);
}

node = next;
}

return printed;
}

static int hist_browser__fprintf_callchain_node(struct hist_browser *browser,
struct callchain_node *node,
int level, FILE *fp)
{
struct callchain_list *chain;
int offset = level * LEVEL_OFFSET_STEP;
char folded_sign = ' ';
int printed = 0;

list_for_each_entry(chain, &node->val, list) {
char ipstr[BITS_PER_LONG / 4 + 1], *s;

folded_sign = callchain_list__folded(chain);
s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s);
}

if (folded_sign == '-')
printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node,
browser->hists->stats.total_period,
level + 1, fp);
return printed;
}

static int hist_browser__fprintf_callchain(struct hist_browser *browser,
struct rb_root *chain, int level, FILE *fp)
{
struct rb_node *nd;
int printed = 0;

for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);

printed += hist_browser__fprintf_callchain_node(browser, node, level, fp);
}

return printed;
}

static int hist_browser__fprintf_entry(struct hist_browser *browser,
struct hist_entry *he, FILE *fp)
{
char s[8192];
double percent;
int printed = 0;
char folded_sign = ' ';

if (symbol_conf.use_callchain)
folded_sign = hist_entry__folded(he);

hist_entry__snprintf(he, s, sizeof(s), browser->hists);
percent = (he->period * 100.0) / browser->hists->stats.total_period;

if (symbol_conf.use_callchain)
printed += fprintf(fp, "%c ", folded_sign);

printed += fprintf(fp, " %5.2f%%", percent);

if (symbol_conf.show_nr_samples)
printed += fprintf(fp, " %11u", he->nr_events);

if (symbol_conf.show_total_period)
printed += fprintf(fp, " %12" PRIu64, he->period);

printed += fprintf(fp, "%s\n", rtrim(s));

if (folded_sign == '-')
printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp);

return printed;
}

static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
{
struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries));
int printed = 0;

while (nd) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);

printed += hist_browser__fprintf_entry(browser, h, fp);
nd = hists__filter_entries(rb_next(nd));
}

return printed;
}

static int hist_browser__dump(struct hist_browser *browser)
{
char filename[64];
FILE *fp;

while (1) {
scnprintf(filename, sizeof(filename), "perf.hist.%d", browser->print_seq);
if (access(filename, F_OK))
break;
/*
* XXX: Just an arbitrary lazy upper limit
*/
if (++browser->print_seq == 8192) {
ui_helpline__fpush("Too many perf.hist.N files, nothing written!");
return -1;
}
}

fp = fopen(filename, "w");
if (fp == NULL) {
char bf[64];
strerror_r(errno, bf, sizeof(bf));
ui_helpline__fpush("Couldn't write to %s: %s", filename, bf);
return -1;
}

++browser->print_seq;
hist_browser__fprintf(browser, fp);
fclose(fp);
ui_helpline__fpush("%s written!", filename);

return 0;
}

static struct hist_browser *hist_browser__new(struct hists *hists)
{
struct hist_browser *browser = zalloc(sizeof(*browser));
Expand Down Expand Up @@ -937,6 +1128,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
browser->selection->map->dso->annotate_warned)
continue;
goto do_annotate;
case 'P':
hist_browser__dump(browser);
continue;
case 'd':
goto zoom_dso;
case 't':
Expand Down Expand Up @@ -969,6 +1163,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n"
"d Zoom into current DSO\n"
"t Zoom into current Thread\n"
"P Print histograms to perf.hist.N\n"
"/ Filter symbol by name");
continue;
case K_ENTER:
Expand Down

0 comments on commit aff3f3f

Please sign in to comment.