aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-04-03 12:16:42 -0400
committerIngo Molnar <mingo@elte.hu>2010-04-03 12:16:42 -0400
commit70a7c1271e2bfca8ad2bf71f44c516ea2763b9ed (patch)
treeeaac85de741bc558529eccaefc372ff1e90ff425 /tools/perf/util
parent40b91cd10f000b4c4934e48e2e5c0bec66def144 (diff)
parent533c46c31c0e82f19dbb087c77d85eaccd6fefdb (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-xtools/perf/util/PERF-VERSION-GEN6
-rw-r--r--tools/perf/util/color.c53
-rw-r--r--tools/perf/util/color.h4
-rw-r--r--tools/perf/util/debug.h16
-rw-r--r--tools/perf/util/event.c9
-rw-r--r--tools/perf/util/hist.c66
-rw-r--r--tools/perf/util/hist.h9
-rw-r--r--tools/perf/util/map.c196
-rw-r--r--tools/perf/util/map.h34
-rw-r--r--tools/perf/util/newt.c298
-rw-r--r--tools/perf/util/session.c22
-rw-r--r--tools/perf/util/session.h19
-rw-r--r--tools/perf/util/sort.c93
-rw-r--r--tools/perf/util/sort.h6
-rw-r--r--tools/perf/util/string.h16
-rw-r--r--tools/perf/util/thread.c169
-rw-r--r--tools/perf/util/util.h12
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
3GVF=PERF-VERSION-FILE 3if [ $# -eq 1 ] ; then
4 OUTPUT=$1
5fi
6
7GVF=${OUTPUT}PERF-VERSION-FILE
4DEF_VER=v0.0.2.PERF 8DEF_VER=v0.0.2.PERF
5 9
6LF=' 10LF='
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
169static 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
169static int __color_vfprintf(FILE *fp, const char *color, const char *fmt, 194static 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
219int 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
194int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args) 225int 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
230int 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
200int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) 242int 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
320int 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);
32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); 32int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
33void color_parse(const char *value, const char *var, char *dst); 33void color_parse(const char *value, const char *var, char *dst);
34void color_parse_mem(const char *value, int len, const char *var, char *dst); 34void color_parse_mem(const char *value, int len, const char *var, char *dst);
35int color_vsnprintf(char *bf, size_t size, const char *color,
36 const char *fmt, va_list args);
35int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args); 37int color_vfprintf(FILE *fp, const char *color, const char *fmt, va_list args);
36int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); 38int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
39int color_snprintf(char *bf, size_t size, const char *color, const char *fmt, ...);
37int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); 40int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
38int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); 41int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
42int percent_color_snprintf(char *bf, size_t size, const char *fmt, double percent);
39int percent_color_fprintf(FILE *fp, const char *fmt, double percent); 43int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
40const char *get_percent_color(double percent); 44const 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;
10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
11void trace_event(event_t *event); 11void trace_event(event_t *event);
12 12
13struct ui_progress;
14
13#ifdef NO_NEWT_SUPPORT 15#ifdef NO_NEWT_SUPPORT
14static inline int browser__show_help(const char *format __used, va_list ap __used) 16static inline int browser__show_help(const char *format __used, va_list ap __used)
15{ 17{
16 return 0; 18 return 0;
17} 19}
20
21static inline struct ui_progress *ui_progress__new(const char *title __used,
22 u64 total __used)
23{
24 return (struct ui_progress *)1;
25}
26
27static inline void ui_progress__update(struct ui_progress *self __used,
28 u64 curr __used) {}
29
30static inline void ui_progress__delete(struct ui_progress *self __used) {}
18#else 31#else
19int browser__show_help(const char *format, va_list ap); 32int browser__show_help(const char *format, va_list ap);
33struct ui_progress *ui_progress__new(const char *title, u64 total);
34void ui_progress__update(struct ui_progress *self, u64 curr);
35void 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
188void perf_session__output_resort(struct rb_root *hists, u64 total_samples) 189u64 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
213static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 217static 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
455size_t hist_entry__fprintf(struct hist_entry *self, 459int 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
546int 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
535static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp, 559static 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);
19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
21size_t hist_entry__fprintf(struct hist_entry *self, 21int 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);
26int 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);
26void hist_entry__free(struct hist_entry *); 31void hist_entry__free(struct hist_entry *);
27 32
28void perf_session__output_resort(struct rb_root *hists, u64 total_samples); 33u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples);
29void perf_session__collapse_resort(struct rb_root *hists); 34void perf_session__collapse_resort(struct rb_root *hists);
30size_t perf_session__fprintf_hists(struct rb_root *hists, 35size_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
238void 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
247void 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
237struct symbol *map_groups__find_symbol(struct map_groups *self, 269struct 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
285struct 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
307size_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
326size_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
334static 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
352static 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
361size_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
368int 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 */
429int 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
249static u64 map__reloc_map_ip(struct map *map, u64 ip) 443static 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
99size_t __map_groups__fprintf_maps(struct map_groups *self, 99size_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);
101void maps__insert(struct rb_root *maps, struct map *map); 101void maps__insert(struct rb_root *maps, struct map *map);
102struct map *maps__find(struct rb_root *maps, u64 addr); 102struct map *maps__find(struct rb_root *maps, u64 addr);
103void map_groups__init(struct map_groups *self); 103void map_groups__init(struct map_groups *self);
104size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp); 104int map_groups__clone(struct map_groups *self,
105 struct map_groups *parent, enum map_type type);
106size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
107size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
105 108
106static inline void map_groups__insert(struct map_groups *self, struct map *map) 109static 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
117struct symbol *map_groups__find_symbol(struct map_groups *self, 120struct 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
121static inline struct symbol *map_groups__find_function(struct map_groups *self, 125struct 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
131static inline
132struct 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
138static inline
139struct 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
146int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
147 int verbose, FILE *fp);
148
128struct map *map_groups__find_by_name(struct map_groups *self, 149struct 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);
130int __map_groups__create_kernel_maps(struct map_groups *self, 151int __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]);
135struct map *map_groups__new_module(struct map_groups *self, u64 start, 156struct map *map_groups__new_module(struct map_groups *self, u64 start,
136 const char *filename); 157 const char *filename);
158void 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
15struct ui_progress {
16 newtComponent form, scale;
17};
18
19struct 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
40out_free_form:
41 newtFormDestroy(self->form);
42out_free_self:
43 free(self);
44 return NULL;
45}
46
47void ui_progress__update(struct ui_progress *self, u64 curr)
48{
49 newtScaleSet(self->scale, curr);
50 newtRefresh();
51}
52
53void ui_progress__delete(struct ui_progress *self)
54{
55 newtFormDestroy(self->form);
56 newtPopWindow();
57 free(self);
58}
59
60static char browser__last_msg[1024];
61
62int 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
15static void newt_form__set_exit_keys(newtComponent self) 81static 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 */
234static char *skip_spaces(const char *str)
235{
236 while (isspace(*str))
237 ++str;
238 return (char *)str;
239}
240
241static 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
259static size_t hist_entry__append_browser(struct hist_entry *self, 297static 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
297static void map_symbol__annotate_browser(const struct map_symbol *self) 320static 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
361static void perf_session__selection(newtComponent self, void *data) 385static 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
367void perf_session__browse_hists(struct rb_root *hists, u64 session_total, 391struct 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); 396static 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
420static void hist_browser__delete(struct hist_browser *self)
421{
422 newtFormDestroy(self->form);
423 newtPopWindow();
424 free(self);
425}
426
427static 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
475int 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;
468do_annotate: 523do_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); 537out:
482 newtPopWindow(); 538 hist_browser__delete(browser);
483} 539 return err;
484
485static char browser__last_msg[1024];
486
487int 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
506void setup_browser(void) 542void 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
55static 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
60struct perf_session *perf_session__new(const char *filename, int mode, bool force) 55struct 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
426more: 420more:
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:
475done: 470done:
476 err = 0; 471 err = 0;
477out_err: 472out_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
83static 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
83static inline struct map * 88static 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
91static inline void perf_session__browse_hists(struct rb_root *hists __used, 96static 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
95void perf_session__browse_hists(struct rb_root *hists, u64 session_total, 105int 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
19LIST_HEAD(hist_entry__sort_list); 19LIST_HEAD(hist_entry__sort_list);
20 20
21static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
22 size_t size, unsigned int width);
23static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
24 size_t size, unsigned int width);
25static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
26 size_t size, unsigned int width);
27static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
28 size_t size, unsigned int width);
29static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
30 size_t size, unsigned int width);
31
21struct sort_entry sort_thread = { 32struct 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
36struct sort_entry sort_dso = { 47struct 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
43struct sort_entry sort_sym = { 54struct 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
49struct sort_entry sort_parent = { 60struct 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
88int repsep_fprintf(FILE *fp, const char *fmt, ...) 99static 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
116size_t 120static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
117sort__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
123size_t 127static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
124sort__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
152size_t 156static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
153sort__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 184static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
181size_t 185 size_t size, unsigned int width __used)
182sort__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
234size_t 238static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
235sort__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
60enum sort_type { 60enum 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
87void setup_sorting(const char * const usagestr[], const struct option *opts); 88void setup_sorting(const char * const usagestr[], const struct option *opts);
88 89
89extern int repsep_fprintf(FILE *fp, const char *fmt, ...);
90extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int); 90extern size_t sort__thread_print(FILE *, struct hist_entry *, unsigned int);
91extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int); 91extern size_t sort__comm_print(FILE *, struct hist_entry *, unsigned int);
92extern size_t sort__dso_print(FILE *, struct hist_entry *, unsigned int); 92extern 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
7s64 perf_atoll(const char *str);
8char **argv_split(const char *str, int *argcp);
9void argv_free(char **argv);
10bool strglobmatch(const char *str, const char *pat);
11bool 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
41void 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
50static struct thread *thread__new(pid_t pid) 41static 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
65static 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
87int thread__set_comm(struct thread *self, const char *comm) 56int 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
113size_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
132size_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
140static 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
157static 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
165static 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
172static size_t thread__fprintf(struct thread *self, FILE *fp) 82static 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
178struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) 88struct 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
217static 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
275void thread__insert_map(struct thread *self, struct map *map) 127void 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 */
284static 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
298int thread__fork(struct thread *self, struct thread *parent) 133int 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,
415int mkdir_p(char *path, mode_t mode); 418int mkdir_p(char *path, mode_t mode);
416int copyfile(const char *from, const char *to); 419int copyfile(const char *from, const char *to);
417 420
421s64 perf_atoll(const char *str);
422char **argv_split(const char *str, int *argcp);
423void argv_free(char **argv);
424bool strglobmatch(const char *str, const char *pat);
425bool strlazymatch(const char *str, const char *pat);
426
427#define _STR(x) #x
428#define STR(x) _STR(x)
429
418#endif 430#endif