diff options
Diffstat (limited to 'tools/perf/util/newt.c')
-rw-r--r-- | tools/perf/util/newt.c | 298 |
1 files changed, 167 insertions, 131 deletions
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index e99bcc8d193..c93bc2a2d13 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); @@ -228,60 +294,17 @@ 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]; @@ -291,10 +314,11 @@ static size_t hist_entry__append_browser(struct hist_entry *self, } else newtListboxAppendEntry(tree, s, &self->ms); - return strlen(s); + return ret; } -static void map_symbol__annotate_browser(const struct map_symbol *self) +static void map_symbol__annotate_browser(const struct map_symbol *self, + const char *input_name) { FILE *fp; int cols, rows; @@ -308,8 +332,8 @@ static void map_symbol__annotate_browser(const struct map_symbol *self) if (self->sym == NULL) return; - if (asprintf(&str, "perf annotate -d \"%s\" %s 2>&1 | expand", - self->map->dso->name, self->sym->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"); @@ -358,90 +382,121 @@ 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 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 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; +struct hist_browser { + newtComponent form, tree; const struct map_symbol *selection; +}; - snprintf(str, sizeof(str), "Samples: %Ld", session_total); - newtDrawRootText(0, 0, str); - newtPushHelpLine(helpline); - - newtGetScreenSize(&cols, &rows); +static struct hist_browser *hist_browser__new(void) +{ + struct hist_browser *self = malloc(sizeof(*self)); - 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 (self != NULL) { + char seq[] = "."; + int rows; - newtComponentAddCallback(tree, perf_session__selection, &selection); + newtGetScreenSize(NULL, &rows); - 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); - } + 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); } + return self; +} + +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++); + 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 = 0; - newtFormRun(form, &es); + newtFormRun(browser->form, &es); if (es.reason == NEWT_EXIT_HOTKEY) { if (toupper(es.u.key) == 'A') goto do_annotate; @@ -455,9 +510,9 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, } } - if (selection->sym != NULL) { + if (browser->selection->sym != NULL) { snprintf(annotate, sizeof(annotate), - "Annotate %s", selection->sym->name); + "Annotate %s", browser->selection->sym->name); options[nr_options++] = annotate; } @@ -466,41 +521,22 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, if (choice == nr_options - 1) break; do_annotate: - if (selection->sym != NULL && choice >= 0) { - if (selection->map->dso->origin == DSO__ORIG_KERNEL) { + 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(selection); + map_symbol__annotate_browser(browser->selection, + input_name); } } - - 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; - } - - return ret; + err = 0; +out: + hist_browser__delete(browser); + return err; } void setup_browser(void) |