diff options
| author | Ingo Molnar <mingo@elte.hu> | 2010-04-03 12:16:42 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-04-03 12:16:42 -0400 |
| commit | 70a7c1271e2bfca8ad2bf71f44c516ea2763b9ed (patch) | |
| tree | eaac85de741bc558529eccaefc372ff1e90ff425 /tools/perf/util | |
| parent | 40b91cd10f000b4c4934e48e2e5c0bec66def144 (diff) | |
| parent | 533c46c31c0e82f19dbb087c77d85eaccd6fefdb (diff) | |
Merge branch 'perf' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
Diffstat (limited to 'tools/perf/util')
| -rwxr-xr-x | tools/perf/util/PERF-VERSION-GEN | 6 | ||||
| -rw-r--r-- | tools/perf/util/color.c | 53 | ||||
| -rw-r--r-- | tools/perf/util/color.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/debug.h | 16 | ||||
| -rw-r--r-- | tools/perf/util/event.c | 9 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 66 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 9 | ||||
| -rw-r--r-- | tools/perf/util/map.c | 196 | ||||
| -rw-r--r-- | tools/perf/util/map.h | 34 | ||||
| -rw-r--r-- | tools/perf/util/newt.c | 298 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 22 | ||||
| -rw-r--r-- | tools/perf/util/session.h | 19 | ||||
| -rw-r--r-- | tools/perf/util/sort.c | 93 | ||||
| -rw-r--r-- | tools/perf/util/sort.h | 6 | ||||
| -rw-r--r-- | tools/perf/util/string.h | 16 | ||||
| -rw-r--r-- | tools/perf/util/thread.c | 169 | ||||
| -rw-r--r-- | tools/perf/util/util.h | 12 |
17 files changed, 614 insertions, 414 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index 54552a00a117..49ece7921914 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | #!/bin/sh | 1 | #!/bin/sh |
| 2 | 2 | ||
| 3 | GVF=PERF-VERSION-FILE | 3 | if [ $# -eq 1 ] ; then |
| 4 | OUTPUT=$1 | ||
| 5 | fi | ||
| 6 | |||
| 7 | GVF=${OUTPUT}PERF-VERSION-FILE | ||
| 4 | DEF_VER=v0.0.2.PERF | 8 | DEF_VER=v0.0.2.PERF |
| 5 | 9 | ||
| 6 | LF=' | 10 | LF=' |
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 9da01914e0af..e191eb9a667f 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
| @@ -166,6 +166,31 @@ int perf_color_default_config(const char *var, const char *value, void *cb) | |||
| 166 | return perf_default_config(var, value, cb); | 166 | return perf_default_config(var, value, cb); |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | static int __color_vsnprintf(char *bf, size_t size, const char *color, | ||
| 170 | const char *fmt, va_list args, const char *trail) | ||
| 171 | { | ||
| 172 | int r = 0; | ||
| 173 | |||
| 174 | /* | ||
| 175 | * Auto-detect: | ||
| 176 | */ | ||
| 177 | if (perf_use_color_default < 0) { | ||
| 178 | if (isatty(1) || pager_in_use()) | ||
| 179 | perf_use_color_default = 1; | ||
| 180 | else | ||
| 181 | perf_use_color_default = 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | if (perf_use_color_default && *color) | ||
| 185 | r += snprintf(bf, size, "%s", color); | ||
| 186 | r += vsnprintf(bf + r, size - r, fmt, args); | ||
| 187 | if (perf_use_color_default && *color) | ||
| 188 | r += snprintf(bf + r, size - r, "%s", PERF_COLOR_RESET); | ||
| 189 | if (trail) | ||
| 190 | r += snprintf(bf + r, size - r, "%s", trail); | ||
| 191 | return r; | ||
| 192 | } | ||
| 193 | |||
| 169 | static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, | 194 | static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, |
| 170 | va_list args, const char *trail) | 195 | va_list args, const char *trail) |
| 171 | { | 196 | { |
| @@ -191,11 +216,28 @@ static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, | |||
| 191 | return r; | 216 | return r; |
| 192 | } | 217 | } |
| 193 | 218 | ||
| 219 | int color_vsnprintf(char *bf, size_t size, const char *color, | ||
| 220 | const char *fmt, va_list args) | ||
| 221 | { | ||
| 222 | return __color_vsnprintf(bf, size, color, fmt, args, NULL); | ||
| 223 | } | ||
| 224 | |||
| 194 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) | 225 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) |
| 195 | { | 226 | { |
| 196 | return __color_vfprintf(fp, color, fmt, args, NULL); | 227 | return __color_vfprintf(fp, color, fmt, args, NULL); |
| 197 | } | 228 | } |
| 198 | 229 | ||
| 230 | int color_snprintf(char *bf, size_t size, const char *color, | ||
| 231 | const char *fmt, ...) | ||
| 232 | { | ||
| 233 | va_list args; | ||
| 234 | int r; | ||
| 235 | |||
| 236 | va_start(args, fmt); | ||
| 237 | r = color_vsnprintf(bf, size, color, fmt, args); | ||
| 238 | va_end(args); | ||
| 239 | return r; | ||
| 240 | } | ||
| 199 | 241 | ||
| 200 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) | 242 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) |
| 201 | { | 243 | { |
| @@ -203,10 +245,7 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) | |||
| 203 | int r; | 245 | int r; |
| 204 | 246 | ||
| 205 | va_start(args, fmt); | 247 | va_start(args, fmt); |
| 206 | if (use_browser) | 248 | r = color_vfprintf(fp, color, fmt, args); |
| 207 | r = vfprintf(fp, fmt, args); | ||
| 208 | else | ||
| 209 | r = color_vfprintf(fp, color, fmt, args); | ||
| 210 | va_end(args); | 249 | va_end(args); |
| 211 | return r; | 250 | return r; |
| 212 | } | 251 | } |
| @@ -277,3 +316,9 @@ int percent_color_fprintf(FILE *fp, const char *fmt, double percent) | |||
| 277 | 316 | ||
| 278 | return r; | 317 | return r; |
| 279 | } | 318 | } |
| 319 | |||
| 320 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent) | ||
| 321 | { | ||
| 322 | const char *color = get_percent_color(percent); | ||
| 323 | return color_snprintf(bf, size, color, fmt, percent); | ||
| 324 | } | ||
diff --git a/tools/perf/util/color.h b/tools/perf/util/color.h index 24e8809210bb..dea082b79602 100644 --- a/tools/perf/util/color.h +++ b/tools/perf/util/color.h | |||
| @@ -32,10 +32,14 @@ int perf_color_default_config(const char *var, const char *value, void *cb); | |||
| 32 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); | 32 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); |
| 33 | void color_parse(const char *value, const char *var, char *dst); | 33 | void color_parse(const char *value, const char *var, char *dst); |
| 34 | void color_parse_mem(const char *value, int len, const char *var, char *dst); | 34 | void color_parse_mem(const char *value, int len, const char *var, char *dst); |
| 35 | int color_vsnprintf(char *bf, size_t size, const char *color, | ||
| 36 | const char *fmt, va_list args); | ||
| 35 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); | 37 | int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); |
| 36 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); | 38 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); |
| 39 | int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...); | ||
| 37 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); | 40 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); |
| 38 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); | 41 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); |
| 42 | int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent); | ||
| 39 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); | 43 | int percent_color_fprintf(FILE *fp, const char *fmt, double percent); |
| 40 | const char *get_percent_color(double percent); | 44 | const char *get_percent_color(double percent); |
| 41 | 45 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 0172edf3f153..5cb0a1b1401a 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
| @@ -10,13 +10,29 @@ extern int dump_trace; | |||
| 10 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 10 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
| 11 | void trace_event(event_t *event); | 11 | void trace_event(event_t *event); |
| 12 | 12 | ||
| 13 | struct ui_progress; | ||
| 14 | |||
| 13 | #ifdef NO_NEWT_SUPPORT | 15 | #ifdef NO_NEWT_SUPPORT |
| 14 | static inline int browser__show_help(const char *format __used, va_list ap __used) | 16 | static inline int browser__show_help(const char *format __used, va_list ap __used) |
| 15 | { | 17 | { |
| 16 | return 0; | 18 | return 0; |
| 17 | } | 19 | } |
| 20 | |||
| 21 | static inline struct ui_progress *ui_progress__new(const char *title __used, | ||
| 22 | u64 total __used) | ||
| 23 | { | ||
| 24 | return (struct ui_progress *)1; | ||
| 25 | } | ||
| 26 | |||
| 27 | static inline void ui_progress__update(struct ui_progress *self __used, | ||
| 28 | u64 curr __used) {} | ||
| 29 | |||
| 30 | static inline void ui_progress__delete(struct ui_progress *self __used) {} | ||
| 18 | #else | 31 | #else |
| 19 | int browser__show_help(const char *format, va_list ap); | 32 | int browser__show_help(const char *format, va_list ap); |
| 33 | struct ui_progress *ui_progress__new(const char *title, u64 total); | ||
| 34 | void ui_progress__update(struct ui_progress *self, u64 curr); | ||
| 35 | void ui_progress__delete(struct ui_progress *self); | ||
| 20 | #endif | 36 | #endif |
| 21 | 37 | ||
| 22 | #endif /* __PERF_DEBUG_H */ | 38 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 052eaeccc202..571fb25f7eb9 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -130,6 +130,7 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 130 | continue; | 130 | continue; |
| 131 | pbf += n + 3; | 131 | pbf += n + 3; |
| 132 | if (*pbf == 'x') { /* vm_exec */ | 132 | if (*pbf == 'x') { /* vm_exec */ |
| 133 | u64 vm_pgoff; | ||
| 133 | char *execname = strchr(bf, '/'); | 134 | char *execname = strchr(bf, '/'); |
| 134 | 135 | ||
| 135 | /* Catch VDSO */ | 136 | /* Catch VDSO */ |
| @@ -139,6 +140,14 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, | |||
| 139 | if (execname == NULL) | 140 | if (execname == NULL) |
| 140 | continue; | 141 | continue; |
| 141 | 142 | ||
| 143 | pbf += 3; | ||
| 144 | n = hex2u64(pbf, &vm_pgoff); | ||
| 145 | /* pgoff is in bytes, not pages */ | ||
| 146 | if (n >= 0) | ||
| 147 | ev.mmap.pgoff = vm_pgoff << getpagesize(); | ||
| 148 | else | ||
| 149 | ev.mmap.pgoff = 0; | ||
| 150 | |||
| 142 | size = strlen(execname); | 151 | size = strlen(execname); |
| 143 | execname[size - 1] = '\0'; /* Remove \n */ | 152 | execname[size - 1] = '\0'; /* Remove \n */ |
| 144 | memcpy(ev.mmap.filename, execname, size); | 153 | memcpy(ev.mmap.filename, execname, size); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 09e09e78cb62..18cf8b321608 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -50,7 +50,8 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, | |||
| 50 | p = &(*p)->rb_right; | 50 | p = &(*p)->rb_right; |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | he = malloc(sizeof(*he)); | 53 | he = malloc(sizeof(*he) + (symbol_conf.use_callchain ? |
| 54 | sizeof(struct callchain_node) : 0)); | ||
| 54 | if (!he) | 55 | if (!he) |
| 55 | return NULL; | 56 | return NULL; |
| 56 | *he = entry; | 57 | *he = entry; |
| @@ -168,7 +169,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root, | |||
| 168 | struct hist_entry *iter; | 169 | struct hist_entry *iter; |
| 169 | 170 | ||
| 170 | if (symbol_conf.use_callchain) | 171 | if (symbol_conf.use_callchain) |
| 171 | callchain_param.sort(&he->sorted_chain, &he->callchain, | 172 | callchain_param.sort(&he->sorted_chain, he->callchain, |
| 172 | min_callchain_hits, &callchain_param); | 173 | min_callchain_hits, &callchain_param); |
| 173 | 174 | ||
| 174 | while (*p != NULL) { | 175 | while (*p != NULL) { |
| @@ -185,12 +186,13 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root, | |||
| 185 | rb_insert_color(&he->rb_node, root); | 186 | rb_insert_color(&he->rb_node, root); |
| 186 | } | 187 | } |
| 187 | 188 | ||
| 188 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples) | 189 | u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples) |
| 189 | { | 190 | { |
| 190 | struct rb_root tmp; | 191 | struct rb_root tmp; |
| 191 | struct rb_node *next; | 192 | struct rb_node *next; |
| 192 | struct hist_entry *n; | 193 | struct hist_entry *n; |
| 193 | u64 min_callchain_hits; | 194 | u64 min_callchain_hits; |
| 195 | u64 nr_hists = 0; | ||
| 194 | 196 | ||
| 195 | min_callchain_hits = | 197 | min_callchain_hits = |
| 196 | total_samples * (callchain_param.min_percent / 100); | 198 | total_samples * (callchain_param.min_percent / 100); |
| @@ -205,9 +207,11 @@ void perf_session__output_resort(struct rb_root *hists, u64 total_samples) | |||
| 205 | rb_erase(&n->rb_node, hists); | 207 | rb_erase(&n->rb_node, hists); |
| 206 | perf_session__insert_output_hist_entry(&tmp, n, | 208 | perf_session__insert_output_hist_entry(&tmp, n, |
| 207 | min_callchain_hits); | 209 | min_callchain_hits); |
| 210 | ++nr_hists; | ||
| 208 | } | 211 | } |
| 209 | 212 | ||
| 210 | *hists = tmp; | 213 | *hists = tmp; |
| 214 | return nr_hists; | ||
| 211 | } | 215 | } |
| 212 | 216 | ||
| 213 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 217 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
| @@ -452,16 +456,17 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self, | |||
| 452 | return ret; | 456 | return ret; |
| 453 | } | 457 | } |
| 454 | 458 | ||
| 455 | size_t hist_entry__fprintf(struct hist_entry *self, | 459 | int hist_entry__snprintf(struct hist_entry *self, |
| 460 | char *s, size_t size, | ||
| 456 | struct perf_session *pair_session, | 461 | struct perf_session *pair_session, |
| 457 | bool show_displacement, | 462 | bool show_displacement, |
| 458 | long displacement, FILE *fp, | 463 | long displacement, bool color, |
| 459 | u64 session_total) | 464 | u64 session_total) |
| 460 | { | 465 | { |
| 461 | struct sort_entry *se; | 466 | struct sort_entry *se; |
| 462 | u64 count, total; | 467 | u64 count, total; |
| 463 | const char *sep = symbol_conf.field_sep; | 468 | const char *sep = symbol_conf.field_sep; |
| 464 | size_t ret; | 469 | int ret; |
| 465 | 470 | ||
| 466 | if (symbol_conf.exclude_other && !self->parent) | 471 | if (symbol_conf.exclude_other && !self->parent) |
| 467 | return 0; | 472 | return 0; |
| @@ -474,17 +479,22 @@ size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 474 | total = session_total; | 479 | total = session_total; |
| 475 | } | 480 | } |
| 476 | 481 | ||
| 477 | if (total) | 482 | if (total) { |
| 478 | ret = percent_color_fprintf(fp, sep ? "%.2f" : " %6.2f%%", | 483 | if (color) |
| 479 | (count * 100.0) / total); | 484 | ret = percent_color_snprintf(s, size, |
| 480 | else | 485 | sep ? "%.2f" : " %6.2f%%", |
| 481 | ret = fprintf(fp, sep ? "%lld" : "%12lld ", count); | 486 | (count * 100.0) / total); |
| 487 | else | ||
| 488 | ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%", | ||
| 489 | (count * 100.0) / total); | ||
| 490 | } else | ||
| 491 | ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count); | ||
| 482 | 492 | ||
| 483 | if (symbol_conf.show_nr_samples) { | 493 | if (symbol_conf.show_nr_samples) { |
| 484 | if (sep) | 494 | if (sep) |
| 485 | ret += fprintf(fp, "%c%lld", *sep, count); | 495 | ret += snprintf(s + ret, size - ret, "%c%lld", *sep, count); |
| 486 | else | 496 | else |
| 487 | ret += fprintf(fp, "%11lld", count); | 497 | ret += snprintf(s + ret, size - ret, "%11lld", count); |
| 488 | } | 498 | } |
| 489 | 499 | ||
| 490 | if (pair_session) { | 500 | if (pair_session) { |
| @@ -504,9 +514,9 @@ size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 504 | snprintf(bf, sizeof(bf), " "); | 514 | snprintf(bf, sizeof(bf), " "); |
| 505 | 515 | ||
| 506 | if (sep) | 516 | if (sep) |
| 507 | ret += fprintf(fp, "%c%s", *sep, bf); | 517 | ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); |
| 508 | else | 518 | else |
| 509 | ret += fprintf(fp, "%11.11s", bf); | 519 | ret += snprintf(s + ret, size - ret, "%11.11s", bf); |
| 510 | 520 | ||
| 511 | if (show_displacement) { | 521 | if (show_displacement) { |
| 512 | if (displacement) | 522 | if (displacement) |
| @@ -515,9 +525,9 @@ size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 515 | snprintf(bf, sizeof(bf), " "); | 525 | snprintf(bf, sizeof(bf), " "); |
| 516 | 526 | ||
| 517 | if (sep) | 527 | if (sep) |
| 518 | ret += fprintf(fp, "%c%s", *sep, bf); | 528 | ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf); |
| 519 | else | 529 | else |
| 520 | ret += fprintf(fp, "%6.6s", bf); | 530 | ret += snprintf(s + ret, size - ret, "%6.6s", bf); |
| 521 | } | 531 | } |
| 522 | } | 532 | } |
| 523 | 533 | ||
| @@ -525,11 +535,25 @@ size_t hist_entry__fprintf(struct hist_entry *self, | |||
| 525 | if (se->elide) | 535 | if (se->elide) |
| 526 | continue; | 536 | continue; |
| 527 | 537 | ||
| 528 | ret += fprintf(fp, "%s", sep ?: " "); | 538 | ret += snprintf(s + ret, size - ret, "%s", sep ?: " "); |
| 529 | ret += se->print(fp, self, se->width ? *se->width : 0); | 539 | ret += se->snprintf(self, s + ret, size - ret, |
| 540 | se->width ? *se->width : 0); | ||
| 530 | } | 541 | } |
| 531 | 542 | ||
| 532 | return ret + fprintf(fp, "\n"); | 543 | return ret; |
| 544 | } | ||
| 545 | |||
| 546 | int hist_entry__fprintf(struct hist_entry *self, | ||
| 547 | struct perf_session *pair_session, | ||
| 548 | bool show_displacement, | ||
| 549 | long displacement, FILE *fp, | ||
| 550 | u64 session_total) | ||
| 551 | { | ||
| 552 | char bf[512]; | ||
| 553 | hist_entry__snprintf(self, bf, sizeof(bf), pair_session, | ||
| 554 | show_displacement, displacement, | ||
| 555 | true, session_total); | ||
| 556 | return fprintf(fp, "%s\n", bf); | ||
| 533 | } | 557 | } |
| 534 | 558 | ||
| 535 | static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, | 559 | static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, |
| @@ -658,7 +682,7 @@ print_entries: | |||
| 658 | 682 | ||
| 659 | if (h->ms.map == NULL && verbose > 1) { | 683 | if (h->ms.map == NULL && verbose > 1) { |
| 660 | __map_groups__fprintf_maps(&h->thread->mg, | 684 | __map_groups__fprintf_maps(&h->thread->mg, |
| 661 | MAP__FUNCTION, fp); | 685 | MAP__FUNCTION, verbose, fp); |
| 662 | fprintf(fp, "%.10s end\n", graph_dotted_line); | 686 | fprintf(fp, "%.10s end\n", graph_dotted_line); |
| 663 | } | 687 | } |
| 664 | } | 688 | } |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index fe366ce5db45..ad17f0ad798b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
| @@ -18,14 +18,19 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, | |||
| 18 | u64 count, bool *hit); | 18 | u64 count, bool *hit); |
| 19 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | 19 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); |
| 20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
| 21 | size_t hist_entry__fprintf(struct hist_entry *self, | 21 | int hist_entry__fprintf(struct hist_entry *self, |
| 22 | struct perf_session *pair_session, | 22 | struct perf_session *pair_session, |
| 23 | bool show_displacement, | 23 | bool show_displacement, |
| 24 | long displacement, FILE *fp, | 24 | long displacement, FILE *fp, |
| 25 | u64 session_total); | 25 | u64 session_total); |
| 26 | int hist_entry__snprintf(struct hist_entry *self, | ||
| 27 | char *bf, size_t size, | ||
| 28 | struct perf_session *pair_session, | ||
| 29 | bool show_displacement, long displacement, | ||
| 30 | bool color, u64 session_total); | ||
| 26 | void hist_entry__free(struct hist_entry *); | 31 | void hist_entry__free(struct hist_entry *); |
| 27 | 32 | ||
| 28 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples); | 33 | u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples); |
| 29 | void perf_session__collapse_resort(struct rb_root *hists); | 34 | void perf_session__collapse_resort(struct rb_root *hists); |
| 30 | size_t perf_session__fprintf_hists(struct rb_root *hists, | 35 | size_t perf_session__fprintf_hists(struct rb_root *hists, |
| 31 | struct perf_session *pair, | 36 | struct perf_session *pair, |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 9f2963f9ee9a..37913b241bdf 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | #include "symbol.h" | 1 | #include "symbol.h" |
| 2 | #include <errno.h> | ||
| 2 | #include <limits.h> | 3 | #include <limits.h> |
| 3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 4 | #include <string.h> | 5 | #include <string.h> |
| @@ -234,18 +235,211 @@ u64 map__objdump_2ip(struct map *map, u64 addr) | |||
| 234 | return ip; | 235 | return ip; |
| 235 | } | 236 | } |
| 236 | 237 | ||
| 238 | void map_groups__init(struct map_groups *self) | ||
| 239 | { | ||
| 240 | int i; | ||
| 241 | for (i = 0; i < MAP__NR_TYPES; ++i) { | ||
| 242 | self->maps[i] = RB_ROOT; | ||
| 243 | INIT_LIST_HEAD(&self->removed_maps[i]); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | void map_groups__flush(struct map_groups *self) | ||
| 248 | { | ||
| 249 | int type; | ||
| 250 | |||
| 251 | for (type = 0; type < MAP__NR_TYPES; type++) { | ||
| 252 | struct rb_root *root = &self->maps[type]; | ||
| 253 | struct rb_node *next = rb_first(root); | ||
| 254 | |||
| 255 | while (next) { | ||
| 256 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 257 | next = rb_next(&pos->rb_node); | ||
| 258 | rb_erase(&pos->rb_node, root); | ||
| 259 | /* | ||
| 260 | * We may have references to this map, for | ||
| 261 | * instance in some hist_entry instances, so | ||
| 262 | * just move them to a separate list. | ||
| 263 | */ | ||
| 264 | list_add_tail(&pos->node, &self->removed_maps[pos->type]); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 237 | struct symbol *map_groups__find_symbol(struct map_groups *self, | 269 | struct symbol *map_groups__find_symbol(struct map_groups *self, |
| 238 | enum map_type type, u64 addr, | 270 | enum map_type type, u64 addr, |
| 271 | struct map **mapp, | ||
| 239 | symbol_filter_t filter) | 272 | symbol_filter_t filter) |
| 240 | { | 273 | { |
| 241 | struct map *map = map_groups__find(self, type, addr); | 274 | struct map *map = map_groups__find(self, type, addr); |
| 242 | 275 | ||
| 243 | if (map != NULL) | 276 | if (map != NULL) { |
| 277 | if (mapp != NULL) | ||
| 278 | *mapp = map; | ||
| 244 | return map__find_symbol(map, map->map_ip(map, addr), filter); | 279 | return map__find_symbol(map, map->map_ip(map, addr), filter); |
| 280 | } | ||
| 245 | 281 | ||
| 246 | return NULL; | 282 | return NULL; |
| 247 | } | 283 | } |
| 248 | 284 | ||
| 285 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, | ||
| 286 | enum map_type type, | ||
| 287 | const char *name, | ||
| 288 | struct map **mapp, | ||
| 289 | symbol_filter_t filter) | ||
| 290 | { | ||
| 291 | struct rb_node *nd; | ||
| 292 | |||
| 293 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | ||
| 294 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 295 | struct symbol *sym = map__find_symbol_by_name(pos, name, filter); | ||
| 296 | |||
| 297 | if (sym == NULL) | ||
| 298 | continue; | ||
| 299 | if (mapp != NULL) | ||
| 300 | *mapp = pos; | ||
| 301 | return sym; | ||
| 302 | } | ||
| 303 | |||
| 304 | return NULL; | ||
| 305 | } | ||
| 306 | |||
| 307 | size_t __map_groups__fprintf_maps(struct map_groups *self, | ||
| 308 | enum map_type type, int verbose, FILE *fp) | ||
| 309 | { | ||
| 310 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
| 311 | struct rb_node *nd; | ||
| 312 | |||
| 313 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | ||
| 314 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 315 | printed += fprintf(fp, "Map:"); | ||
| 316 | printed += map__fprintf(pos, fp); | ||
| 317 | if (verbose > 2) { | ||
| 318 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 319 | printed += fprintf(fp, "--\n"); | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | return printed; | ||
| 324 | } | ||
| 325 | |||
| 326 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp) | ||
| 327 | { | ||
| 328 | size_t printed = 0, i; | ||
| 329 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 330 | printed += __map_groups__fprintf_maps(self, i, verbose, fp); | ||
| 331 | return printed; | ||
| 332 | } | ||
| 333 | |||
| 334 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, | ||
| 335 | enum map_type type, | ||
| 336 | int verbose, FILE *fp) | ||
| 337 | { | ||
| 338 | struct map *pos; | ||
| 339 | size_t printed = 0; | ||
| 340 | |||
| 341 | list_for_each_entry(pos, &self->removed_maps[type], node) { | ||
| 342 | printed += fprintf(fp, "Map:"); | ||
| 343 | printed += map__fprintf(pos, fp); | ||
| 344 | if (verbose > 1) { | ||
| 345 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 346 | printed += fprintf(fp, "--\n"); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | return printed; | ||
| 350 | } | ||
| 351 | |||
| 352 | static size_t map_groups__fprintf_removed_maps(struct map_groups *self, | ||
| 353 | int verbose, FILE *fp) | ||
| 354 | { | ||
| 355 | size_t printed = 0, i; | ||
| 356 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 357 | printed += __map_groups__fprintf_removed_maps(self, i, verbose, fp); | ||
| 358 | return printed; | ||
| 359 | } | ||
| 360 | |||
| 361 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp) | ||
| 362 | { | ||
| 363 | size_t printed = map_groups__fprintf_maps(self, verbose, fp); | ||
| 364 | printed += fprintf(fp, "Removed maps:\n"); | ||
| 365 | return printed + map_groups__fprintf_removed_maps(self, verbose, fp); | ||
| 366 | } | ||
| 367 | |||
| 368 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | ||
| 369 | int verbose, FILE *fp) | ||
| 370 | { | ||
| 371 | struct rb_root *root = &self->maps[map->type]; | ||
| 372 | struct rb_node *next = rb_first(root); | ||
| 373 | |||
| 374 | while (next) { | ||
| 375 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 376 | next = rb_next(&pos->rb_node); | ||
| 377 | |||
| 378 | if (!map__overlap(pos, map)) | ||
| 379 | continue; | ||
| 380 | |||
| 381 | if (verbose >= 2) { | ||
| 382 | fputs("overlapping maps:\n", fp); | ||
| 383 | map__fprintf(map, fp); | ||
| 384 | map__fprintf(pos, fp); | ||
| 385 | } | ||
| 386 | |||
| 387 | rb_erase(&pos->rb_node, root); | ||
| 388 | /* | ||
| 389 | * We may have references to this map, for instance in some | ||
| 390 | * hist_entry instances, so just move them to a separate | ||
| 391 | * list. | ||
| 392 | */ | ||
| 393 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | ||
| 394 | /* | ||
| 395 | * Now check if we need to create new maps for areas not | ||
| 396 | * overlapped by the new map: | ||
| 397 | */ | ||
| 398 | if (map->start > pos->start) { | ||
| 399 | struct map *before = map__clone(pos); | ||
| 400 | |||
| 401 | if (before == NULL) | ||
| 402 | return -ENOMEM; | ||
| 403 | |||
| 404 | before->end = map->start - 1; | ||
| 405 | map_groups__insert(self, before); | ||
| 406 | if (verbose >= 2) | ||
| 407 | map__fprintf(before, fp); | ||
| 408 | } | ||
| 409 | |||
| 410 | if (map->end < pos->end) { | ||
| 411 | struct map *after = map__clone(pos); | ||
| 412 | |||
| 413 | if (after == NULL) | ||
| 414 | return -ENOMEM; | ||
| 415 | |||
| 416 | after->start = map->end + 1; | ||
| 417 | map_groups__insert(self, after); | ||
| 418 | if (verbose >= 2) | ||
| 419 | map__fprintf(after, fp); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | |||
| 426 | /* | ||
| 427 | * XXX This should not really _copy_ te maps, but refcount them. | ||
| 428 | */ | ||
| 429 | int map_groups__clone(struct map_groups *self, | ||
| 430 | struct map_groups *parent, enum map_type type) | ||
| 431 | { | ||
| 432 | struct rb_node *nd; | ||
| 433 | for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { | ||
| 434 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
| 435 | struct map *new = map__clone(map); | ||
| 436 | if (new == NULL) | ||
| 437 | return -ENOMEM; | ||
| 438 | map_groups__insert(self, new); | ||
| 439 | } | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 249 | static u64 map__reloc_map_ip(struct map *map, u64 ip) | 443 | static u64 map__reloc_map_ip(struct map *map, u64 ip) |
| 250 | { | 444 | { |
| 251 | return ip + (s64)map->pgoff; | 445 | return ip + (s64)map->pgoff; |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 6a703fa74707..2031278cc06a 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -97,11 +97,14 @@ struct map_groups { | |||
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | size_t __map_groups__fprintf_maps(struct map_groups *self, | 99 | size_t __map_groups__fprintf_maps(struct map_groups *self, |
| 100 | enum map_type type, FILE *fp); | 100 | enum map_type type, int verbose, FILE *fp); |
| 101 | void maps__insert(struct rb_root *maps, struct map *map); | 101 | void maps__insert(struct rb_root *maps, struct map *map); |
| 102 | struct map *maps__find(struct rb_root *maps, u64 addr); | 102 | struct map *maps__find(struct rb_root *maps, u64 addr); |
| 103 | void map_groups__init(struct map_groups *self); | 103 | void map_groups__init(struct map_groups *self); |
| 104 | size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); | 104 | int map_groups__clone(struct map_groups *self, |
| 105 | struct map_groups *parent, enum map_type type); | ||
| 106 | size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp); | ||
| 107 | size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp); | ||
| 105 | 108 | ||
| 106 | static inline void map_groups__insert(struct map_groups *self, struct map *map) | 109 | static inline void map_groups__insert(struct map_groups *self, struct map *map) |
| 107 | { | 110 | { |
| @@ -116,15 +119,33 @@ static inline struct map *map_groups__find(struct map_groups *self, | |||
| 116 | 119 | ||
| 117 | struct symbol *map_groups__find_symbol(struct map_groups *self, | 120 | struct symbol *map_groups__find_symbol(struct map_groups *self, |
| 118 | enum map_type type, u64 addr, | 121 | enum map_type type, u64 addr, |
| 122 | struct map **mapp, | ||
| 119 | symbol_filter_t filter); | 123 | symbol_filter_t filter); |
| 120 | 124 | ||
| 121 | static inline struct symbol *map_groups__find_function(struct map_groups *self, | 125 | struct symbol *map_groups__find_symbol_by_name(struct map_groups *self, |
| 122 | u64 addr, | 126 | enum map_type type, |
| 123 | symbol_filter_t filter) | 127 | const char *name, |
| 128 | struct map **mapp, | ||
| 129 | symbol_filter_t filter); | ||
| 130 | |||
| 131 | static inline | ||
| 132 | struct symbol *map_groups__find_function(struct map_groups *self, u64 addr, | ||
| 133 | struct map **mapp, symbol_filter_t filter) | ||
| 124 | { | 134 | { |
| 125 | return map_groups__find_symbol(self, MAP__FUNCTION, addr, filter); | 135 | return map_groups__find_symbol(self, MAP__FUNCTION, addr, mapp, filter); |
| 126 | } | 136 | } |
| 127 | 137 | ||
| 138 | static inline | ||
| 139 | struct symbol *map_groups__find_function_by_name(struct map_groups *self, | ||
| 140 | const char *name, struct map **mapp, | ||
| 141 | symbol_filter_t filter) | ||
| 142 | { | ||
| 143 | return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter); | ||
| 144 | } | ||
| 145 | |||
| 146 | int map_groups__fixup_overlappings(struct map_groups *self, struct map *map, | ||
| 147 | int verbose, FILE *fp); | ||
| 148 | |||
| 128 | struct map *map_groups__find_by_name(struct map_groups *self, | 149 | struct map *map_groups__find_by_name(struct map_groups *self, |
| 129 | enum map_type type, const char *name); | 150 | enum map_type type, const char *name); |
| 130 | int __map_groups__create_kernel_maps(struct map_groups *self, | 151 | int __map_groups__create_kernel_maps(struct map_groups *self, |
| @@ -134,5 +155,6 @@ int map_groups__create_kernel_maps(struct map_groups *self, | |||
| 134 | struct map *vmlinux_maps[MAP__NR_TYPES]); | 155 | struct map *vmlinux_maps[MAP__NR_TYPES]); |
| 135 | struct map *map_groups__new_module(struct map_groups *self, u64 start, | 156 | struct map *map_groups__new_module(struct map_groups *self, u64 start, |
| 136 | const char *filename); | 157 | const char *filename); |
| 158 | void map_groups__flush(struct map_groups *self); | ||
| 137 | 159 | ||
| 138 | #endif /* __PERF_MAP_H */ | 160 | #endif /* __PERF_MAP_H */ |
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index e99bcc8d1939..c93bc2a2d137 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
| @@ -12,6 +12,72 @@ | |||
| 12 | #include "sort.h" | 12 | #include "sort.h" |
| 13 | #include "symbol.h" | 13 | #include "symbol.h" |
| 14 | 14 | ||
| 15 | struct ui_progress { | ||
| 16 | newtComponent form, scale; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct ui_progress *ui_progress__new(const char *title, u64 total) | ||
| 20 | { | ||
| 21 | struct ui_progress *self = malloc(sizeof(*self)); | ||
| 22 | |||
| 23 | if (self != NULL) { | ||
| 24 | int cols; | ||
| 25 | newtGetScreenSize(&cols, NULL); | ||
| 26 | cols -= 4; | ||
| 27 | newtCenteredWindow(cols, 1, title); | ||
| 28 | self->form = newtForm(NULL, NULL, 0); | ||
| 29 | if (self->form == NULL) | ||
| 30 | goto out_free_self; | ||
| 31 | self->scale = newtScale(0, 0, cols, total); | ||
| 32 | if (self->scale == NULL) | ||
| 33 | goto out_free_form; | ||
| 34 | newtFormAddComponents(self->form, self->scale, NULL); | ||
| 35 | newtRefresh(); | ||
| 36 | } | ||
| 37 | |||
| 38 | return self; | ||
| 39 | |||
| 40 | out_free_form: | ||
| 41 | newtFormDestroy(self->form); | ||
| 42 | out_free_self: | ||
| 43 | free(self); | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | |||
| 47 | void ui_progress__update(struct ui_progress *self, u64 curr) | ||
| 48 | { | ||
| 49 | newtScaleSet(self->scale, curr); | ||
| 50 | newtRefresh(); | ||
| 51 | } | ||
| 52 | |||
| 53 | void ui_progress__delete(struct ui_progress *self) | ||
| 54 | { | ||
| 55 | newtFormDestroy(self->form); | ||
| 56 | newtPopWindow(); | ||
| 57 | free(self); | ||
| 58 | } | ||
| 59 | |||
| 60 | static char browser__last_msg[1024]; | ||
| 61 | |||
| 62 | int browser__show_help(const char *format, va_list ap) | ||
| 63 | { | ||
| 64 | int ret; | ||
| 65 | static int backlog; | ||
| 66 | |||
| 67 | ret = vsnprintf(browser__last_msg + backlog, | ||
| 68 | sizeof(browser__last_msg) - backlog, format, ap); | ||
| 69 | backlog += ret; | ||
| 70 | |||
| 71 | if (browser__last_msg[backlog - 1] == '\n') { | ||
| 72 | newtPopHelpLine(); | ||
| 73 | newtPushHelpLine(browser__last_msg); | ||
| 74 | newtRefresh(); | ||
| 75 | backlog = 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 15 | static void newt_form__set_exit_keys(newtComponent self) | 81 | static void newt_form__set_exit_keys(newtComponent self) |
| 16 | { | 82 | { |
| 17 | newtFormAddHotKey(self, NEWT_KEY_ESCAPE); | 83 | newtFormAddHotKey(self, NEWT_KEY_ESCAPE); |
| @@ -228,60 +294,17 @@ static void hist_entry__append_callchain_browser(struct hist_entry *self, | |||
| 228 | } | 294 | } |
| 229 | } | 295 | } |
| 230 | 296 | ||
| 231 | /* | ||
| 232 | * FIXME: get lib/string.c linked with perf somehow | ||
| 233 | */ | ||
| 234 | static char *skip_spaces(const char *str) | ||
| 235 | { | ||
| 236 | while (isspace(*str)) | ||
| 237 | ++str; | ||
| 238 | return (char *)str; | ||
| 239 | } | ||
| 240 | |||
| 241 | static char *strim(char *s) | ||
| 242 | { | ||
| 243 | size_t size; | ||
| 244 | char *end; | ||
| 245 | |||
| 246 | s = skip_spaces(s); | ||
| 247 | size = strlen(s); | ||
| 248 | if (!size) | ||
| 249 | return s; | ||
| 250 | |||
| 251 | end = s + size - 1; | ||
| 252 | while (end >= s && isspace(*end)) | ||
| 253 | end--; | ||
| 254 | *(end + 1) = '\0'; | ||
| 255 | |||
| 256 | return s; | ||
| 257 | } | ||
| 258 | |||
| 259 | static size_t hist_entry__append_browser(struct hist_entry *self, | 297 | static size_t hist_entry__append_browser(struct hist_entry *self, |
| 260 | newtComponent tree, u64 total) | 298 | newtComponent tree, u64 total) |
| 261 | { | 299 | { |
| 262 | char bf[1024], *s; | 300 | char s[256]; |
| 263 | FILE *fp; | 301 | size_t ret; |
| 264 | 302 | ||
| 265 | if (symbol_conf.exclude_other && !self->parent) | 303 | if (symbol_conf.exclude_other && !self->parent) |
| 266 | return 0; | 304 | return 0; |
| 267 | 305 | ||
| 268 | fp = fmemopen(bf, sizeof(bf), "w"); | 306 | ret = hist_entry__snprintf(self, s, sizeof(s), NULL, |
| 269 | if (fp == NULL) | 307 | false, 0, false, total); |
| 270 | return 0; | ||
| 271 | |||
| 272 | hist_entry__fprintf(self, NULL, false, 0, fp, total); | ||
| 273 | fclose(fp); | ||
| 274 | |||
| 275 | /* | ||
| 276 | * FIXME: We shouldn't need to trim, as the printing routines shouldn't | ||
| 277 | * add spaces it in the first place, the stdio output routines should | ||
| 278 | * call a __snprintf method instead of the current __print (that | ||
| 279 | * actually is a __fprintf) one, but get the raw string and _then_ add | ||
| 280 | * the newline, as this is a detail of stdio printing, not needed in | ||
| 281 | * other UIs, e.g. newt. | ||
| 282 | */ | ||
| 283 | s = strim(bf); | ||
| 284 | |||
| 285 | if (symbol_conf.use_callchain) { | 308 | if (symbol_conf.use_callchain) { |
| 286 | int indexes[2]; | 309 | int indexes[2]; |
| 287 | 310 | ||
| @@ -291,10 +314,11 @@ static size_t hist_entry__append_browser(struct hist_entry *self, | |||
| 291 | } else | 314 | } else |
| 292 | newtListboxAppendEntry(tree, s, &self->ms); | 315 | newtListboxAppendEntry(tree, s, &self->ms); |
| 293 | 316 | ||
| 294 | return strlen(s); | 317 | return ret; |
| 295 | } | 318 | } |
| 296 | 319 | ||
| 297 | static void map_symbol__annotate_browser(const struct map_symbol *self) | 320 | static void map_symbol__annotate_browser(const struct map_symbol *self, |
| 321 | const char *input_name) | ||
| 298 | { | 322 | { |
| 299 | FILE *fp; | 323 | FILE *fp; |
| 300 | int cols, rows; | 324 | int cols, rows; |
| @@ -308,8 +332,8 @@ static void map_symbol__annotate_browser(const struct map_symbol *self) | |||
| 308 | if (self->sym == NULL) | 332 | if (self->sym == NULL) |
| 309 | return; | 333 | return; |
| 310 | 334 | ||
| 311 | if (asprintf(&str, "perf annotate -d \"%s\" %s 2>&1 | expand", | 335 | if (asprintf(&str, "perf annotate -i \"%s\" -d \"%s\" %s 2>&1 | expand", |
| 312 | self->map->dso->name, self->sym->name) < 0) | 336 | input_name, self->map->dso->name, self->sym->name) < 0) |
| 313 | return; | 337 | return; |
| 314 | 338 | ||
| 315 | fp = popen(str, "r"); | 339 | fp = popen(str, "r"); |
| @@ -358,90 +382,121 @@ static const void *newt__symbol_tree_get_current(newtComponent self) | |||
| 358 | return newtListboxGetCurrent(self); | 382 | return newtListboxGetCurrent(self); |
| 359 | } | 383 | } |
| 360 | 384 | ||
| 361 | static void perf_session__selection(newtComponent self, void *data) | 385 | static void hist_browser__selection(newtComponent self, void *data) |
| 362 | { | 386 | { |
| 363 | const struct map_symbol **symbol_ptr = data; | 387 | const struct map_symbol **symbol_ptr = data; |
| 364 | *symbol_ptr = newt__symbol_tree_get_current(self); | 388 | *symbol_ptr = newt__symbol_tree_get_current(self); |
| 365 | } | 389 | } |
| 366 | 390 | ||
| 367 | void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | 391 | struct hist_browser { |
| 368 | const char *helpline) | 392 | newtComponent form, tree; |
| 369 | { | ||
| 370 | struct sort_entry *se; | ||
| 371 | struct rb_node *nd; | ||
| 372 | char seq[] = "."; | ||
| 373 | unsigned int width; | ||
| 374 | char *col_width = symbol_conf.col_width_list_str; | ||
| 375 | int rows, cols, idx; | ||
| 376 | int max_len = 0; | ||
| 377 | char str[1024]; | ||
| 378 | newtComponent form, tree; | ||
| 379 | struct newtExitStruct es; | ||
| 380 | const struct map_symbol *selection; | 393 | const struct map_symbol *selection; |
| 394 | }; | ||
| 381 | 395 | ||
| 382 | snprintf(str, sizeof(str), "Samples: %Ld", session_total); | 396 | static struct hist_browser *hist_browser__new(void) |
| 383 | newtDrawRootText(0, 0, str); | 397 | { |
| 384 | newtPushHelpLine(helpline); | 398 | struct hist_browser *self = malloc(sizeof(*self)); |
| 385 | |||
| 386 | newtGetScreenSize(&cols, &rows); | ||
| 387 | 399 | ||
| 388 | if (symbol_conf.use_callchain) | 400 | if (self != NULL) { |
| 389 | tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq, | 401 | char seq[] = "."; |
| 390 | NEWT_FLAG_SCROLL); | 402 | int rows; |
| 391 | else | ||
| 392 | tree = newtListbox(0, 0, rows - 5, (NEWT_FLAG_SCROLL | | ||
| 393 | NEWT_FLAG_RETURNEXIT)); | ||
| 394 | 403 | ||
| 395 | newtComponentAddCallback(tree, perf_session__selection, &selection); | 404 | newtGetScreenSize(NULL, &rows); |
| 396 | 405 | ||
| 397 | list_for_each_entry(se, &hist_entry__sort_list, list) { | 406 | if (symbol_conf.use_callchain) |
| 398 | if (se->elide) | 407 | self->tree = newtCheckboxTreeMulti(0, 0, rows - 5, seq, |
| 399 | continue; | 408 | NEWT_FLAG_SCROLL); |
| 400 | width = strlen(se->header); | 409 | else |
| 401 | if (se->width) { | 410 | self->tree = newtListbox(0, 0, rows - 5, |
| 402 | if (symbol_conf.col_width_list_str) { | 411 | (NEWT_FLAG_SCROLL | |
| 403 | if (col_width) { | 412 | NEWT_FLAG_RETURNEXIT)); |
| 404 | *se->width = atoi(col_width); | 413 | newtComponentAddCallback(self->tree, hist_browser__selection, |
| 405 | col_width = strchr(col_width, ','); | 414 | &self->selection); |
| 406 | if (col_width) | ||
| 407 | ++col_width; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | *se->width = max(*se->width, width); | ||
| 411 | } | ||
| 412 | } | 415 | } |
| 413 | 416 | ||
| 417 | return self; | ||
| 418 | } | ||
| 419 | |||
| 420 | static void hist_browser__delete(struct hist_browser *self) | ||
| 421 | { | ||
| 422 | newtFormDestroy(self->form); | ||
| 423 | newtPopWindow(); | ||
| 424 | free(self); | ||
| 425 | } | ||
| 426 | |||
| 427 | static int hist_browser__populate(struct hist_browser *self, struct rb_root *hists, | ||
| 428 | u64 nr_hists, u64 session_total) | ||
| 429 | { | ||
| 430 | int max_len = 0, idx, cols, rows; | ||
| 431 | struct ui_progress *progress; | ||
| 432 | struct rb_node *nd; | ||
| 433 | u64 curr_hist = 0; | ||
| 434 | |||
| 435 | progress = ui_progress__new("Adding entries to the browser...", nr_hists); | ||
| 436 | if (progress == NULL) | ||
| 437 | return -1; | ||
| 438 | |||
| 414 | idx = 0; | 439 | idx = 0; |
| 415 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | 440 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { |
| 416 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | 441 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); |
| 417 | int len = hist_entry__append_browser(h, tree, session_total); | 442 | int len = hist_entry__append_browser(h, self->tree, session_total); |
| 418 | if (len > max_len) | 443 | if (len > max_len) |
| 419 | max_len = len; | 444 | max_len = len; |
| 420 | if (symbol_conf.use_callchain) | 445 | if (symbol_conf.use_callchain) |
| 421 | hist_entry__append_callchain_browser(h, tree, session_total, idx++); | 446 | hist_entry__append_callchain_browser(h, self->tree, |
| 447 | session_total, idx++); | ||
| 448 | ++curr_hist; | ||
| 449 | if (curr_hist % 5) | ||
| 450 | ui_progress__update(progress, curr_hist); | ||
| 422 | } | 451 | } |
| 423 | 452 | ||
| 453 | ui_progress__delete(progress); | ||
| 454 | |||
| 455 | newtGetScreenSize(&cols, &rows); | ||
| 456 | |||
| 424 | if (max_len > cols) | 457 | if (max_len > cols) |
| 425 | max_len = cols - 3; | 458 | max_len = cols - 3; |
| 426 | 459 | ||
| 427 | if (!symbol_conf.use_callchain) | 460 | if (!symbol_conf.use_callchain) |
| 428 | newtListboxSetWidth(tree, max_len); | 461 | newtListboxSetWidth(self->tree, max_len); |
| 429 | 462 | ||
| 430 | newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0), | 463 | newtCenteredWindow(max_len + (symbol_conf.use_callchain ? 5 : 0), |
| 431 | rows - 5, "Report"); | 464 | rows - 5, "Report"); |
| 432 | form = newt_form__new(); | 465 | self->form = newt_form__new(); |
| 433 | newtFormAddHotKey(form, 'A'); | 466 | newtFormAddHotKey(self->form, 'A'); |
| 434 | newtFormAddHotKey(form, 'a'); | 467 | newtFormAddHotKey(self->form, 'a'); |
| 435 | newtFormAddHotKey(form, NEWT_KEY_RIGHT); | 468 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); |
| 436 | newtFormAddComponents(form, tree, NULL); | 469 | newtFormAddComponents(self->form, self->tree, NULL); |
| 437 | selection = newt__symbol_tree_get_current(tree); | 470 | self->selection = newt__symbol_tree_get_current(self->tree); |
| 471 | |||
| 472 | return 0; | ||
| 473 | } | ||
| 474 | |||
| 475 | int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, | ||
| 476 | u64 session_total, const char *helpline, | ||
| 477 | const char *input_name) | ||
| 478 | { | ||
| 479 | struct newtExitStruct es; | ||
| 480 | char str[1024]; | ||
| 481 | int err = -1; | ||
| 482 | struct hist_browser *browser = hist_browser__new(); | ||
| 483 | |||
| 484 | if (browser == NULL) | ||
| 485 | return -1; | ||
| 486 | |||
| 487 | snprintf(str, sizeof(str), "Samples: %Ld", session_total); | ||
| 488 | newtDrawRootText(0, 0, str); | ||
| 489 | newtPushHelpLine(helpline); | ||
| 490 | |||
| 491 | if (hist_browser__populate(browser, hists, nr_hists, session_total) < 0) | ||
| 492 | goto out; | ||
| 438 | 493 | ||
| 439 | while (1) { | 494 | while (1) { |
| 440 | char annotate[512]; | 495 | char annotate[512]; |
| 441 | const char *options[2]; | 496 | const char *options[2]; |
| 442 | int nr_options = 0, choice = 0; | 497 | int nr_options = 0, choice = 0; |
| 443 | 498 | ||
| 444 | newtFormRun(form, &es); | 499 | newtFormRun(browser->form, &es); |
| 445 | if (es.reason == NEWT_EXIT_HOTKEY) { | 500 | if (es.reason == NEWT_EXIT_HOTKEY) { |
| 446 | if (toupper(es.u.key) == 'A') | 501 | if (toupper(es.u.key) == 'A') |
| 447 | goto do_annotate; | 502 | goto do_annotate; |
| @@ -455,9 +510,9 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | |||
| 455 | } | 510 | } |
| 456 | } | 511 | } |
| 457 | 512 | ||
| 458 | if (selection->sym != NULL) { | 513 | if (browser->selection->sym != NULL) { |
| 459 | snprintf(annotate, sizeof(annotate), | 514 | snprintf(annotate, sizeof(annotate), |
| 460 | "Annotate %s", selection->sym->name); | 515 | "Annotate %s", browser->selection->sym->name); |
| 461 | options[nr_options++] = annotate; | 516 | options[nr_options++] = annotate; |
| 462 | } | 517 | } |
| 463 | 518 | ||
| @@ -466,41 +521,22 @@ void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | |||
| 466 | if (choice == nr_options - 1) | 521 | if (choice == nr_options - 1) |
| 467 | break; | 522 | break; |
| 468 | do_annotate: | 523 | do_annotate: |
| 469 | if (selection->sym != NULL && choice >= 0) { | 524 | if (browser->selection->sym != NULL && choice >= 0) { |
| 470 | if (selection->map->dso->origin == DSO__ORIG_KERNEL) { | 525 | if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { |
| 471 | newtPopHelpLine(); | 526 | newtPopHelpLine(); |
| 472 | newtPushHelpLine("No vmlinux file found, can't " | 527 | newtPushHelpLine("No vmlinux file found, can't " |
| 473 | "annotate with just a " | 528 | "annotate with just a " |
| 474 | "kallsyms file"); | 529 | "kallsyms file"); |
| 475 | continue; | 530 | continue; |
| 476 | } | 531 | } |
| 477 | map_symbol__annotate_browser(selection); | 532 | map_symbol__annotate_browser(browser->selection, |
| 533 | input_name); | ||
| 478 | } | 534 | } |
| 479 | } | 535 | } |
| 480 | 536 | err = 0; | |
| 481 | newtFormDestroy(form); | 537 | out: |
| 482 | newtPopWindow(); | 538 | hist_browser__delete(browser); |
| 483 | } | 539 | return err; |
| 484 | |||
| 485 | static char browser__last_msg[1024]; | ||
| 486 | |||
| 487 | int browser__show_help(const char *format, va_list ap) | ||
| 488 | { | ||
| 489 | int ret; | ||
| 490 | static int backlog; | ||
| 491 | |||
| 492 | ret = vsnprintf(browser__last_msg + backlog, | ||
| 493 | sizeof(browser__last_msg) - backlog, format, ap); | ||
| 494 | backlog += ret; | ||
| 495 | |||
| 496 | if (browser__last_msg[backlog - 1] == '\n') { | ||
| 497 | newtPopHelpLine(); | ||
| 498 | newtPushHelpLine(browser__last_msg); | ||
| 499 | newtRefresh(); | ||
| 500 | backlog = 0; | ||
| 501 | } | ||
| 502 | |||
| 503 | return ret; | ||
| 504 | } | 540 | } |
| 505 | 541 | ||
| 506 | void setup_browser(void) | 542 | void setup_browser(void) |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 76b4ac689df9..ddf288fca3eb 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -52,11 +52,6 @@ out_close: | |||
| 52 | return -1; | 52 | return -1; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static inline int perf_session__create_kernel_maps(struct perf_session *self) | ||
| 56 | { | ||
| 57 | return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps); | ||
| 58 | } | ||
| 59 | |||
| 60 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) | 55 | struct perf_session *perf_session__new(const char *filename, int mode, bool force) |
| 61 | { | 56 | { |
| 62 | size_t len = filename ? strlen(filename) + 1 : 0; | 57 | size_t len = filename ? strlen(filename) + 1 : 0; |
| @@ -123,16 +118,11 @@ struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, | |||
| 123 | struct symbol **parent) | 118 | struct symbol **parent) |
| 124 | { | 119 | { |
| 125 | u8 cpumode = PERF_RECORD_MISC_USER; | 120 | u8 cpumode = PERF_RECORD_MISC_USER; |
| 126 | struct map_symbol *syms = NULL; | ||
| 127 | unsigned int i; | 121 | unsigned int i; |
| 122 | struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); | ||
| 128 | 123 | ||
| 129 | if (symbol_conf.use_callchain) { | 124 | if (!syms) |
| 130 | syms = calloc(chain->nr, sizeof(*syms)); | 125 | return NULL; |
| 131 | if (!syms) { | ||
| 132 | fprintf(stderr, "Can't allocate memory for symbols\n"); | ||
| 133 | exit(-1); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | 126 | ||
| 137 | for (i = 0; i < chain->nr; i++) { | 127 | for (i = 0; i < chain->nr; i++) { |
| 138 | u64 ip = chain->ips[i]; | 128 | u64 ip = chain->ips[i]; |
| @@ -397,6 +387,10 @@ int __perf_session__process_events(struct perf_session *self, | |||
| 397 | event_t *event; | 387 | event_t *event; |
| 398 | uint32_t size; | 388 | uint32_t size; |
| 399 | char *buf; | 389 | char *buf; |
| 390 | struct ui_progress *progress = ui_progress__new("Processing events...", | ||
| 391 | self->size); | ||
| 392 | if (progress == NULL) | ||
| 393 | return -1; | ||
| 400 | 394 | ||
| 401 | perf_event_ops__fill_defaults(ops); | 395 | perf_event_ops__fill_defaults(ops); |
| 402 | 396 | ||
| @@ -425,6 +419,7 @@ remap: | |||
| 425 | 419 | ||
| 426 | more: | 420 | more: |
| 427 | event = (event_t *)(buf + head); | 421 | event = (event_t *)(buf + head); |
| 422 | ui_progress__update(progress, offset); | ||
| 428 | 423 | ||
| 429 | if (self->header.needs_swap) | 424 | if (self->header.needs_swap) |
| 430 | perf_event_header__bswap(&event->header); | 425 | perf_event_header__bswap(&event->header); |
| @@ -475,6 +470,7 @@ more: | |||
| 475 | done: | 470 | done: |
| 476 | err = 0; | 471 | err = 0; |
| 477 | out_err: | 472 | out_err: |
| 473 | ui_progress__delete(progress); | ||
| 478 | return err; | 474 | return err; |
| 479 | } | 475 | } |
| 480 | 476 | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 631f8157fc17..27f4c2dc715b 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
| @@ -80,6 +80,11 @@ static inline int __perf_session__create_kernel_maps(struct perf_session *self, | |||
| 80 | self->vmlinux_maps, kernel); | 80 | self->vmlinux_maps, kernel); |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static inline int perf_session__create_kernel_maps(struct perf_session *self) | ||
| 84 | { | ||
| 85 | return map_groups__create_kernel_maps(&self->kmaps, self->vmlinux_maps); | ||
| 86 | } | ||
| 87 | |||
| 83 | static inline struct map * | 88 | static inline struct map * |
| 84 | perf_session__new_module_map(struct perf_session *self, | 89 | perf_session__new_module_map(struct perf_session *self, |
| 85 | u64 start, const char *filename) | 90 | u64 start, const char *filename) |
| @@ -88,11 +93,17 @@ static inline struct map * | |||
| 88 | } | 93 | } |
| 89 | 94 | ||
| 90 | #ifdef NO_NEWT_SUPPORT | 95 | #ifdef NO_NEWT_SUPPORT |
| 91 | static inline void perf_session__browse_hists(struct rb_root *hists __used, | 96 | static inline int perf_session__browse_hists(struct rb_root *hists __used, |
| 97 | u64 nr_hists __used, | ||
| 92 | u64 session_total __used, | 98 | u64 session_total __used, |
| 93 | const char *helpline __used) {} | 99 | const char *helpline __used, |
| 100 | const char *input_name __used) | ||
| 101 | { | ||
| 102 | return 0; | ||
| 103 | } | ||
| 94 | #else | 104 | #else |
| 95 | void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | 105 | int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists, |
| 96 | const char *helpline); | 106 | u64 session_total, const char *helpline, |
| 107 | const char *input_name); | ||
| 97 | #endif | 108 | #endif |
| 98 | #endif /* __PERF_SESSION_H */ | 109 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 9b80c13cae46..9d24d4b2c8fb 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -18,10 +18,21 @@ char * field_sep; | |||
| 18 | 18 | ||
| 19 | LIST_HEAD(hist_entry__sort_list); | 19 | LIST_HEAD(hist_entry__sort_list); |
| 20 | 20 | ||
| 21 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, | ||
| 22 | size_t size, unsigned int width); | ||
| 23 | static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, | ||
| 24 | size_t size, unsigned int width); | ||
| 25 | static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, | ||
| 26 | size_t size, unsigned int width); | ||
| 27 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | ||
| 28 | size_t size, unsigned int width); | ||
| 29 | static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, | ||
| 30 | size_t size, unsigned int width); | ||
| 31 | |||
| 21 | struct sort_entry sort_thread = { | 32 | struct sort_entry sort_thread = { |
| 22 | .header = "Command: Pid", | 33 | .header = "Command: Pid", |
| 23 | .cmp = sort__thread_cmp, | 34 | .cmp = sort__thread_cmp, |
| 24 | .print = sort__thread_print, | 35 | .snprintf = hist_entry__thread_snprintf, |
| 25 | .width = &threads__col_width, | 36 | .width = &threads__col_width, |
| 26 | }; | 37 | }; |
| 27 | 38 | ||
| @@ -29,27 +40,27 @@ struct sort_entry sort_comm = { | |||
| 29 | .header = "Command", | 40 | .header = "Command", |
| 30 | .cmp = sort__comm_cmp, | 41 | .cmp = sort__comm_cmp, |
| 31 | .collapse = sort__comm_collapse, | 42 | .collapse = sort__comm_collapse, |
| 32 | .print = sort__comm_print, | 43 | .snprintf = hist_entry__comm_snprintf, |
| 33 | .width = &comms__col_width, | 44 | .width = &comms__col_width, |
| 34 | }; | 45 | }; |
| 35 | 46 | ||
| 36 | struct sort_entry sort_dso = { | 47 | struct sort_entry sort_dso = { |
| 37 | .header = "Shared Object", | 48 | .header = "Shared Object", |
| 38 | .cmp = sort__dso_cmp, | 49 | .cmp = sort__dso_cmp, |
| 39 | .print = sort__dso_print, | 50 | .snprintf = hist_entry__dso_snprintf, |
| 40 | .width = &dsos__col_width, | 51 | .width = &dsos__col_width, |
| 41 | }; | 52 | }; |
| 42 | 53 | ||
| 43 | struct sort_entry sort_sym = { | 54 | struct sort_entry sort_sym = { |
| 44 | .header = "Symbol", | 55 | .header = "Symbol", |
| 45 | .cmp = sort__sym_cmp, | 56 | .cmp = sort__sym_cmp, |
| 46 | .print = sort__sym_print, | 57 | .snprintf = hist_entry__sym_snprintf, |
| 47 | }; | 58 | }; |
| 48 | 59 | ||
| 49 | struct sort_entry sort_parent = { | 60 | struct sort_entry sort_parent = { |
| 50 | .header = "Parent symbol", | 61 | .header = "Parent symbol", |
| 51 | .cmp = sort__parent_cmp, | 62 | .cmp = sort__parent_cmp, |
| 52 | .print = sort__parent_print, | 63 | .snprintf = hist_entry__parent_snprintf, |
| 53 | .width = &parent_symbol__col_width, | 64 | .width = &parent_symbol__col_width, |
| 54 | }; | 65 | }; |
| 55 | 66 | ||
| @@ -85,45 +96,38 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 85 | return right->thread->pid - left->thread->pid; | 96 | return right->thread->pid - left->thread->pid; |
| 86 | } | 97 | } |
| 87 | 98 | ||
| 88 | int repsep_fprintf(FILE *fp, const char *fmt, ...) | 99 | static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) |
| 89 | { | 100 | { |
| 90 | int n; | 101 | int n; |
| 91 | va_list ap; | 102 | va_list ap; |
| 92 | 103 | ||
| 93 | va_start(ap, fmt); | 104 | va_start(ap, fmt); |
| 94 | if (!field_sep) | 105 | n = vsnprintf(bf, size, fmt, ap); |
| 95 | n = vfprintf(fp, fmt, ap); | 106 | if (field_sep && n > 0) { |
| 96 | else { | 107 | char *sep = bf; |
| 97 | char *bf = NULL; | 108 | |
| 98 | n = vasprintf(&bf, fmt, ap); | 109 | while (1) { |
| 99 | if (n > 0) { | 110 | sep = strchr(sep, *field_sep); |
| 100 | char *sep = bf; | 111 | if (sep == NULL) |
| 101 | 112 | break; | |
| 102 | while (1) { | 113 | *sep = '.'; |
| 103 | sep = strchr(sep, *field_sep); | ||
| 104 | if (sep == NULL) | ||
| 105 | break; | ||
| 106 | *sep = '.'; | ||
| 107 | } | ||
| 108 | } | 114 | } |
| 109 | fputs(bf, fp); | ||
| 110 | free(bf); | ||
| 111 | } | 115 | } |
| 112 | va_end(ap); | 116 | va_end(ap); |
| 113 | return n; | 117 | return n; |
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | size_t | 120 | static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, |
| 117 | sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width) | 121 | size_t size, unsigned int width) |
| 118 | { | 122 | { |
| 119 | return repsep_fprintf(fp, "%*s:%5d", width - 6, | 123 | return repsep_snprintf(bf, size, "%*s:%5d", width, |
| 120 | self->thread->comm ?: "", self->thread->pid); | 124 | self->thread->comm ?: "", self->thread->pid); |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 123 | size_t | 127 | static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, |
| 124 | sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width) | 128 | size_t size, unsigned int width) |
| 125 | { | 129 | { |
| 126 | return repsep_fprintf(fp, "%*s", width, self->thread->comm); | 130 | return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); |
| 127 | } | 131 | } |
| 128 | 132 | ||
| 129 | /* --sort dso */ | 133 | /* --sort dso */ |
| @@ -149,16 +153,16 @@ sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 149 | return strcmp(dso_name_l, dso_name_r); | 153 | return strcmp(dso_name_l, dso_name_r); |
| 150 | } | 154 | } |
| 151 | 155 | ||
| 152 | size_t | 156 | static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, |
| 153 | sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width) | 157 | size_t size, unsigned int width) |
| 154 | { | 158 | { |
| 155 | if (self->ms.map && self->ms.map->dso) { | 159 | if (self->ms.map && self->ms.map->dso) { |
| 156 | const char *dso_name = !verbose ? self->ms.map->dso->short_name : | 160 | const char *dso_name = !verbose ? self->ms.map->dso->short_name : |
| 157 | self->ms.map->dso->long_name; | 161 | self->ms.map->dso->long_name; |
| 158 | return repsep_fprintf(fp, "%-*s", width, dso_name); | 162 | return repsep_snprintf(bf, size, "%-*s", width, dso_name); |
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | return repsep_fprintf(fp, "%*llx", width, (u64)self->ip); | 165 | return repsep_snprintf(bf, size, "%*Lx", width, self->ip); |
| 162 | } | 166 | } |
| 163 | 167 | ||
| 164 | /* --sort symbol */ | 168 | /* --sort symbol */ |
| @@ -177,22 +181,22 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 177 | return (int64_t)(ip_r - ip_l); | 181 | return (int64_t)(ip_r - ip_l); |
| 178 | } | 182 | } |
| 179 | 183 | ||
| 180 | 184 | static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, | |
| 181 | size_t | 185 | size_t size, unsigned int width __used) |
| 182 | sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used) | ||
| 183 | { | 186 | { |
| 184 | size_t ret = 0; | 187 | size_t ret = 0; |
| 185 | 188 | ||
| 186 | if (verbose) { | 189 | if (verbose) { |
| 187 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; | 190 | char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!'; |
| 188 | ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o); | 191 | ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o); |
| 189 | } | 192 | } |
| 190 | 193 | ||
| 191 | ret += repsep_fprintf(fp, "[%c] ", self->level); | 194 | ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level); |
| 192 | if (self->ms.sym) | 195 | if (self->ms.sym) |
| 193 | ret += repsep_fprintf(fp, "%s", self->ms.sym->name); | 196 | ret += repsep_snprintf(bf + ret, size - ret, "%s", |
| 197 | self->ms.sym->name); | ||
| 194 | else | 198 | else |
| 195 | ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip); | 199 | ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip); |
| 196 | 200 | ||
| 197 | return ret; | 201 | return ret; |
| 198 | } | 202 | } |
| @@ -231,10 +235,10 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) | |||
| 231 | return strcmp(sym_l->name, sym_r->name); | 235 | return strcmp(sym_l->name, sym_r->name); |
| 232 | } | 236 | } |
| 233 | 237 | ||
| 234 | size_t | 238 | static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, |
| 235 | sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width) | 239 | size_t size, unsigned int width) |
| 236 | { | 240 | { |
| 237 | return repsep_fprintf(fp, "%-*s", width, | 241 | return repsep_snprintf(bf, size, "%-*s", width, |
| 238 | self->parent ? self->parent->name : "[other]"); | 242 | self->parent ? self->parent->name : "[other]"); |
| 239 | } | 243 | } |
| 240 | 244 | ||
| @@ -260,9 +264,8 @@ int sort_dimension__add(const char *tok) | |||
| 260 | char err[BUFSIZ]; | 264 | char err[BUFSIZ]; |
| 261 | 265 | ||
| 262 | regerror(ret, &parent_regex, err, sizeof(err)); | 266 | regerror(ret, &parent_regex, err, sizeof(err)); |
| 263 | fprintf(stderr, "Invalid regex: %s\n%s", | 267 | pr_err("Invalid regex: %s\n%s", parent_pattern, err); |
| 264 | parent_pattern, err); | 268 | return -EINVAL; |
| 265 | exit(-1); | ||
| 266 | } | 269 | } |
| 267 | sort__has_parent = 1; | 270 | sort__has_parent = 1; |
| 268 | } | 271 | } |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 598568696f97..5bf2b744e7b2 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -49,12 +49,12 @@ struct hist_entry { | |||
| 49 | u64 ip; | 49 | u64 ip; |
| 50 | char level; | 50 | char level; |
| 51 | struct symbol *parent; | 51 | struct symbol *parent; |
| 52 | struct callchain_node callchain; | ||
| 53 | union { | 52 | union { |
| 54 | unsigned long position; | 53 | unsigned long position; |
| 55 | struct hist_entry *pair; | 54 | struct hist_entry *pair; |
| 56 | struct rb_root sorted_chain; | 55 | struct rb_root sorted_chain; |
| 57 | }; | 56 | }; |
| 57 | struct callchain_node callchain[0]; | ||
| 58 | }; | 58 | }; |
| 59 | 59 | ||
| 60 | enum sort_type { | 60 | enum sort_type { |
| @@ -76,7 +76,8 @@ struct sort_entry { | |||
| 76 | 76 | ||
| 77 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); | 77 | int64_t (*cmp)(struct hist_entry *, struct hist_entry *); |
| 78 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); | 78 | int64_t (*collapse)(struct hist_entry *, struct hist_entry *); |
| 79 | size_t (*print)(FILE *fp, struct hist_entry *, unsigned int width); | 79 | int (*snprintf)(struct hist_entry *self, char *bf, size_t size, |
| 80 | unsigned int width); | ||
| 80 | unsigned int *width; | 81 | unsigned int *width; |
| 81 | bool elide; | 82 | bool elide; |
| 82 | }; | 83 | }; |
| @@ -86,7 +87,6 @@ extern struct list_head hist_entry__sort_list; | |||
| 86 | 87 | ||
| 87 | void setup_sorting(const char * const usagestr[], const struct option *opts); | 88 | void setup_sorting(const char * const usagestr[], const struct option *opts); |
| 88 | 89 | ||
| 89 | extern int repsep_fprintf(FILE *fp, const char *fmt, ...); | ||
| 90 | extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); | 90 | extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); |
| 91 | extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); | 91 | extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); |
| 92 | extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int); | 92 | extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int); |
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h deleted file mode 100644 index 700582416664..000000000000 --- a/tools/perf/util/string.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | #ifndef __PERF_STRING_H_ | ||
| 2 | #define __PERF_STRING_H_ | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include "types.h" | ||
| 6 | |||
| 7 | s64 perf_atoll(const char *str); | ||
| 8 | char **argv_split(const char *str, int *argcp); | ||
| 9 | void argv_free(char **argv); | ||
| 10 | bool strglobmatch(const char *str, const char *pat); | ||
| 11 | bool strlazymatch(const char *str, const char *pat); | ||
| 12 | |||
| 13 | #define _STR(x) #x | ||
| 14 | #define STR(x) _STR(x) | ||
| 15 | |||
| 16 | #endif /* __PERF_STRING_H */ | ||
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 9bbe27d75306..1f7ecd47f499 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -38,15 +38,6 @@ failure: | |||
| 38 | return ret; | 38 | return ret; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void map_groups__init(struct map_groups *self) | ||
| 42 | { | ||
| 43 | int i; | ||
| 44 | for (i = 0; i < MAP__NR_TYPES; ++i) { | ||
| 45 | self->maps[i] = RB_ROOT; | ||
| 46 | INIT_LIST_HEAD(&self->removed_maps[i]); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | static struct thread *thread__new(pid_t pid) | 41 | static struct thread *thread__new(pid_t pid) |
| 51 | { | 42 | { |
| 52 | struct thread *self = zalloc(sizeof(*self)); | 43 | struct thread *self = zalloc(sizeof(*self)); |
| @@ -62,28 +53,6 @@ static struct thread *thread__new(pid_t pid) | |||
| 62 | return self; | 53 | return self; |
| 63 | } | 54 | } |
| 64 | 55 | ||
| 65 | static void map_groups__flush(struct map_groups *self) | ||
| 66 | { | ||
| 67 | int type; | ||
| 68 | |||
| 69 | for (type = 0; type < MAP__NR_TYPES; type++) { | ||
| 70 | struct rb_root *root = &self->maps[type]; | ||
| 71 | struct rb_node *next = rb_first(root); | ||
| 72 | |||
| 73 | while (next) { | ||
| 74 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 75 | next = rb_next(&pos->rb_node); | ||
| 76 | rb_erase(&pos->rb_node, root); | ||
| 77 | /* | ||
| 78 | * We may have references to this map, for | ||
| 79 | * instance in some hist_entry instances, so | ||
| 80 | * just move them to a separate list. | ||
| 81 | */ | ||
| 82 | list_add_tail(&pos->node, &self->removed_maps[pos->type]); | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | int thread__set_comm(struct thread *self, const char *comm) | 56 | int thread__set_comm(struct thread *self, const char *comm) |
| 88 | { | 57 | { |
| 89 | int err; | 58 | int err; |
| @@ -110,69 +79,10 @@ int thread__comm_len(struct thread *self) | |||
| 110 | return self->comm_len; | 79 | return self->comm_len; |
| 111 | } | 80 | } |
| 112 | 81 | ||
| 113 | size_t __map_groups__fprintf_maps(struct map_groups *self, | ||
| 114 | enum map_type type, FILE *fp) | ||
| 115 | { | ||
| 116 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
| 117 | struct rb_node *nd; | ||
| 118 | |||
| 119 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | ||
| 120 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 121 | printed += fprintf(fp, "Map:"); | ||
| 122 | printed += map__fprintf(pos, fp); | ||
| 123 | if (verbose > 2) { | ||
| 124 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 125 | printed += fprintf(fp, "--\n"); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | return printed; | ||
| 130 | } | ||
| 131 | |||
| 132 | size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp) | ||
| 133 | { | ||
| 134 | size_t printed = 0, i; | ||
| 135 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 136 | printed += __map_groups__fprintf_maps(self, i, fp); | ||
| 137 | return printed; | ||
| 138 | } | ||
| 139 | |||
| 140 | static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, | ||
| 141 | enum map_type type, FILE *fp) | ||
| 142 | { | ||
| 143 | struct map *pos; | ||
| 144 | size_t printed = 0; | ||
| 145 | |||
| 146 | list_for_each_entry(pos, &self->removed_maps[type], node) { | ||
| 147 | printed += fprintf(fp, "Map:"); | ||
| 148 | printed += map__fprintf(pos, fp); | ||
| 149 | if (verbose > 1) { | ||
| 150 | printed += dso__fprintf(pos->dso, type, fp); | ||
| 151 | printed += fprintf(fp, "--\n"); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | return printed; | ||
| 155 | } | ||
| 156 | |||
| 157 | static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp) | ||
| 158 | { | ||
| 159 | size_t printed = 0, i; | ||
| 160 | for (i = 0; i < MAP__NR_TYPES; ++i) | ||
| 161 | printed += __map_groups__fprintf_removed_maps(self, i, fp); | ||
| 162 | return printed; | ||
| 163 | } | ||
| 164 | |||
| 165 | static size_t map_groups__fprintf(struct map_groups *self, FILE *fp) | ||
| 166 | { | ||
| 167 | size_t printed = map_groups__fprintf_maps(self, fp); | ||
| 168 | printed += fprintf(fp, "Removed maps:\n"); | ||
| 169 | return printed + map_groups__fprintf_removed_maps(self, fp); | ||
| 170 | } | ||
| 171 | |||
| 172 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 82 | static size_t thread__fprintf(struct thread *self, FILE *fp) |
| 173 | { | 83 | { |
| 174 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + | 84 | return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + |
| 175 | map_groups__fprintf(&self->mg, fp); | 85 | map_groups__fprintf(&self->mg, verbose, fp); |
| 176 | } | 86 | } |
| 177 | 87 | ||
| 178 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | 88 | struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) |
| @@ -214,87 +124,12 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) | |||
| 214 | return th; | 124 | return th; |
| 215 | } | 125 | } |
| 216 | 126 | ||
| 217 | static int map_groups__fixup_overlappings(struct map_groups *self, | ||
| 218 | struct map *map) | ||
| 219 | { | ||
| 220 | struct rb_root *root = &self->maps[map->type]; | ||
| 221 | struct rb_node *next = rb_first(root); | ||
| 222 | |||
| 223 | while (next) { | ||
| 224 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 225 | next = rb_next(&pos->rb_node); | ||
| 226 | |||
| 227 | if (!map__overlap(pos, map)) | ||
| 228 | continue; | ||
| 229 | |||
| 230 | if (verbose >= 2) { | ||
| 231 | fputs("overlapping maps:\n", stderr); | ||
| 232 | map__fprintf(map, stderr); | ||
| 233 | map__fprintf(pos, stderr); | ||
| 234 | } | ||
| 235 | |||
| 236 | rb_erase(&pos->rb_node, root); | ||
| 237 | /* | ||
| 238 | * We may have references to this map, for instance in some | ||
| 239 | * hist_entry instances, so just move them to a separate | ||
| 240 | * list. | ||
| 241 | */ | ||
| 242 | list_add_tail(&pos->node, &self->removed_maps[map->type]); | ||
| 243 | /* | ||
| 244 | * Now check if we need to create new maps for areas not | ||
| 245 | * overlapped by the new map: | ||
| 246 | */ | ||
| 247 | if (map->start > pos->start) { | ||
| 248 | struct map *before = map__clone(pos); | ||
| 249 | |||
| 250 | if (before == NULL) | ||
| 251 | return -ENOMEM; | ||
| 252 | |||
| 253 | before->end = map->start - 1; | ||
| 254 | map_groups__insert(self, before); | ||
| 255 | if (verbose >= 2) | ||
| 256 | map__fprintf(before, stderr); | ||
| 257 | } | ||
| 258 | |||
| 259 | if (map->end < pos->end) { | ||
| 260 | struct map *after = map__clone(pos); | ||
| 261 | |||
| 262 | if (after == NULL) | ||
| 263 | return -ENOMEM; | ||
| 264 | |||
| 265 | after->start = map->end + 1; | ||
| 266 | map_groups__insert(self, after); | ||
| 267 | if (verbose >= 2) | ||
| 268 | map__fprintf(after, stderr); | ||
| 269 | } | ||
| 270 | } | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | void thread__insert_map(struct thread *self, struct map *map) | 127 | void thread__insert_map(struct thread *self, struct map *map) |
| 276 | { | 128 | { |
| 277 | map_groups__fixup_overlappings(&self->mg, map); | 129 | map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); |
| 278 | map_groups__insert(&self->mg, map); | 130 | map_groups__insert(&self->mg, map); |
| 279 | } | 131 | } |
| 280 | 132 | ||
| 281 | /* | ||
| 282 | * XXX This should not really _copy_ te maps, but refcount them. | ||
| 283 | */ | ||
| 284 | static int map_groups__clone(struct map_groups *self, | ||
| 285 | struct map_groups *parent, enum map_type type) | ||
| 286 | { | ||
| 287 | struct rb_node *nd; | ||
| 288 | for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { | ||
| 289 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
| 290 | struct map *new = map__clone(map); | ||
| 291 | if (new == NULL) | ||
| 292 | return -ENOMEM; | ||
| 293 | map_groups__insert(self, new); | ||
| 294 | } | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | int thread__fork(struct thread *self, struct thread *parent) | 133 | int thread__fork(struct thread *self, struct thread *parent) |
| 299 | { | 134 | { |
| 300 | int i; | 135 | int i; |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 52701087ce04..fbf45d1b26f7 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -42,12 +42,14 @@ | |||
| 42 | #define _ALL_SOURCE 1 | 42 | #define _ALL_SOURCE 1 |
| 43 | #define _GNU_SOURCE 1 | 43 | #define _GNU_SOURCE 1 |
| 44 | #define _BSD_SOURCE 1 | 44 | #define _BSD_SOURCE 1 |
| 45 | #define HAS_BOOL | ||
| 45 | 46 | ||
| 46 | #include <unistd.h> | 47 | #include <unistd.h> |
| 47 | #include <stdio.h> | 48 | #include <stdio.h> |
| 48 | #include <sys/stat.h> | 49 | #include <sys/stat.h> |
| 49 | #include <sys/statfs.h> | 50 | #include <sys/statfs.h> |
| 50 | #include <fcntl.h> | 51 | #include <fcntl.h> |
| 52 | #include <stdbool.h> | ||
| 51 | #include <stddef.h> | 53 | #include <stddef.h> |
| 52 | #include <stdlib.h> | 54 | #include <stdlib.h> |
| 53 | #include <stdarg.h> | 55 | #include <stdarg.h> |
| @@ -78,6 +80,7 @@ | |||
| 78 | #include <pwd.h> | 80 | #include <pwd.h> |
| 79 | #include <inttypes.h> | 81 | #include <inttypes.h> |
| 80 | #include "../../../include/linux/magic.h" | 82 | #include "../../../include/linux/magic.h" |
| 83 | #include "types.h" | ||
| 81 | 84 | ||
| 82 | 85 | ||
| 83 | #ifndef NO_ICONV | 86 | #ifndef NO_ICONV |
| @@ -415,4 +418,13 @@ void git_qsort(void *base, size_t nmemb, size_t size, | |||
| 415 | int mkdir_p(char *path, mode_t mode); | 418 | int mkdir_p(char *path, mode_t mode); |
| 416 | int copyfile(const char *from, const char *to); | 419 | int copyfile(const char *from, const char *to); |
| 417 | 420 | ||
| 421 | s64 perf_atoll(const char *str); | ||
| 422 | char **argv_split(const char *str, int *argcp); | ||
| 423 | void argv_free(char **argv); | ||
| 424 | bool strglobmatch(const char *str, const char *pat); | ||
| 425 | bool strlazymatch(const char *str, const char *pat); | ||
| 426 | |||
| 427 | #define _STR(x) #x | ||
| 428 | #define STR(x) _STR(x) | ||
| 429 | |||
| 418 | #endif | 430 | #endif |
