X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=tools%2Fperf%2Futil%2Fnewt.c;h=c93bc2a2d13792ac8512f8d031b6ede4e3aff57d;hb=533c46c31c0e82f19dbb087c77d85eaccd6fefdb;hp=25cd2e1f4251facf5bef58eb88f495f17f9b56d0;hpb=59fd53062f71011a68d03f4cd0ba93d822ac3249;p=safe%2Fjmp%2Flinux-2.6 diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 25cd2e1..c93bc2a 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c @@ -12,6 +12,72 @@ #include "sort.h" #include "symbol.h" +struct ui_progress { + newtComponent form, scale; +}; + +struct ui_progress *ui_progress__new(const char *title, u64 total) +{ + struct ui_progress *self = malloc(sizeof(*self)); + + if (self != NULL) { + int cols; + newtGetScreenSize(&cols, NULL); + cols -= 4; + newtCenteredWindow(cols, 1, title); + self->form = newtForm(NULL, NULL, 0); + if (self->form == NULL) + goto out_free_self; + self->scale = newtScale(0, 0, cols, total); + if (self->scale == NULL) + goto out_free_form; + newtFormAddComponents(self->form, self->scale, NULL); + newtRefresh(); + } + + return self; + +out_free_form: + newtFormDestroy(self->form); +out_free_self: + free(self); + return NULL; +} + +void ui_progress__update(struct ui_progress *self, u64 curr) +{ + newtScaleSet(self->scale, curr); + newtRefresh(); +} + +void ui_progress__delete(struct ui_progress *self) +{ + newtFormDestroy(self->form); + newtPopWindow(); + free(self); +} + +static char browser__last_msg[1024]; + +int browser__show_help(const char *format, va_list ap) +{ + int ret; + static int backlog; + + ret = vsnprintf(browser__last_msg + backlog, + sizeof(browser__last_msg) - backlog, format, ap); + backlog += ret; + + if (browser__last_msg[backlog - 1] == '\n') { + newtPopHelpLine(); + newtPushHelpLine(browser__last_msg); + newtRefresh(); + backlog = 0; + } + + return ret; +} + static void newt_form__set_exit_keys(newtComponent self) { newtFormAddHotKey(self, NEWT_KEY_ESCAPE); @@ -104,8 +170,8 @@ static void newt_checkbox_tree__add(newtComponent tree, const char *str, static char *callchain_list__sym_name(struct callchain_list *self, char *bf, size_t bfsize) { - if (self->sym) - return self->sym->name; + if (self->ms.sym) + return self->ms.sym->name; snprintf(bf, bfsize, "%#Lx", self->ip); return bf; @@ -157,7 +223,7 @@ static void __callchain__append_graph_browser(struct callchain_node *self, indexes[depth + 2] = NEWT_ARG_LAST; ++chain_idx; } - newt_checkbox_tree__add(tree, str, chain->sym, indexes); + newt_checkbox_tree__add(tree, str, &chain->ms, indexes); free(alloc_str); ++printed; } @@ -193,7 +259,7 @@ static void callchain__append_graph_browser(struct callchain_node *self, continue; str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr)); - newt_checkbox_tree__add(tree, str, chain->sym, indexes); + newt_checkbox_tree__add(tree, str, &chain->ms, indexes); } indexes[1] = parent_idx; @@ -228,73 +294,31 @@ static void hist_entry__append_callchain_browser(struct hist_entry *self, } } -/* - * FIXME: get lib/string.c linked with perf somehow - */ -static char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} - -static char *strim(char *s) -{ - size_t size; - char *end; - - s = skip_spaces(s); - size = strlen(s); - if (!size) - return s; - - end = s + size - 1; - while (end >= s && isspace(*end)) - end--; - *(end + 1) = '\0'; - - return s; -} - static size_t hist_entry__append_browser(struct hist_entry *self, newtComponent tree, u64 total) { - char bf[1024], *s; - FILE *fp; + char s[256]; + size_t ret; if (symbol_conf.exclude_other && !self->parent) return 0; - fp = fmemopen(bf, sizeof(bf), "w"); - if (fp == NULL) - return 0; - - hist_entry__fprintf(self, NULL, false, 0, fp, total); - fclose(fp); - - /* - * FIXME: We shouldn't need to trim, as the printing routines shouldn't - * add spaces it in the first place, the stdio output routines should - * call a __snprintf method instead of the current __print (that - * actually is a __fprintf) one, but get the raw string and _then_ add - * the newline, as this is a detail of stdio printing, not needed in - * other UIs, e.g. newt. - */ - s = strim(bf); - + ret = hist_entry__snprintf(self, s, sizeof(s), NULL, + false, 0, false, total); if (symbol_conf.use_callchain) { int indexes[2]; indexes[0] = NEWT_ARG_APPEND; indexes[1] = NEWT_ARG_LAST; - newt_checkbox_tree__add(tree, s, self->ms.sym, indexes); + newt_checkbox_tree__add(tree, s, &self->ms, indexes); } else - newtListboxAppendEntry(tree, s, self->ms.sym); + newtListboxAppendEntry(tree, s, &self->ms); - return strlen(s); + return ret; } -static void symbol__annotate_browser(const struct symbol *self) +static void map_symbol__annotate_browser(const struct map_symbol *self, + const char *input_name) { FILE *fp; int cols, rows; @@ -305,10 +329,11 @@ static void symbol__annotate_browser(const struct symbol *self) size_t max_usable_width; char *line = NULL; - if (self == NULL) + if (self->sym == NULL) return; - if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->name) < 0) + if (asprintf(&str, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand", + input_name, self->map->dso->name, self->sym->name) < 0) return; fp = popen(str, "r"); @@ -338,7 +363,7 @@ static void symbol__annotate_browser(const struct symbol *self) newtListboxSetWidth(tree, max_line_len); - newtCenteredWindow(max_line_len + 2, rows - 5, self->name); + newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name); form = newt_form__new(); newtFormAddComponents(form, tree, NULL); @@ -357,98 +382,124 @@ static const void *newt__symbol_tree_get_current(newtComponent self) return newtListboxGetCurrent(self); } -static void perf_session__selection(newtComponent self, void *data) +static void hist_browser__selection(newtComponent self, void *data) { - const struct symbol **symbol_ptr = data; + const struct map_symbol **symbol_ptr = data; *symbol_ptr = newt__symbol_tree_get_current(self); } -void perf_session__browse_hists(struct rb_root *hists, u64 session_total, - const char *helpline) +struct hist_browser { + newtComponent form, tree; + const struct map_symbol *selection; +}; + +static struct hist_browser *hist_browser__new(void) { - struct sort_entry *se; - struct rb_node *nd; - char seq[] = "."; - unsigned int width; - char *col_width = symbol_conf.col_width_list_str; - int rows, cols, idx; - int max_len = 0; - char str[1024]; - newtComponent form, tree; - struct newtExitStruct es; - const struct symbol *selection; + struct hist_browser *self = malloc(sizeof(*self)); - snprintf(str, sizeof(str), "Samples: %Ld", session_total); - newtDrawRootText(0, 0, str); - newtPushHelpLine(helpline); + if (self != NULL) { + char seq[] = "."; + int rows; - newtGetScreenSize(&cols, &rows); + newtGetScreenSize(NULL, &rows); - if (symbol_conf.use_callchain) - tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq, - NEWT_FLAG_SCROLL); - else - tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL | - NEWT_FLAG_RETURNEXIT)); + if (symbol_conf.use_callchain) + self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq, + NEWT_FLAG_SCROLL); + else + self->tree = newtListbox(0, 0, rows - 5, + (NEWT_FLAG_SCROLL | + NEWT_FLAG_RETURNEXIT)); + newtComponentAddCallback(self->tree, hist_browser__selection, + &self->selection); + } - newtComponentAddCallback(tree, perf_session__selection, &selection); + return self; +} - list_for_each_entry(se, &hist_entry__sort_list, list) { - if (se->elide) - continue; - width = strlen(se->header); - if (se->width) { - if (symbol_conf.col_width_list_str) { - if (col_width) { - *se->width = atoi(col_width); - col_width = strchr(col_width, ','); - if (col_width) - ++col_width; - } - } - *se->width = max(*se->width, width); - } - } +static void hist_browser__delete(struct hist_browser *self) +{ + newtFormDestroy(self->form); + newtPopWindow(); + free(self); +} + +static int hist_browser__populate(struct hist_browser *self, struct rb_root *hists, + u64 nr_hists, u64 session_total) +{ + int max_len = 0, idx, cols, rows; + struct ui_progress *progress; + struct rb_node *nd; + u64 curr_hist = 0; + + progress = ui_progress__new("Adding entries to the browser...", nr_hists); + if (progress == NULL) + return -1; idx = 0; for (nd = rb_first(hists); nd; nd = rb_next(nd)) { struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); - int len = hist_entry__append_browser(h, tree, session_total); + int len = hist_entry__append_browser(h, self->tree, session_total); if (len > max_len) max_len = len; - if (symbol_conf.use_callchain) { - hist_entry__append_callchain_browser(h, tree, session_total, idx++); - if (idx > 3300) - break; - } + if (symbol_conf.use_callchain) + hist_entry__append_callchain_browser(h, self->tree, + session_total, idx++); + ++curr_hist; + if (curr_hist % 5) + ui_progress__update(progress, curr_hist); } + ui_progress__delete(progress); + + newtGetScreenSize(&cols, &rows); + if (max_len > cols) max_len = cols - 3; if (!symbol_conf.use_callchain) - newtListboxSetWidth(tree, max_len); + newtListboxSetWidth(self->tree, max_len); newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0), rows - 5, "Report"); - form = newt_form__new(); - newtFormAddHotKey(form, 'A'); - newtFormAddHotKey(form, 'a'); - newtFormAddHotKey(form, NEWT_KEY_RIGHT); - newtFormAddComponents(form, tree, NULL); - selection = newt__symbol_tree_get_current(tree); + self->form = newt_form__new(); + newtFormAddHotKey(self->form, 'A'); + newtFormAddHotKey(self->form, 'a'); + newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); + newtFormAddComponents(self->form, self->tree, NULL); + self->selection = newt__symbol_tree_get_current(self->tree); + + return 0; +} + +int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, + u64 session_total, const char *helpline, + const char *input_name) +{ + struct newtExitStruct es; + char str[1024]; + int err = -1; + struct hist_browser *browser = hist_browser__new(); + + if (browser == NULL) + return -1; + + snprintf(str, sizeof(str), "Samples: %Ld", session_total); + newtDrawRootText(0, 0, str); + newtPushHelpLine(helpline); + + if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0) + goto out; while (1) { char annotate[512]; const char *options[2]; - int nr_options = 0, choice; + int nr_options = 0, choice = 0; - newtFormRun(form, &es); + newtFormRun(browser->form, &es); if (es.reason == NEWT_EXIT_HOTKEY) { - if (toupper(es.u.key) == 'A') { - symbol__annotate_browser(selection); - continue; - } + if (toupper(es.u.key) == 'A') + goto do_annotate; if (es.u.key == NEWT_KEY_ESCAPE || toupper(es.u.key) == 'Q' || es.u.key == CTRL('c')) { @@ -459,9 +510,9 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, } } - if (selection != NULL) { + if (browser->selection->sym != NULL) { snprintf(annotate, sizeof(annotate), - "Annotate %s", selection->name); + "Annotate %s", browser->selection->sym->name); options[nr_options++] = annotate; } @@ -469,33 +520,23 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, choice = popup_menu(nr_options, options); if (choice == nr_options - 1) break; - else if (selection != NULL && choice >= 0) - symbol__annotate_browser(selection); - } - - newtFormDestroy(form); - newtPopWindow(); -} - -static char browser__last_msg[1024]; - -int browser__show_help(const char *format, va_list ap) -{ - int ret; - static int backlog; - - ret = vsnprintf(browser__last_msg + backlog, - sizeof(browser__last_msg) - backlog, format, ap); - backlog += ret; - - if (browser__last_msg[backlog - 1] == '\n') { - newtPopHelpLine(); - newtPushHelpLine(browser__last_msg); - newtRefresh(); - backlog = 0; +do_annotate: + if (browser->selection->sym != NULL && choice >= 0) { + if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { + newtPopHelpLine(); + newtPushHelpLine("No vmlinux file found, can't " + "annotate with just a " + "kallsyms file"); + continue; + } + map_symbol__annotate_browser(browser->selection, + input_name); + } } - - return ret; + err = 0; +out: + hist_browser__delete(browser); + return err; } void setup_browser(void)