xref: /linux/tools/perf/builtin-report.c (revision dfc349402de8e95f6a42e8341e9ea193b718eee3)
1 /*
2  * builtin-report.c
3  *
4  * Builtin report command: Analyze the perf.data input file,
5  * look up and read DSOs and symbol information and display
6  * a histogram of results, along various sorting keys.
7  */
8 #include "builtin.h"
9 
10 #include "util/util.h"
11 
12 #include "util/color.h"
13 #include <linux/list.h>
14 #include "util/cache.h"
15 #include <linux/rbtree.h>
16 #include "util/symbol.h"
17 #include "util/string.h"
18 #include "util/callchain.h"
19 #include "util/strlist.h"
20 #include "util/values.h"
21 
22 #include "perf.h"
23 #include "util/debug.h"
24 #include "util/header.h"
25 
26 #include "util/parse-options.h"
27 #include "util/parse-events.h"
28 
29 #include "util/thread.h"
30 
31 static char		const *input_name = "perf.data";
32 
33 static char		default_sort_order[] = "comm,dso,symbol";
34 static char		*sort_order = default_sort_order;
35 static char		*dso_list_str, *comm_list_str, *sym_list_str,
36 			*col_width_list_str;
37 static struct strlist	*dso_list, *comm_list, *sym_list;
38 static char		*field_sep;
39 
40 static int		force;
41 static int		input;
42 static int		show_mask = SHOW_KERNEL | SHOW_USER | SHOW_HV;
43 
44 static int		full_paths;
45 static int		show_nr_samples;
46 
47 static int		show_threads;
48 static struct perf_read_values	show_threads_values;
49 
50 static char		default_pretty_printing_style[] = "normal";
51 static char		*pretty_printing_style = default_pretty_printing_style;
52 
53 static unsigned long	page_size;
54 static unsigned long	mmap_window = 32;
55 
56 static char		default_parent_pattern[] = "^sys_|^do_page_fault";
57 static char		*parent_pattern = default_parent_pattern;
58 static regex_t		parent_regex;
59 
60 static int		exclude_other = 1;
61 
62 static char		callchain_default_opt[] = "fractal,0.5";
63 
64 static int		callchain;
65 
66 static char		__cwd[PATH_MAX];
67 static char		*cwd = __cwd;
68 static int		cwdlen;
69 
70 static struct rb_root	threads;
71 static struct thread	*last_match;
72 
73 static struct perf_header *header;
74 
75 static
76 struct callchain_param	callchain_param = {
77 	.mode	= CHAIN_GRAPH_REL,
78 	.min_percent = 0.5
79 };
80 
81 static u64		sample_type;
82 
83 static int repsep_fprintf(FILE *fp, const char *fmt, ...)
84 {
85 	int n;
86 	va_list ap;
87 
88 	va_start(ap, fmt);
89 	if (!field_sep)
90 		n = vfprintf(fp, fmt, ap);
91 	else {
92 		char *bf = NULL;
93 		n = vasprintf(&bf, fmt, ap);
94 		if (n > 0) {
95 			char *sep = bf;
96 
97 			while (1) {
98 				sep = strchr(sep, *field_sep);
99 				if (sep == NULL)
100 					break;
101 				*sep = '.';
102 			}
103 		}
104 		fputs(bf, fp);
105 		free(bf);
106 	}
107 	va_end(ap);
108 	return n;
109 }
110 
111 static unsigned int dsos__col_width,
112 		    comms__col_width,
113 		    threads__col_width;
114 
115 /*
116  * histogram, sorted on item, collects counts
117  */
118 
119 static struct rb_root hist;
120 
121 struct hist_entry {
122 	struct rb_node		rb_node;
123 
124 	struct thread		*thread;
125 	struct map		*map;
126 	struct dso		*dso;
127 	struct symbol		*sym;
128 	struct symbol		*parent;
129 	u64			ip;
130 	char			level;
131 	struct callchain_node	callchain;
132 	struct rb_root		sorted_chain;
133 
134 	u64			count;
135 };
136 
137 /*
138  * configurable sorting bits
139  */
140 
141 struct sort_entry {
142 	struct list_head list;
143 
144 	const char *header;
145 
146 	int64_t (*cmp)(struct hist_entry *, struct hist_entry *);
147 	int64_t (*collapse)(struct hist_entry *, struct hist_entry *);
148 	size_t	(*print)(FILE *fp, struct hist_entry *, unsigned int width);
149 	unsigned int *width;
150 	bool	elide;
151 };
152 
153 static int64_t cmp_null(void *l, void *r)
154 {
155 	if (!l && !r)
156 		return 0;
157 	else if (!l)
158 		return -1;
159 	else
160 		return 1;
161 }
162 
163 /* --sort pid */
164 
165 static int64_t
166 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
167 {
168 	return right->thread->pid - left->thread->pid;
169 }
170 
171 static size_t
172 sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
173 {
174 	return repsep_fprintf(fp, "%*s:%5d", width - 6,
175 			      self->thread->comm ?: "", self->thread->pid);
176 }
177 
178 static struct sort_entry sort_thread = {
179 	.header = "Command:  Pid",
180 	.cmp	= sort__thread_cmp,
181 	.print	= sort__thread_print,
182 	.width	= &threads__col_width,
183 };
184 
185 /* --sort comm */
186 
187 static int64_t
188 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
189 {
190 	return right->thread->pid - left->thread->pid;
191 }
192 
193 static int64_t
194 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
195 {
196 	char *comm_l = left->thread->comm;
197 	char *comm_r = right->thread->comm;
198 
199 	if (!comm_l || !comm_r)
200 		return cmp_null(comm_l, comm_r);
201 
202 	return strcmp(comm_l, comm_r);
203 }
204 
205 static size_t
206 sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
207 {
208 	return repsep_fprintf(fp, "%*s", width, self->thread->comm);
209 }
210 
211 static struct sort_entry sort_comm = {
212 	.header		= "Command",
213 	.cmp		= sort__comm_cmp,
214 	.collapse	= sort__comm_collapse,
215 	.print		= sort__comm_print,
216 	.width		= &comms__col_width,
217 };
218 
219 /* --sort dso */
220 
221 static int64_t
222 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
223 {
224 	struct dso *dso_l = left->dso;
225 	struct dso *dso_r = right->dso;
226 
227 	if (!dso_l || !dso_r)
228 		return cmp_null(dso_l, dso_r);
229 
230 	return strcmp(dso_l->name, dso_r->name);
231 }
232 
233 static size_t
234 sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
235 {
236 	if (self->dso)
237 		return repsep_fprintf(fp, "%-*s", width, self->dso->name);
238 
239 	return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
240 }
241 
242 static struct sort_entry sort_dso = {
243 	.header = "Shared Object",
244 	.cmp	= sort__dso_cmp,
245 	.print	= sort__dso_print,
246 	.width	= &dsos__col_width,
247 };
248 
249 /* --sort symbol */
250 
251 static int64_t
252 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
253 {
254 	u64 ip_l, ip_r;
255 
256 	if (left->sym == right->sym)
257 		return 0;
258 
259 	ip_l = left->sym ? left->sym->start : left->ip;
260 	ip_r = right->sym ? right->sym->start : right->ip;
261 
262 	return (int64_t)(ip_r - ip_l);
263 }
264 
265 static size_t
266 sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
267 {
268 	size_t ret = 0;
269 
270 	if (verbose)
271 		ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
272 				      dso__symtab_origin(self->dso));
273 
274 	ret += repsep_fprintf(fp, "[%c] ", self->level);
275 	if (self->sym) {
276 		ret += repsep_fprintf(fp, "%s", self->sym->name);
277 
278 		if (self->sym->module)
279 			ret += repsep_fprintf(fp, "\t[%s]",
280 					     self->sym->module->name);
281 	} else {
282 		ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
283 	}
284 
285 	return ret;
286 }
287 
288 static struct sort_entry sort_sym = {
289 	.header = "Symbol",
290 	.cmp	= sort__sym_cmp,
291 	.print	= sort__sym_print,
292 };
293 
294 /* --sort parent */
295 
296 static int64_t
297 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
298 {
299 	struct symbol *sym_l = left->parent;
300 	struct symbol *sym_r = right->parent;
301 
302 	if (!sym_l || !sym_r)
303 		return cmp_null(sym_l, sym_r);
304 
305 	return strcmp(sym_l->name, sym_r->name);
306 }
307 
308 static size_t
309 sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
310 {
311 	return repsep_fprintf(fp, "%-*s", width,
312 			      self->parent ? self->parent->name : "[other]");
313 }
314 
315 static unsigned int parent_symbol__col_width;
316 
317 static struct sort_entry sort_parent = {
318 	.header = "Parent symbol",
319 	.cmp	= sort__parent_cmp,
320 	.print	= sort__parent_print,
321 	.width	= &parent_symbol__col_width,
322 };
323 
324 static int sort__need_collapse = 0;
325 static int sort__has_parent = 0;
326 
327 struct sort_dimension {
328 	const char		*name;
329 	struct sort_entry	*entry;
330 	int			taken;
331 };
332 
333 static struct sort_dimension sort_dimensions[] = {
334 	{ .name = "pid",	.entry = &sort_thread,	},
335 	{ .name = "comm",	.entry = &sort_comm,	},
336 	{ .name = "dso",	.entry = &sort_dso,	},
337 	{ .name = "symbol",	.entry = &sort_sym,	},
338 	{ .name = "parent",	.entry = &sort_parent,	},
339 };
340 
341 static LIST_HEAD(hist_entry__sort_list);
342 
343 static int sort_dimension__add(const char *tok)
344 {
345 	unsigned int i;
346 
347 	for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
348 		struct sort_dimension *sd = &sort_dimensions[i];
349 
350 		if (sd->taken)
351 			continue;
352 
353 		if (strncasecmp(tok, sd->name, strlen(tok)))
354 			continue;
355 
356 		if (sd->entry->collapse)
357 			sort__need_collapse = 1;
358 
359 		if (sd->entry == &sort_parent) {
360 			int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
361 			if (ret) {
362 				char err[BUFSIZ];
363 
364 				regerror(ret, &parent_regex, err, sizeof(err));
365 				fprintf(stderr, "Invalid regex: %s\n%s",
366 					parent_pattern, err);
367 				exit(-1);
368 			}
369 			sort__has_parent = 1;
370 		}
371 
372 		list_add_tail(&sd->entry->list, &hist_entry__sort_list);
373 		sd->taken = 1;
374 
375 		return 0;
376 	}
377 
378 	return -ESRCH;
379 }
380 
381 static int64_t
382 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
383 {
384 	struct sort_entry *se;
385 	int64_t cmp = 0;
386 
387 	list_for_each_entry(se, &hist_entry__sort_list, list) {
388 		cmp = se->cmp(left, right);
389 		if (cmp)
390 			break;
391 	}
392 
393 	return cmp;
394 }
395 
396 static int64_t
397 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
398 {
399 	struct sort_entry *se;
400 	int64_t cmp = 0;
401 
402 	list_for_each_entry(se, &hist_entry__sort_list, list) {
403 		int64_t (*f)(struct hist_entry *, struct hist_entry *);
404 
405 		f = se->collapse ?: se->cmp;
406 
407 		cmp = f(left, right);
408 		if (cmp)
409 			break;
410 	}
411 
412 	return cmp;
413 }
414 
415 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
416 {
417 	int i;
418 	size_t ret = 0;
419 
420 	ret += fprintf(fp, "%s", "                ");
421 
422 	for (i = 0; i < depth; i++)
423 		if (depth_mask & (1 << i))
424 			ret += fprintf(fp, "|          ");
425 		else
426 			ret += fprintf(fp, "           ");
427 
428 	ret += fprintf(fp, "\n");
429 
430 	return ret;
431 }
432 static size_t
433 ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, int depth,
434 		       int depth_mask, int count, u64 total_samples,
435 		       int hits)
436 {
437 	int i;
438 	size_t ret = 0;
439 
440 	ret += fprintf(fp, "%s", "                ");
441 	for (i = 0; i < depth; i++) {
442 		if (depth_mask & (1 << i))
443 			ret += fprintf(fp, "|");
444 		else
445 			ret += fprintf(fp, " ");
446 		if (!count && i == depth - 1) {
447 			double percent;
448 
449 			percent = hits * 100.0 / total_samples;
450 			ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
451 		} else
452 			ret += fprintf(fp, "%s", "          ");
453 	}
454 	if (chain->sym)
455 		ret += fprintf(fp, "%s\n", chain->sym->name);
456 	else
457 		ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
458 
459 	return ret;
460 }
461 
462 static struct symbol *rem_sq_bracket;
463 static struct callchain_list rem_hits;
464 
465 static void init_rem_hits(void)
466 {
467 	rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
468 	if (!rem_sq_bracket) {
469 		fprintf(stderr, "Not enough memory to display remaining hits\n");
470 		return;
471 	}
472 
473 	strcpy(rem_sq_bracket->name, "[...]");
474 	rem_hits.sym = rem_sq_bracket;
475 }
476 
477 static size_t
478 callchain__fprintf_graph(FILE *fp, struct callchain_node *self,
479 			u64 total_samples, int depth, int depth_mask)
480 {
481 	struct rb_node *node, *next;
482 	struct callchain_node *child;
483 	struct callchain_list *chain;
484 	int new_depth_mask = depth_mask;
485 	u64 new_total;
486 	u64 remaining;
487 	size_t ret = 0;
488 	int i;
489 
490 	if (callchain_param.mode == CHAIN_GRAPH_REL)
491 		new_total = self->children_hit;
492 	else
493 		new_total = total_samples;
494 
495 	remaining = new_total;
496 
497 	node = rb_first(&self->rb_root);
498 	while (node) {
499 		u64 cumul;
500 
501 		child = rb_entry(node, struct callchain_node, rb_node);
502 		cumul = cumul_hits(child);
503 		remaining -= cumul;
504 
505 		/*
506 		 * The depth mask manages the output of pipes that show
507 		 * the depth. We don't want to keep the pipes of the current
508 		 * level for the last child of this depth.
509 		 * Except if we have remaining filtered hits. They will
510 		 * supersede the last child
511 		 */
512 		next = rb_next(node);
513 		if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
514 			new_depth_mask &= ~(1 << (depth - 1));
515 
516 		/*
517 		 * But we keep the older depth mask for the line seperator
518 		 * to keep the level link until we reach the last child
519 		 */
520 		ret += ipchain__fprintf_graph_line(fp, depth, depth_mask);
521 		i = 0;
522 		list_for_each_entry(chain, &child->val, list) {
523 			if (chain->ip >= PERF_CONTEXT_MAX)
524 				continue;
525 			ret += ipchain__fprintf_graph(fp, chain, depth,
526 						      new_depth_mask, i++,
527 						      new_total,
528 						      cumul);
529 		}
530 		ret += callchain__fprintf_graph(fp, child, new_total,
531 						depth + 1,
532 						new_depth_mask | (1 << depth));
533 		node = next;
534 	}
535 
536 	if (callchain_param.mode == CHAIN_GRAPH_REL &&
537 		remaining && remaining != new_total) {
538 
539 		if (!rem_sq_bracket)
540 			return ret;
541 
542 		new_depth_mask &= ~(1 << (depth - 1));
543 
544 		ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
545 					      new_depth_mask, 0, new_total,
546 					      remaining);
547 	}
548 
549 	return ret;
550 }
551 
552 static size_t
553 callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
554 			u64 total_samples)
555 {
556 	struct callchain_list *chain;
557 	size_t ret = 0;
558 
559 	if (!self)
560 		return 0;
561 
562 	ret += callchain__fprintf_flat(fp, self->parent, total_samples);
563 
564 
565 	list_for_each_entry(chain, &self->val, list) {
566 		if (chain->ip >= PERF_CONTEXT_MAX)
567 			continue;
568 		if (chain->sym)
569 			ret += fprintf(fp, "                %s\n", chain->sym->name);
570 		else
571 			ret += fprintf(fp, "                %p\n",
572 					(void *)(long)chain->ip);
573 	}
574 
575 	return ret;
576 }
577 
578 static size_t
579 hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
580 			      u64 total_samples)
581 {
582 	struct rb_node *rb_node;
583 	struct callchain_node *chain;
584 	size_t ret = 0;
585 
586 	rb_node = rb_first(&self->sorted_chain);
587 	while (rb_node) {
588 		double percent;
589 
590 		chain = rb_entry(rb_node, struct callchain_node, rb_node);
591 		percent = chain->hit * 100.0 / total_samples;
592 		switch (callchain_param.mode) {
593 		case CHAIN_FLAT:
594 			ret += percent_color_fprintf(fp, "           %6.2f%%\n",
595 						     percent);
596 			ret += callchain__fprintf_flat(fp, chain, total_samples);
597 			break;
598 		case CHAIN_GRAPH_ABS: /* Falldown */
599 		case CHAIN_GRAPH_REL:
600 			ret += callchain__fprintf_graph(fp, chain,
601 							total_samples, 1, 1);
602 		case CHAIN_NONE:
603 		default:
604 			break;
605 		}
606 		ret += fprintf(fp, "\n");
607 		rb_node = rb_next(rb_node);
608 	}
609 
610 	return ret;
611 }
612 
613 
614 static size_t
615 hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
616 {
617 	struct sort_entry *se;
618 	size_t ret;
619 
620 	if (exclude_other && !self->parent)
621 		return 0;
622 
623 	if (total_samples)
624 		ret = percent_color_fprintf(fp,
625 					    field_sep ? "%.2f" : "   %6.2f%%",
626 					(self->count * 100.0) / total_samples);
627 	else
628 		ret = fprintf(fp, field_sep ? "%lld" : "%12lld ", self->count);
629 
630 	if (show_nr_samples) {
631 		if (field_sep)
632 			fprintf(fp, "%c%lld", *field_sep, self->count);
633 		else
634 			fprintf(fp, "%11lld", self->count);
635 	}
636 
637 	list_for_each_entry(se, &hist_entry__sort_list, list) {
638 		if (se->elide)
639 			continue;
640 
641 		fprintf(fp, "%s", field_sep ?: "  ");
642 		ret += se->print(fp, self, se->width ? *se->width : 0);
643 	}
644 
645 	ret += fprintf(fp, "\n");
646 
647 	if (callchain)
648 		hist_entry_callchain__fprintf(fp, self, total_samples);
649 
650 	return ret;
651 }
652 
653 /*
654  *
655  */
656 
657 static void dso__calc_col_width(struct dso *self)
658 {
659 	if (!col_width_list_str && !field_sep &&
660 	    (!dso_list || strlist__has_entry(dso_list, self->name))) {
661 		unsigned int slen = strlen(self->name);
662 		if (slen > dsos__col_width)
663 			dsos__col_width = slen;
664 	}
665 
666 	self->slen_calculated = 1;
667 }
668 
669 static void thread__comm_adjust(struct thread *self)
670 {
671 	char *comm = self->comm;
672 
673 	if (!col_width_list_str && !field_sep &&
674 	    (!comm_list || strlist__has_entry(comm_list, comm))) {
675 		unsigned int slen = strlen(comm);
676 
677 		if (slen > comms__col_width) {
678 			comms__col_width = slen;
679 			threads__col_width = slen + 6;
680 		}
681 	}
682 }
683 
684 static int thread__set_comm_adjust(struct thread *self, const char *comm)
685 {
686 	int ret = thread__set_comm(self, comm);
687 
688 	if (ret)
689 		return ret;
690 
691 	thread__comm_adjust(self);
692 
693 	return 0;
694 }
695 
696 
697 static struct symbol *
698 resolve_symbol(struct thread *thread, struct map **mapp,
699 	       struct dso **dsop, u64 *ipp)
700 {
701 	struct dso *dso = dsop ? *dsop : NULL;
702 	struct map *map = mapp ? *mapp : NULL;
703 	u64 ip = *ipp;
704 
705 	if (!thread)
706 		return NULL;
707 
708 	if (dso)
709 		goto got_dso;
710 
711 	if (map)
712 		goto got_map;
713 
714 	map = thread__find_map(thread, ip);
715 	if (map != NULL) {
716 		/*
717 		 * We have to do this here as we may have a dso
718 		 * with no symbol hit that has a name longer than
719 		 * the ones with symbols sampled.
720 		 */
721 		if (!sort_dso.elide && !map->dso->slen_calculated)
722 			dso__calc_col_width(map->dso);
723 
724 		if (mapp)
725 			*mapp = map;
726 got_map:
727 		ip = map->map_ip(map, ip);
728 
729 		dso = map->dso;
730 	} else {
731 		/*
732 		 * If this is outside of all known maps,
733 		 * and is a negative address, try to look it
734 		 * up in the kernel dso, as it might be a
735 		 * vsyscall (which executes in user-mode):
736 		 */
737 		if ((long long)ip < 0)
738 		dso = kernel_dso;
739 	}
740 	dump_printf(" ...... dso: %s\n", dso ? dso->name : "<not found>");
741 	dump_printf(" ...... map: %Lx -> %Lx\n", *ipp, ip);
742 	*ipp  = ip;
743 
744 	if (dsop)
745 		*dsop = dso;
746 
747 	if (!dso)
748 		return NULL;
749 got_dso:
750 	return dso->find_symbol(dso, ip);
751 }
752 
753 static int call__match(struct symbol *sym)
754 {
755 	if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0))
756 		return 1;
757 
758 	return 0;
759 }
760 
761 static struct symbol **
762 resolve_callchain(struct thread *thread, struct map *map __used,
763 		    struct ip_callchain *chain, struct hist_entry *entry)
764 {
765 	u64 context = PERF_CONTEXT_MAX;
766 	struct symbol **syms = NULL;
767 	unsigned int i;
768 
769 	if (callchain) {
770 		syms = calloc(chain->nr, sizeof(*syms));
771 		if (!syms) {
772 			fprintf(stderr, "Can't allocate memory for symbols\n");
773 			exit(-1);
774 		}
775 	}
776 
777 	for (i = 0; i < chain->nr; i++) {
778 		u64 ip = chain->ips[i];
779 		struct dso *dso = NULL;
780 		struct symbol *sym;
781 
782 		if (ip >= PERF_CONTEXT_MAX) {
783 			context = ip;
784 			continue;
785 		}
786 
787 		switch (context) {
788 		case PERF_CONTEXT_HV:
789 			dso = hypervisor_dso;
790 			break;
791 		case PERF_CONTEXT_KERNEL:
792 			dso = kernel_dso;
793 			break;
794 		default:
795 			break;
796 		}
797 
798 		sym = resolve_symbol(thread, NULL, &dso, &ip);
799 
800 		if (sym) {
801 			if (sort__has_parent && call__match(sym) &&
802 			    !entry->parent)
803 				entry->parent = sym;
804 			if (!callchain)
805 				break;
806 			syms[i] = sym;
807 		}
808 	}
809 
810 	return syms;
811 }
812 
813 /*
814  * collect histogram counts
815  */
816 
817 static int
818 hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
819 		struct symbol *sym, u64 ip, struct ip_callchain *chain,
820 		char level, u64 count)
821 {
822 	struct rb_node **p = &hist.rb_node;
823 	struct rb_node *parent = NULL;
824 	struct hist_entry *he;
825 	struct symbol **syms = NULL;
826 	struct hist_entry entry = {
827 		.thread	= thread,
828 		.map	= map,
829 		.dso	= dso,
830 		.sym	= sym,
831 		.ip	= ip,
832 		.level	= level,
833 		.count	= count,
834 		.parent = NULL,
835 		.sorted_chain = RB_ROOT
836 	};
837 	int cmp;
838 
839 	if ((sort__has_parent || callchain) && chain)
840 		syms = resolve_callchain(thread, map, chain, &entry);
841 
842 	while (*p != NULL) {
843 		parent = *p;
844 		he = rb_entry(parent, struct hist_entry, rb_node);
845 
846 		cmp = hist_entry__cmp(&entry, he);
847 
848 		if (!cmp) {
849 			he->count += count;
850 			if (callchain) {
851 				append_chain(&he->callchain, chain, syms);
852 				free(syms);
853 			}
854 			return 0;
855 		}
856 
857 		if (cmp < 0)
858 			p = &(*p)->rb_left;
859 		else
860 			p = &(*p)->rb_right;
861 	}
862 
863 	he = malloc(sizeof(*he));
864 	if (!he)
865 		return -ENOMEM;
866 	*he = entry;
867 	if (callchain) {
868 		callchain_init(&he->callchain);
869 		append_chain(&he->callchain, chain, syms);
870 		free(syms);
871 	}
872 	rb_link_node(&he->rb_node, parent, p);
873 	rb_insert_color(&he->rb_node, &hist);
874 
875 	return 0;
876 }
877 
878 static void hist_entry__free(struct hist_entry *he)
879 {
880 	free(he);
881 }
882 
883 /*
884  * collapse the histogram
885  */
886 
887 static struct rb_root collapse_hists;
888 
889 static void collapse__insert_entry(struct hist_entry *he)
890 {
891 	struct rb_node **p = &collapse_hists.rb_node;
892 	struct rb_node *parent = NULL;
893 	struct hist_entry *iter;
894 	int64_t cmp;
895 
896 	while (*p != NULL) {
897 		parent = *p;
898 		iter = rb_entry(parent, struct hist_entry, rb_node);
899 
900 		cmp = hist_entry__collapse(iter, he);
901 
902 		if (!cmp) {
903 			iter->count += he->count;
904 			hist_entry__free(he);
905 			return;
906 		}
907 
908 		if (cmp < 0)
909 			p = &(*p)->rb_left;
910 		else
911 			p = &(*p)->rb_right;
912 	}
913 
914 	rb_link_node(&he->rb_node, parent, p);
915 	rb_insert_color(&he->rb_node, &collapse_hists);
916 }
917 
918 static void collapse__resort(void)
919 {
920 	struct rb_node *next;
921 	struct hist_entry *n;
922 
923 	if (!sort__need_collapse)
924 		return;
925 
926 	next = rb_first(&hist);
927 	while (next) {
928 		n = rb_entry(next, struct hist_entry, rb_node);
929 		next = rb_next(&n->rb_node);
930 
931 		rb_erase(&n->rb_node, &hist);
932 		collapse__insert_entry(n);
933 	}
934 }
935 
936 /*
937  * reverse the map, sort on count.
938  */
939 
940 static struct rb_root output_hists;
941 
942 static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
943 {
944 	struct rb_node **p = &output_hists.rb_node;
945 	struct rb_node *parent = NULL;
946 	struct hist_entry *iter;
947 
948 	if (callchain)
949 		callchain_param.sort(&he->sorted_chain, &he->callchain,
950 				      min_callchain_hits, &callchain_param);
951 
952 	while (*p != NULL) {
953 		parent = *p;
954 		iter = rb_entry(parent, struct hist_entry, rb_node);
955 
956 		if (he->count > iter->count)
957 			p = &(*p)->rb_left;
958 		else
959 			p = &(*p)->rb_right;
960 	}
961 
962 	rb_link_node(&he->rb_node, parent, p);
963 	rb_insert_color(&he->rb_node, &output_hists);
964 }
965 
966 static void output__resort(u64 total_samples)
967 {
968 	struct rb_node *next;
969 	struct hist_entry *n;
970 	struct rb_root *tree = &hist;
971 	u64 min_callchain_hits;
972 
973 	min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
974 
975 	if (sort__need_collapse)
976 		tree = &collapse_hists;
977 
978 	next = rb_first(tree);
979 
980 	while (next) {
981 		n = rb_entry(next, struct hist_entry, rb_node);
982 		next = rb_next(&n->rb_node);
983 
984 		rb_erase(&n->rb_node, tree);
985 		output__insert_entry(n, min_callchain_hits);
986 	}
987 }
988 
989 static size_t output__fprintf(FILE *fp, u64 total_samples)
990 {
991 	struct hist_entry *pos;
992 	struct sort_entry *se;
993 	struct rb_node *nd;
994 	size_t ret = 0;
995 	unsigned int width;
996 	char *col_width = col_width_list_str;
997 	int raw_printing_style;
998 
999 	raw_printing_style = !strcmp(pretty_printing_style, "raw");
1000 
1001 	init_rem_hits();
1002 
1003 	fprintf(fp, "# Samples: %Ld\n", (u64)total_samples);
1004 	fprintf(fp, "#\n");
1005 
1006 	fprintf(fp, "# Overhead");
1007 	if (show_nr_samples) {
1008 		if (field_sep)
1009 			fprintf(fp, "%cSamples", *field_sep);
1010 		else
1011 			fputs("  Samples  ", fp);
1012 	}
1013 	list_for_each_entry(se, &hist_entry__sort_list, list) {
1014 		if (se->elide)
1015 			continue;
1016 		if (field_sep) {
1017 			fprintf(fp, "%c%s", *field_sep, se->header);
1018 			continue;
1019 		}
1020 		width = strlen(se->header);
1021 		if (se->width) {
1022 			if (col_width_list_str) {
1023 				if (col_width) {
1024 					*se->width = atoi(col_width);
1025 					col_width = strchr(col_width, ',');
1026 					if (col_width)
1027 						++col_width;
1028 				}
1029 			}
1030 			width = *se->width = max(*se->width, width);
1031 		}
1032 		fprintf(fp, "  %*s", width, se->header);
1033 	}
1034 	fprintf(fp, "\n");
1035 
1036 	if (field_sep)
1037 		goto print_entries;
1038 
1039 	fprintf(fp, "# ........");
1040 	if (show_nr_samples)
1041 		fprintf(fp, " ..........");
1042 	list_for_each_entry(se, &hist_entry__sort_list, list) {
1043 		unsigned int i;
1044 
1045 		if (se->elide)
1046 			continue;
1047 
1048 		fprintf(fp, "  ");
1049 		if (se->width)
1050 			width = *se->width;
1051 		else
1052 			width = strlen(se->header);
1053 		for (i = 0; i < width; i++)
1054 			fprintf(fp, ".");
1055 	}
1056 	fprintf(fp, "\n");
1057 
1058 	fprintf(fp, "#\n");
1059 
1060 print_entries:
1061 	for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
1062 		pos = rb_entry(nd, struct hist_entry, rb_node);
1063 		ret += hist_entry__fprintf(fp, pos, total_samples);
1064 	}
1065 
1066 	if (sort_order == default_sort_order &&
1067 			parent_pattern == default_parent_pattern) {
1068 		fprintf(fp, "#\n");
1069 		fprintf(fp, "# (For a higher level overview, try: perf report --sort comm,dso)\n");
1070 		fprintf(fp, "#\n");
1071 	}
1072 	fprintf(fp, "\n");
1073 
1074 	free(rem_sq_bracket);
1075 
1076 	if (show_threads)
1077 		perf_read_values_display(fp, &show_threads_values,
1078 					 raw_printing_style);
1079 
1080 	return ret;
1081 }
1082 
1083 static unsigned long total = 0,
1084 		     total_mmap = 0,
1085 		     total_comm = 0,
1086 		     total_fork = 0,
1087 		     total_unknown = 0,
1088 		     total_lost = 0;
1089 
1090 static int validate_chain(struct ip_callchain *chain, event_t *event)
1091 {
1092 	unsigned int chain_size;
1093 
1094 	chain_size = event->header.size;
1095 	chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event;
1096 
1097 	if (chain->nr*sizeof(u64) > chain_size)
1098 		return -1;
1099 
1100 	return 0;
1101 }
1102 
1103 static int
1104 process_sample_event(event_t *event, unsigned long offset, unsigned long head)
1105 {
1106 	char level;
1107 	int show = 0;
1108 	struct dso *dso = NULL;
1109 	struct thread *thread;
1110 	u64 ip = event->ip.ip;
1111 	u64 period = 1;
1112 	struct map *map = NULL;
1113 	void *more_data = event->ip.__more_data;
1114 	struct ip_callchain *chain = NULL;
1115 	int cpumode;
1116 
1117 	thread = threads__findnew(event->ip.pid, &threads, &last_match);
1118 
1119 	if (sample_type & PERF_SAMPLE_PERIOD) {
1120 		period = *(u64 *)more_data;
1121 		more_data += sizeof(u64);
1122 	}
1123 
1124 	dump_printf("%p [%p]: PERF_RECORD_SAMPLE (IP, %d): %d/%d: %p period: %Ld\n",
1125 		(void *)(offset + head),
1126 		(void *)(long)(event->header.size),
1127 		event->header.misc,
1128 		event->ip.pid, event->ip.tid,
1129 		(void *)(long)ip,
1130 		(long long)period);
1131 
1132 	if (sample_type & PERF_SAMPLE_CALLCHAIN) {
1133 		unsigned int i;
1134 
1135 		chain = (void *)more_data;
1136 
1137 		dump_printf("... chain: nr:%Lu\n", chain->nr);
1138 
1139 		if (validate_chain(chain, event) < 0) {
1140 			eprintf("call-chain problem with event, skipping it.\n");
1141 			return 0;
1142 		}
1143 
1144 		if (dump_trace) {
1145 			for (i = 0; i < chain->nr; i++)
1146 				dump_printf("..... %2d: %016Lx\n", i, chain->ips[i]);
1147 		}
1148 	}
1149 
1150 	dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
1151 
1152 	if (thread == NULL) {
1153 		eprintf("problem processing %d event, skipping it.\n",
1154 			event->header.type);
1155 		return -1;
1156 	}
1157 
1158 	if (comm_list && !strlist__has_entry(comm_list, thread->comm))
1159 		return 0;
1160 
1161 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
1162 
1163 	if (cpumode == PERF_RECORD_MISC_KERNEL) {
1164 		show = SHOW_KERNEL;
1165 		level = 'k';
1166 
1167 		dso = kernel_dso;
1168 
1169 		dump_printf(" ...... dso: %s\n", dso->name);
1170 
1171 	} else if (cpumode == PERF_RECORD_MISC_USER) {
1172 
1173 		show = SHOW_USER;
1174 		level = '.';
1175 
1176 	} else {
1177 		show = SHOW_HV;
1178 		level = 'H';
1179 
1180 		dso = hypervisor_dso;
1181 
1182 		dump_printf(" ...... dso: [hypervisor]\n");
1183 	}
1184 
1185 	if (show & show_mask) {
1186 		struct symbol *sym = resolve_symbol(thread, &map, &dso, &ip);
1187 
1188 		if (dso_list && (!dso || !dso->name ||
1189 				 !strlist__has_entry(dso_list, dso->name)))
1190 			return 0;
1191 
1192 		if (sym_list && (!sym || !strlist__has_entry(sym_list, sym->name)))
1193 			return 0;
1194 
1195 		if (hist_entry__add(thread, map, dso, sym, ip, chain, level, period)) {
1196 			eprintf("problem incrementing symbol count, skipping event\n");
1197 			return -1;
1198 		}
1199 	}
1200 	total += period;
1201 
1202 	return 0;
1203 }
1204 
1205 static int
1206 process_mmap_event(event_t *event, unsigned long offset, unsigned long head)
1207 {
1208 	struct thread *thread;
1209 	struct map *map = map__new(&event->mmap, cwd, cwdlen);
1210 
1211 	thread = threads__findnew(event->mmap.pid, &threads, &last_match);
1212 
1213 	dump_printf("%p [%p]: PERF_RECORD_MMAP %d/%d: [%p(%p) @ %p]: %s\n",
1214 		(void *)(offset + head),
1215 		(void *)(long)(event->header.size),
1216 		event->mmap.pid,
1217 		event->mmap.tid,
1218 		(void *)(long)event->mmap.start,
1219 		(void *)(long)event->mmap.len,
1220 		(void *)(long)event->mmap.pgoff,
1221 		event->mmap.filename);
1222 
1223 	if (thread == NULL || map == NULL) {
1224 		dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
1225 		return 0;
1226 	}
1227 
1228 	thread__insert_map(thread, map);
1229 	total_mmap++;
1230 
1231 	return 0;
1232 }
1233 
1234 static int
1235 process_comm_event(event_t *event, unsigned long offset, unsigned long head)
1236 {
1237 	struct thread *thread;
1238 
1239 	thread = threads__findnew(event->comm.pid, &threads, &last_match);
1240 
1241 	dump_printf("%p [%p]: PERF_RECORD_COMM: %s:%d\n",
1242 		(void *)(offset + head),
1243 		(void *)(long)(event->header.size),
1244 		event->comm.comm, event->comm.pid);
1245 
1246 	if (thread == NULL ||
1247 	    thread__set_comm_adjust(thread, event->comm.comm)) {
1248 		dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
1249 		return -1;
1250 	}
1251 	total_comm++;
1252 
1253 	return 0;
1254 }
1255 
1256 static int
1257 process_task_event(event_t *event, unsigned long offset, unsigned long head)
1258 {
1259 	struct thread *thread;
1260 	struct thread *parent;
1261 
1262 	thread = threads__findnew(event->fork.pid, &threads, &last_match);
1263 	parent = threads__findnew(event->fork.ppid, &threads, &last_match);
1264 
1265 	dump_printf("%p [%p]: PERF_RECORD_%s: (%d:%d):(%d:%d)\n",
1266 		(void *)(offset + head),
1267 		(void *)(long)(event->header.size),
1268 		event->header.type == PERF_RECORD_FORK ? "FORK" : "EXIT",
1269 		event->fork.pid, event->fork.tid,
1270 		event->fork.ppid, event->fork.ptid);
1271 
1272 	/*
1273 	 * A thread clone will have the same PID for both
1274 	 * parent and child.
1275 	 */
1276 	if (thread == parent)
1277 		return 0;
1278 
1279 	if (event->header.type == PERF_RECORD_EXIT)
1280 		return 0;
1281 
1282 	if (!thread || !parent || thread__fork(thread, parent)) {
1283 		dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
1284 		return -1;
1285 	}
1286 	total_fork++;
1287 
1288 	return 0;
1289 }
1290 
1291 static int
1292 process_lost_event(event_t *event, unsigned long offset, unsigned long head)
1293 {
1294 	dump_printf("%p [%p]: PERF_RECORD_LOST: id:%Ld: lost:%Ld\n",
1295 		(void *)(offset + head),
1296 		(void *)(long)(event->header.size),
1297 		event->lost.id,
1298 		event->lost.lost);
1299 
1300 	total_lost += event->lost.lost;
1301 
1302 	return 0;
1303 }
1304 
1305 static int
1306 process_read_event(event_t *event, unsigned long offset, unsigned long head)
1307 {
1308 	struct perf_event_attr *attr;
1309 
1310 	attr = perf_header__find_attr(event->read.id, header);
1311 
1312 	if (show_threads) {
1313 		const char *name = attr ? __event_name(attr->type, attr->config)
1314 				   : "unknown";
1315 		perf_read_values_add_value(&show_threads_values,
1316 					   event->read.pid, event->read.tid,
1317 					   event->read.id,
1318 					   name,
1319 					   event->read.value);
1320 	}
1321 
1322 	dump_printf("%p [%p]: PERF_RECORD_READ: %d %d %s %Lu\n",
1323 			(void *)(offset + head),
1324 			(void *)(long)(event->header.size),
1325 			event->read.pid,
1326 			event->read.tid,
1327 			attr ? __event_name(attr->type, attr->config)
1328 			     : "FAIL",
1329 			event->read.value);
1330 
1331 	return 0;
1332 }
1333 
1334 static int
1335 process_event(event_t *event, unsigned long offset, unsigned long head)
1336 {
1337 	trace_event(event);
1338 
1339 	switch (event->header.type) {
1340 	case PERF_RECORD_SAMPLE:
1341 		return process_sample_event(event, offset, head);
1342 
1343 	case PERF_RECORD_MMAP:
1344 		return process_mmap_event(event, offset, head);
1345 
1346 	case PERF_RECORD_COMM:
1347 		return process_comm_event(event, offset, head);
1348 
1349 	case PERF_RECORD_FORK:
1350 	case PERF_RECORD_EXIT:
1351 		return process_task_event(event, offset, head);
1352 
1353 	case PERF_RECORD_LOST:
1354 		return process_lost_event(event, offset, head);
1355 
1356 	case PERF_RECORD_READ:
1357 		return process_read_event(event, offset, head);
1358 
1359 	/*
1360 	 * We dont process them right now but they are fine:
1361 	 */
1362 
1363 	case PERF_RECORD_THROTTLE:
1364 	case PERF_RECORD_UNTHROTTLE:
1365 		return 0;
1366 
1367 	default:
1368 		return -1;
1369 	}
1370 
1371 	return 0;
1372 }
1373 
1374 static int __cmd_report(void)
1375 {
1376 	int ret, rc = EXIT_FAILURE;
1377 	unsigned long offset = 0;
1378 	unsigned long head, shift;
1379 	struct stat input_stat;
1380 	struct thread *idle;
1381 	event_t *event;
1382 	uint32_t size;
1383 	char *buf;
1384 
1385 	idle = register_idle_thread(&threads, &last_match);
1386 	thread__comm_adjust(idle);
1387 
1388 	if (show_threads)
1389 		perf_read_values_init(&show_threads_values);
1390 
1391 	input = open(input_name, O_RDONLY);
1392 	if (input < 0) {
1393 		fprintf(stderr, " failed to open file: %s", input_name);
1394 		if (!strcmp(input_name, "perf.data"))
1395 			fprintf(stderr, "  (try 'perf record' first)");
1396 		fprintf(stderr, "\n");
1397 		exit(-1);
1398 	}
1399 
1400 	ret = fstat(input, &input_stat);
1401 	if (ret < 0) {
1402 		perror("failed to stat file");
1403 		exit(-1);
1404 	}
1405 
1406 	if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) {
1407 		fprintf(stderr, "file: %s not owned by current user or root\n", input_name);
1408 		exit(-1);
1409 	}
1410 
1411 	if (!input_stat.st_size) {
1412 		fprintf(stderr, "zero-sized file, nothing to do!\n");
1413 		exit(0);
1414 	}
1415 
1416 	header = perf_header__read(input);
1417 	head = header->data_offset;
1418 
1419 	sample_type = perf_header__sample_type(header);
1420 
1421 	if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
1422 		if (sort__has_parent) {
1423 			fprintf(stderr, "selected --sort parent, but no"
1424 					" callchain data. Did you call"
1425 					" perf record without -g?\n");
1426 			exit(-1);
1427 		}
1428 		if (callchain) {
1429 			fprintf(stderr, "selected -g but no callchain data."
1430 					" Did you call perf record without"
1431 					" -g?\n");
1432 			exit(-1);
1433 		}
1434 	} else if (callchain_param.mode != CHAIN_NONE && !callchain) {
1435 			callchain = 1;
1436 			if (register_callchain_param(&callchain_param) < 0) {
1437 				fprintf(stderr, "Can't register callchain"
1438 						" params\n");
1439 				exit(-1);
1440 			}
1441 	}
1442 
1443 	if (load_kernel() < 0) {
1444 		perror("failed to load kernel symbols");
1445 		return EXIT_FAILURE;
1446 	}
1447 
1448 	if (!full_paths) {
1449 		if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
1450 			perror("failed to get the current directory");
1451 			return EXIT_FAILURE;
1452 		}
1453 		cwdlen = strlen(cwd);
1454 	} else {
1455 		cwd = NULL;
1456 		cwdlen = 0;
1457 	}
1458 
1459 	shift = page_size * (head / page_size);
1460 	offset += shift;
1461 	head -= shift;
1462 
1463 remap:
1464 	buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
1465 			   MAP_SHARED, input, offset);
1466 	if (buf == MAP_FAILED) {
1467 		perror("failed to mmap file");
1468 		exit(-1);
1469 	}
1470 
1471 more:
1472 	event = (event_t *)(buf + head);
1473 
1474 	size = event->header.size;
1475 	if (!size)
1476 		size = 8;
1477 
1478 	if (head + event->header.size >= page_size * mmap_window) {
1479 		int munmap_ret;
1480 
1481 		shift = page_size * (head / page_size);
1482 
1483 		munmap_ret = munmap(buf, page_size * mmap_window);
1484 		assert(munmap_ret == 0);
1485 
1486 		offset += shift;
1487 		head -= shift;
1488 		goto remap;
1489 	}
1490 
1491 	size = event->header.size;
1492 
1493 	dump_printf("\n%p [%p]: event: %d\n",
1494 			(void *)(offset + head),
1495 			(void *)(long)event->header.size,
1496 			event->header.type);
1497 
1498 	if (!size || process_event(event, offset, head) < 0) {
1499 
1500 		dump_printf("%p [%p]: skipping unknown header type: %d\n",
1501 			(void *)(offset + head),
1502 			(void *)(long)(event->header.size),
1503 			event->header.type);
1504 
1505 		total_unknown++;
1506 
1507 		/*
1508 		 * assume we lost track of the stream, check alignment, and
1509 		 * increment a single u64 in the hope to catch on again 'soon'.
1510 		 */
1511 
1512 		if (unlikely(head & 7))
1513 			head &= ~7ULL;
1514 
1515 		size = 8;
1516 	}
1517 
1518 	head += size;
1519 
1520 	if (offset + head >= header->data_offset + header->data_size)
1521 		goto done;
1522 
1523 	if (offset + head < (unsigned long)input_stat.st_size)
1524 		goto more;
1525 
1526 done:
1527 	rc = EXIT_SUCCESS;
1528 	close(input);
1529 
1530 	dump_printf("      IP events: %10ld\n", total);
1531 	dump_printf("    mmap events: %10ld\n", total_mmap);
1532 	dump_printf("    comm events: %10ld\n", total_comm);
1533 	dump_printf("    fork events: %10ld\n", total_fork);
1534 	dump_printf("    lost events: %10ld\n", total_lost);
1535 	dump_printf(" unknown events: %10ld\n", total_unknown);
1536 
1537 	if (dump_trace)
1538 		return 0;
1539 
1540 	if (verbose >= 3)
1541 		threads__fprintf(stdout, &threads);
1542 
1543 	if (verbose >= 2)
1544 		dsos__fprintf(stdout);
1545 
1546 	collapse__resort();
1547 	output__resort(total);
1548 	output__fprintf(stdout, total);
1549 
1550 	if (show_threads)
1551 		perf_read_values_destroy(&show_threads_values);
1552 
1553 	return rc;
1554 }
1555 
1556 static int
1557 parse_callchain_opt(const struct option *opt __used, const char *arg,
1558 		    int unset __used)
1559 {
1560 	char *tok;
1561 	char *endptr;
1562 
1563 	callchain = 1;
1564 
1565 	if (!arg)
1566 		return 0;
1567 
1568 	tok = strtok((char *)arg, ",");
1569 	if (!tok)
1570 		return -1;
1571 
1572 	/* get the output mode */
1573 	if (!strncmp(tok, "graph", strlen(arg)))
1574 		callchain_param.mode = CHAIN_GRAPH_ABS;
1575 
1576 	else if (!strncmp(tok, "flat", strlen(arg)))
1577 		callchain_param.mode = CHAIN_FLAT;
1578 
1579 	else if (!strncmp(tok, "fractal", strlen(arg)))
1580 		callchain_param.mode = CHAIN_GRAPH_REL;
1581 
1582 	else if (!strncmp(tok, "none", strlen(arg))) {
1583 		callchain_param.mode = CHAIN_NONE;
1584 		callchain = 0;
1585 
1586 		return 0;
1587 	}
1588 
1589 	else
1590 		return -1;
1591 
1592 	/* get the min percentage */
1593 	tok = strtok(NULL, ",");
1594 	if (!tok)
1595 		goto setup;
1596 
1597 	callchain_param.min_percent = strtod(tok, &endptr);
1598 	if (tok == endptr)
1599 		return -1;
1600 
1601 setup:
1602 	if (register_callchain_param(&callchain_param) < 0) {
1603 		fprintf(stderr, "Can't register callchain params\n");
1604 		return -1;
1605 	}
1606 	return 0;
1607 }
1608 
1609 static const char * const report_usage[] = {
1610 	"perf report [<options>] <command>",
1611 	NULL
1612 };
1613 
1614 static const struct option options[] = {
1615 	OPT_STRING('i', "input", &input_name, "file",
1616 		    "input file name"),
1617 	OPT_BOOLEAN('v', "verbose", &verbose,
1618 		    "be more verbose (show symbol address, etc)"),
1619 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1620 		    "dump raw trace in ASCII"),
1621 	OPT_STRING('k', "vmlinux", &vmlinux_name, "file", "vmlinux pathname"),
1622 	OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1623 	OPT_BOOLEAN('m', "modules", &modules,
1624 		    "load module symbols - WARNING: use only with -k and LIVE kernel"),
1625 	OPT_BOOLEAN('n', "show-nr-samples", &show_nr_samples,
1626 		    "Show a column with the number of samples"),
1627 	OPT_BOOLEAN('T', "threads", &show_threads,
1628 		    "Show per-thread event counters"),
1629 	OPT_STRING(0, "pretty", &pretty_printing_style, "key",
1630 		   "pretty printing style key: normal raw"),
1631 	OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1632 		   "sort by key(s): pid, comm, dso, symbol, parent"),
1633 	OPT_BOOLEAN('P', "full-paths", &full_paths,
1634 		    "Don't shorten the pathnames taking into account the cwd"),
1635 	OPT_STRING('p', "parent", &parent_pattern, "regex",
1636 		   "regex filter to identify parent, see: '--sort parent'"),
1637 	OPT_BOOLEAN('x', "exclude-other", &exclude_other,
1638 		    "Only display entries with parent-match"),
1639 	OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent",
1640 		     "Display callchains using output_type and min percent threshold. "
1641 		     "Default: fractal,0.5", &parse_callchain_opt, callchain_default_opt),
1642 	OPT_STRING('d', "dsos", &dso_list_str, "dso[,dso...]",
1643 		   "only consider symbols in these dsos"),
1644 	OPT_STRING('C', "comms", &comm_list_str, "comm[,comm...]",
1645 		   "only consider symbols in these comms"),
1646 	OPT_STRING('S', "symbols", &sym_list_str, "symbol[,symbol...]",
1647 		   "only consider these symbols"),
1648 	OPT_STRING('w', "column-widths", &col_width_list_str,
1649 		   "width[,width...]",
1650 		   "don't try to adjust column width, use these fixed values"),
1651 	OPT_STRING('t', "field-separator", &field_sep, "separator",
1652 		   "separator for columns, no spaces will be added between "
1653 		   "columns '.' is reserved."),
1654 	OPT_END()
1655 };
1656 
1657 static void setup_sorting(void)
1658 {
1659 	char *tmp, *tok, *str = strdup(sort_order);
1660 
1661 	for (tok = strtok_r(str, ", ", &tmp);
1662 			tok; tok = strtok_r(NULL, ", ", &tmp)) {
1663 		if (sort_dimension__add(tok) < 0) {
1664 			error("Unknown --sort key: `%s'", tok);
1665 			usage_with_options(report_usage, options);
1666 		}
1667 	}
1668 
1669 	free(str);
1670 }
1671 
1672 static void setup_list(struct strlist **list, const char *list_str,
1673 		       struct sort_entry *se, const char *list_name,
1674 		       FILE *fp)
1675 {
1676 	if (list_str) {
1677 		*list = strlist__new(true, list_str);
1678 		if (!*list) {
1679 			fprintf(stderr, "problems parsing %s list\n",
1680 				list_name);
1681 			exit(129);
1682 		}
1683 		if (strlist__nr_entries(*list) == 1) {
1684 			fprintf(fp, "# %s: %s\n", list_name,
1685 				strlist__entry(*list, 0)->s);
1686 			se->elide = true;
1687 		}
1688 	}
1689 }
1690 
1691 int cmd_report(int argc, const char **argv, const char *prefix __used)
1692 {
1693 	symbol__init();
1694 
1695 	page_size = getpagesize();
1696 
1697 	argc = parse_options(argc, argv, options, report_usage, 0);
1698 
1699 	setup_sorting();
1700 
1701 	if (parent_pattern != default_parent_pattern) {
1702 		sort_dimension__add("parent");
1703 		sort_parent.elide = 1;
1704 	} else
1705 		exclude_other = 0;
1706 
1707 	/*
1708 	 * Any (unrecognized) arguments left?
1709 	 */
1710 	if (argc)
1711 		usage_with_options(report_usage, options);
1712 
1713 	setup_pager();
1714 
1715 	setup_list(&dso_list, dso_list_str, &sort_dso, "dso", stdout);
1716 	setup_list(&comm_list, comm_list_str, &sort_comm, "comm", stdout);
1717 	setup_list(&sym_list, sym_list_str, &sort_sym, "symbol", stdout);
1718 
1719 	if (field_sep && *field_sep == '.') {
1720 		fputs("'.' is the only non valid --field-separator argument\n",
1721 		      stderr);
1722 		exit(129);
1723 	}
1724 
1725 	return __cmd_report();
1726 }
1727