]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - tools/perf/util/sort.c
perf tools: Fix segfault on dynamic entries
[mirror_ubuntu-focal-kernel.git] / tools / perf / util / sort.c
CommitLineData
9b32ba71 1#include <sys/mman.h>
dd68ada2 2#include "sort.h"
8a6c5b26 3#include "hist.h"
4dfced35 4#include "comm.h"
08e71542 5#include "symbol.h"
8b536999 6#include "evsel.h"
40184c46
NK
7#include "evlist.h"
8#include <traceevent/event-parse.h>
dd68ada2
JK
9
10regex_t parent_regex;
edb7c60e
ACM
11const char default_parent_pattern[] = "^sys_|^do_page_fault";
12const char *parent_pattern = default_parent_pattern;
13const char default_sort_order[] = "comm,dso,symbol";
40997d6c 14const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
512ae1bd
NK
15const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
16const char default_top_sort_order[] = "dso,symbol";
17const char default_diff_sort_order[] = "dso,symbol";
d49dadea 18const char default_tracepoint_sort_order[] = "trace";
512ae1bd 19const char *sort_order;
a7d945bc 20const char *field_order;
b21484f1
GP
21regex_t ignore_callees_regex;
22int have_ignore_callees = 0;
af0a6fa4
FW
23int sort__need_collapse = 0;
24int sort__has_parent = 0;
1af55640 25int sort__has_sym = 0;
68f6d022 26int sort__has_dso = 0;
2e7ea3ab 27int sort__has_socket = 0;
cfd92dad 28int sort__has_thread = 0;
55369fc1 29enum sort_mode sort__mode = SORT_MODE__NORMAL;
a4fb581b 30
37d9bb58
ACM
31/*
32 * Replaces all occurrences of a char used with the:
33 *
34 * -t, --field-separator
35 *
36 * option, that uses a special separator character and don't pad with spaces,
37 * replacing all occurances of this separator in symbol names (and other
38 * output) with a '.' character, that thus it's the only non valid separator.
39*/
a4e3b956 40static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
dd68ada2
JK
41{
42 int n;
43 va_list ap;
44
45 va_start(ap, fmt);
a4e3b956 46 n = vsnprintf(bf, size, fmt, ap);
0ca0c130 47 if (symbol_conf.field_sep && n > 0) {
a4e3b956
ACM
48 char *sep = bf;
49
50 while (1) {
0ca0c130 51 sep = strchr(sep, *symbol_conf.field_sep);
a4e3b956
ACM
52 if (sep == NULL)
53 break;
54 *sep = '.';
dd68ada2 55 }
dd68ada2
JK
56 }
57 va_end(ap);
b832796c
AB
58
59 if (n >= (int)size)
60 return size - 1;
dd68ada2
JK
61 return n;
62}
63
b9c5143a 64static int64_t cmp_null(const void *l, const void *r)
872a878f
FW
65{
66 if (!l && !r)
67 return 0;
68 else if (!l)
69 return -1;
70 else
71 return 1;
72}
73
74/* --sort pid */
75
76static int64_t
77sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
78{
38051234 79 return right->thread->tid - left->thread->tid;
872a878f
FW
80}
81
c824c433 82static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
a4e3b956 83 size_t size, unsigned int width)
dd68ada2 84{
b9c5143a 85 const char *comm = thread__comm_str(he->thread);
5b591669
NK
86
87 width = max(7U, width) - 6;
88 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
89 width, width, comm ?: "");
dd68ada2
JK
90}
91
872a878f 92struct sort_entry sort_thread = {
8246de88 93 .se_header = " Pid:Command",
872a878f
FW
94 .se_cmp = sort__thread_cmp,
95 .se_snprintf = hist_entry__thread_snprintf,
96 .se_width_idx = HISTC_THREAD,
97};
98
99/* --sort comm */
100
101static int64_t
102sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
103{
fedd63d3 104 /* Compare the addr that should be unique among comm */
2f15bd8c 105 return strcmp(comm__str(right->comm), comm__str(left->comm));
872a878f
FW
106}
107
108static int64_t
109sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
110{
4dfced35 111 /* Compare the addr that should be unique among comm */
2f15bd8c 112 return strcmp(comm__str(right->comm), comm__str(left->comm));
872a878f
FW
113}
114
202e7a6d
NK
115static int64_t
116sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
117{
118 return strcmp(comm__str(right->comm), comm__str(left->comm));
119}
120
c824c433 121static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
a4e3b956 122 size_t size, unsigned int width)
dd68ada2 123{
5b591669 124 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
dd68ada2
JK
125}
126
14d1ac74
NK
127struct sort_entry sort_comm = {
128 .se_header = "Command",
129 .se_cmp = sort__comm_cmp,
130 .se_collapse = sort__comm_collapse,
202e7a6d 131 .se_sort = sort__comm_sort,
14d1ac74
NK
132 .se_snprintf = hist_entry__comm_snprintf,
133 .se_width_idx = HISTC_COMM,
134};
135
136/* --sort dso */
137
b5387528
RAV
138static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
139{
140 struct dso *dso_l = map_l ? map_l->dso : NULL;
141 struct dso *dso_r = map_r ? map_r->dso : NULL;
142 const char *dso_name_l, *dso_name_r;
143
144 if (!dso_l || !dso_r)
202e7a6d 145 return cmp_null(dso_r, dso_l);
b5387528
RAV
146
147 if (verbose) {
148 dso_name_l = dso_l->long_name;
149 dso_name_r = dso_r->long_name;
150 } else {
151 dso_name_l = dso_l->short_name;
152 dso_name_r = dso_r->short_name;
153 }
154
155 return strcmp(dso_name_l, dso_name_r);
156}
157
872a878f 158static int64_t
dd68ada2
JK
159sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
160{
202e7a6d 161 return _sort__dso_cmp(right->ms.map, left->ms.map);
b5387528 162}
dd68ada2 163
14d1ac74
NK
164static int _hist_entry__dso_snprintf(struct map *map, char *bf,
165 size_t size, unsigned int width)
166{
167 if (map && map->dso) {
168 const char *dso_name = !verbose ? map->dso->short_name :
169 map->dso->long_name;
5b591669 170 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
14d1ac74
NK
171 }
172
5b591669 173 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
14d1ac74
NK
174}
175
c824c433 176static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
14d1ac74
NK
177 size_t size, unsigned int width)
178{
c824c433 179 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
14d1ac74
NK
180}
181
182struct sort_entry sort_dso = {
183 .se_header = "Shared Object",
184 .se_cmp = sort__dso_cmp,
185 .se_snprintf = hist_entry__dso_snprintf,
186 .se_width_idx = HISTC_DSO,
187};
188
189/* --sort symbol */
dd68ada2 190
2037be53
NK
191static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
192{
193 return (int64_t)(right_ip - left_ip);
194}
195
51f27d14 196static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
b5387528
RAV
197{
198 if (!sym_l || !sym_r)
199 return cmp_null(sym_l, sym_r);
200
201 if (sym_l == sym_r)
202 return 0;
203
c05676c0
YB
204 if (sym_l->start != sym_r->start)
205 return (int64_t)(sym_r->start - sym_l->start);
b5387528 206
c05676c0 207 return (int64_t)(sym_r->end - sym_l->end);
b5387528
RAV
208}
209
14d1ac74
NK
210static int64_t
211sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
b5387528 212{
09600e0f
NK
213 int64_t ret;
214
14d1ac74 215 if (!left->ms.sym && !right->ms.sym)
2037be53 216 return _sort__addr_cmp(left->ip, right->ip);
dd68ada2 217
09600e0f
NK
218 /*
219 * comparing symbol address alone is not enough since it's a
220 * relative address within a dso.
221 */
68f6d022
NK
222 if (!sort__has_dso) {
223 ret = sort__dso_cmp(left, right);
224 if (ret != 0)
225 return ret;
226 }
09600e0f 227
51f27d14 228 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
b5387528
RAV
229}
230
202e7a6d
NK
231static int64_t
232sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
233{
234 if (!left->ms.sym || !right->ms.sym)
235 return cmp_null(left->ms.sym, right->ms.sym);
236
237 return strcmp(right->ms.sym->name, left->ms.sym->name);
238}
239
b5387528
RAV
240static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
241 u64 ip, char level, char *bf, size_t size,
43355522 242 unsigned int width)
b5387528
RAV
243{
244 size_t ret = 0;
245
246 if (verbose) {
247 char o = map ? dso__symtab_origin(map->dso) : '!';
248 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
ded19d57 249 BITS_PER_LONG / 4 + 2, ip, o);
439d473b 250 }
dd68ada2 251
b5387528 252 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
98a3b32c
SE
253 if (sym && map) {
254 if (map->type == MAP__VARIABLE) {
255 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
256 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
62667746 257 ip - map->unmap_ip(map, sym->start));
98a3b32c 258 } else {
89fee709 259 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
98a3b32c
SE
260 width - ret,
261 sym->name);
262 }
263 } else {
b5387528
RAV
264 size_t len = BITS_PER_LONG / 4;
265 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
266 len, ip);
b5387528
RAV
267 }
268
89fee709 269 return ret;
dd68ada2
JK
270}
271
c824c433 272static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
43355522 273 size_t size, unsigned int width)
b5387528 274{
c824c433
ACM
275 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
276 he->level, bf, size, width);
b5387528 277}
dd68ada2 278
872a878f
FW
279struct sort_entry sort_sym = {
280 .se_header = "Symbol",
281 .se_cmp = sort__sym_cmp,
202e7a6d 282 .se_sort = sort__sym_sort,
872a878f
FW
283 .se_snprintf = hist_entry__sym_snprintf,
284 .se_width_idx = HISTC_SYMBOL,
285};
dd68ada2 286
409a8be6
ACM
287/* --sort srcline */
288
289static int64_t
290sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
291{
4adcc430
NK
292 if (!left->srcline) {
293 if (!left->ms.map)
294 left->srcline = SRCLINE_UNKNOWN;
295 else {
296 struct map *map = left->ms.map;
297 left->srcline = get_srcline(map->dso,
85c116a6
AK
298 map__rip_2objdump(map, left->ip),
299 left->ms.sym, true);
4adcc430
NK
300 }
301 }
302 if (!right->srcline) {
303 if (!right->ms.map)
304 right->srcline = SRCLINE_UNKNOWN;
305 else {
306 struct map *map = right->ms.map;
307 right->srcline = get_srcline(map->dso,
85c116a6
AK
308 map__rip_2objdump(map, right->ip),
309 right->ms.sym, true);
4adcc430
NK
310 }
311 }
202e7a6d 312 return strcmp(right->srcline, left->srcline);
409a8be6
ACM
313}
314
c824c433 315static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
5b591669 316 size_t size, unsigned int width)
409a8be6 317{
b2d53671 318 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
409a8be6
ACM
319}
320
321struct sort_entry sort_srcline = {
322 .se_header = "Source:Line",
323 .se_cmp = sort__srcline_cmp,
324 .se_snprintf = hist_entry__srcline_snprintf,
325 .se_width_idx = HISTC_SRCLINE,
326};
327
31191a85
AK
328/* --sort srcfile */
329
330static char no_srcfile[1];
331
332static char *get_srcfile(struct hist_entry *e)
333{
334 char *sf, *p;
335 struct map *map = e->ms.map;
336
2f84b42b
AK
337 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
338 e->ms.sym, false, true);
76b10655
AK
339 if (!strcmp(sf, SRCLINE_UNKNOWN))
340 return no_srcfile;
31191a85
AK
341 p = strchr(sf, ':');
342 if (p && *sf) {
343 *p = 0;
344 return sf;
345 }
346 free(sf);
347 return no_srcfile;
348}
349
350static int64_t
351sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
352{
353 if (!left->srcfile) {
354 if (!left->ms.map)
355 left->srcfile = no_srcfile;
356 else
357 left->srcfile = get_srcfile(left);
358 }
359 if (!right->srcfile) {
360 if (!right->ms.map)
361 right->srcfile = no_srcfile;
362 else
363 right->srcfile = get_srcfile(right);
364 }
365 return strcmp(right->srcfile, left->srcfile);
366}
367
368static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
369 size_t size, unsigned int width)
370{
371 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
372}
373
374struct sort_entry sort_srcfile = {
375 .se_header = "Source File",
376 .se_cmp = sort__srcfile_cmp,
377 .se_snprintf = hist_entry__srcfile_snprintf,
378 .se_width_idx = HISTC_SRCFILE,
379};
380
dd68ada2
JK
381/* --sort parent */
382
872a878f 383static int64_t
dd68ada2
JK
384sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 struct symbol *sym_l = left->parent;
387 struct symbol *sym_r = right->parent;
388
389 if (!sym_l || !sym_r)
390 return cmp_null(sym_l, sym_r);
391
202e7a6d 392 return strcmp(sym_r->name, sym_l->name);
dd68ada2
JK
393}
394
c824c433 395static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
a4e3b956 396 size_t size, unsigned int width)
dd68ada2 397{
5b591669 398 return repsep_snprintf(bf, size, "%-*.*s", width, width,
c824c433 399 he->parent ? he->parent->name : "[other]");
dd68ada2
JK
400}
401
872a878f
FW
402struct sort_entry sort_parent = {
403 .se_header = "Parent symbol",
404 .se_cmp = sort__parent_cmp,
405 .se_snprintf = hist_entry__parent_snprintf,
406 .se_width_idx = HISTC_PARENT,
407};
408
f60f3593
AS
409/* --sort cpu */
410
872a878f 411static int64_t
f60f3593
AS
412sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
413{
414 return right->cpu - left->cpu;
415}
416
c824c433
ACM
417static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
418 size_t size, unsigned int width)
f60f3593 419{
5b591669 420 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
f60f3593
AS
421}
422
872a878f
FW
423struct sort_entry sort_cpu = {
424 .se_header = "CPU",
425 .se_cmp = sort__cpu_cmp,
426 .se_snprintf = hist_entry__cpu_snprintf,
427 .se_width_idx = HISTC_CPU,
428};
429
2e7ea3ab
KL
430/* --sort socket */
431
432static int64_t
433sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
434{
435 return right->socket - left->socket;
436}
437
438static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
439 size_t size, unsigned int width)
440{
441 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
442}
443
444struct sort_entry sort_socket = {
445 .se_header = "Socket",
446 .se_cmp = sort__socket_cmp,
447 .se_snprintf = hist_entry__socket_snprintf,
448 .se_width_idx = HISTC_SOCKET,
449};
450
a34bb6a0
NK
451/* --sort trace */
452
453static char *get_trace_output(struct hist_entry *he)
454{
455 struct trace_seq seq;
456 struct perf_evsel *evsel;
457 struct pevent_record rec = {
458 .data = he->raw_data,
459 .size = he->raw_size,
460 };
461
462 evsel = hists_to_evsel(he->hists);
463
464 trace_seq_init(&seq);
053a3989
NK
465 if (symbol_conf.raw_trace) {
466 pevent_print_fields(&seq, he->raw_data, he->raw_size,
467 evsel->tp_format);
468 } else {
469 pevent_event_info(&seq, evsel->tp_format, &rec);
470 }
a34bb6a0
NK
471 return seq.buffer;
472}
473
474static int64_t
475sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
476{
477 struct perf_evsel *evsel;
478
479 evsel = hists_to_evsel(left->hists);
480 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
481 return 0;
482
483 if (left->trace_output == NULL)
484 left->trace_output = get_trace_output(left);
485 if (right->trace_output == NULL)
486 right->trace_output = get_trace_output(right);
487
488 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
489 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
490
491 return strcmp(right->trace_output, left->trace_output);
492}
493
494static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
495 size_t size, unsigned int width)
496{
497 struct perf_evsel *evsel;
498
499 evsel = hists_to_evsel(he->hists);
500 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
501 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
502
503 if (he->trace_output == NULL)
504 he->trace_output = get_trace_output(he);
505 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
506}
507
508struct sort_entry sort_trace = {
509 .se_header = "Trace output",
510 .se_cmp = sort__trace_cmp,
511 .se_snprintf = hist_entry__trace_snprintf,
512 .se_width_idx = HISTC_TRACE,
513};
514
14d1ac74
NK
515/* sort keys for branch stacks */
516
b5387528
RAV
517static int64_t
518sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
519{
288a4b91
JO
520 if (!left->branch_info || !right->branch_info)
521 return cmp_null(left->branch_info, right->branch_info);
522
b5387528
RAV
523 return _sort__dso_cmp(left->branch_info->from.map,
524 right->branch_info->from.map);
525}
526
c824c433 527static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
528 size_t size, unsigned int width)
529{
288a4b91
JO
530 if (he->branch_info)
531 return _hist_entry__dso_snprintf(he->branch_info->from.map,
532 bf, size, width);
533 else
534 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
b5387528
RAV
535}
536
b5387528
RAV
537static int64_t
538sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
539{
8b62fa59
JO
540 if (!left->branch_info || !right->branch_info)
541 return cmp_null(left->branch_info, right->branch_info);
542
b5387528
RAV
543 return _sort__dso_cmp(left->branch_info->to.map,
544 right->branch_info->to.map);
545}
546
c824c433 547static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
548 size_t size, unsigned int width)
549{
8b62fa59
JO
550 if (he->branch_info)
551 return _hist_entry__dso_snprintf(he->branch_info->to.map,
552 bf, size, width);
553 else
554 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
b5387528
RAV
555}
556
557static int64_t
558sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
559{
560 struct addr_map_symbol *from_l = &left->branch_info->from;
561 struct addr_map_symbol *from_r = &right->branch_info->from;
562
1b9e97a2
JO
563 if (!left->branch_info || !right->branch_info)
564 return cmp_null(left->branch_info, right->branch_info);
565
566 from_l = &left->branch_info->from;
567 from_r = &right->branch_info->from;
568
b5387528 569 if (!from_l->sym && !from_r->sym)
2037be53 570 return _sort__addr_cmp(from_l->addr, from_r->addr);
b5387528 571
51f27d14 572 return _sort__sym_cmp(from_l->sym, from_r->sym);
b5387528
RAV
573}
574
575static int64_t
576sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
577{
38cdbd39
JO
578 struct addr_map_symbol *to_l, *to_r;
579
580 if (!left->branch_info || !right->branch_info)
581 return cmp_null(left->branch_info, right->branch_info);
582
583 to_l = &left->branch_info->to;
584 to_r = &right->branch_info->to;
b5387528
RAV
585
586 if (!to_l->sym && !to_r->sym)
2037be53 587 return _sort__addr_cmp(to_l->addr, to_r->addr);
b5387528 588
51f27d14 589 return _sort__sym_cmp(to_l->sym, to_r->sym);
b5387528
RAV
590}
591
c824c433 592static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
43355522 593 size_t size, unsigned int width)
b5387528 594{
1b9e97a2
JO
595 if (he->branch_info) {
596 struct addr_map_symbol *from = &he->branch_info->from;
b5387528 597
1b9e97a2
JO
598 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
599 he->level, bf, size, width);
600 }
601
602 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
b5387528
RAV
603}
604
c824c433 605static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
43355522 606 size_t size, unsigned int width)
b5387528 607{
38cdbd39
JO
608 if (he->branch_info) {
609 struct addr_map_symbol *to = &he->branch_info->to;
610
611 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
612 he->level, bf, size, width);
613 }
b5387528 614
38cdbd39 615 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
b5387528
RAV
616}
617
14d1ac74
NK
618struct sort_entry sort_dso_from = {
619 .se_header = "Source Shared Object",
620 .se_cmp = sort__dso_from_cmp,
621 .se_snprintf = hist_entry__dso_from_snprintf,
622 .se_width_idx = HISTC_DSO_FROM,
623};
624
b5387528
RAV
625struct sort_entry sort_dso_to = {
626 .se_header = "Target Shared Object",
627 .se_cmp = sort__dso_to_cmp,
628 .se_snprintf = hist_entry__dso_to_snprintf,
629 .se_width_idx = HISTC_DSO_TO,
630};
631
632struct sort_entry sort_sym_from = {
633 .se_header = "Source Symbol",
634 .se_cmp = sort__sym_from_cmp,
635 .se_snprintf = hist_entry__sym_from_snprintf,
636 .se_width_idx = HISTC_SYMBOL_FROM,
637};
638
639struct sort_entry sort_sym_to = {
640 .se_header = "Target Symbol",
641 .se_cmp = sort__sym_to_cmp,
642 .se_snprintf = hist_entry__sym_to_snprintf,
643 .se_width_idx = HISTC_SYMBOL_TO,
644};
645
646static int64_t
647sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
648{
428560e7 649 unsigned char mp, p;
b5387528 650
428560e7
JO
651 if (!left->branch_info || !right->branch_info)
652 return cmp_null(left->branch_info, right->branch_info);
653
654 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
655 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
b5387528
RAV
656 return mp || p;
657}
658
c824c433 659static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
660 size_t size, unsigned int width){
661 static const char *out = "N/A";
662
428560e7
JO
663 if (he->branch_info) {
664 if (he->branch_info->flags.predicted)
665 out = "N";
666 else if (he->branch_info->flags.mispred)
667 out = "Y";
668 }
b5387528 669
5b591669 670 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
b5387528
RAV
671}
672
0e332f03
AK
673static int64_t
674sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
675{
676 return left->branch_info->flags.cycles -
677 right->branch_info->flags.cycles;
678}
679
680static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
681 size_t size, unsigned int width)
682{
683 if (he->branch_info->flags.cycles == 0)
684 return repsep_snprintf(bf, size, "%-*s", width, "-");
685 return repsep_snprintf(bf, size, "%-*hd", width,
686 he->branch_info->flags.cycles);
687}
688
689struct sort_entry sort_cycles = {
690 .se_header = "Basic Block Cycles",
691 .se_cmp = sort__cycles_cmp,
692 .se_snprintf = hist_entry__cycles_snprintf,
693 .se_width_idx = HISTC_CYCLES,
694};
695
98a3b32c
SE
696/* --sort daddr_sym */
697static int64_t
698sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
699{
700 uint64_t l = 0, r = 0;
701
702 if (left->mem_info)
703 l = left->mem_info->daddr.addr;
704 if (right->mem_info)
705 r = right->mem_info->daddr.addr;
706
707 return (int64_t)(r - l);
708}
709
c824c433 710static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
711 size_t size, unsigned int width)
712{
713 uint64_t addr = 0;
714 struct map *map = NULL;
715 struct symbol *sym = NULL;
716
c824c433
ACM
717 if (he->mem_info) {
718 addr = he->mem_info->daddr.addr;
719 map = he->mem_info->daddr.map;
720 sym = he->mem_info->daddr.sym;
98a3b32c 721 }
c824c433 722 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
98a3b32c
SE
723 width);
724}
725
28e6db20
DZ
726static int64_t
727sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
728{
729 uint64_t l = 0, r = 0;
730
731 if (left->mem_info)
732 l = left->mem_info->iaddr.addr;
733 if (right->mem_info)
734 r = right->mem_info->iaddr.addr;
735
736 return (int64_t)(r - l);
737}
738
739static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
740 size_t size, unsigned int width)
741{
742 uint64_t addr = 0;
743 struct map *map = NULL;
744 struct symbol *sym = NULL;
745
746 if (he->mem_info) {
747 addr = he->mem_info->iaddr.addr;
748 map = he->mem_info->iaddr.map;
749 sym = he->mem_info->iaddr.sym;
750 }
751 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
752 width);
753}
754
98a3b32c
SE
755static int64_t
756sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
757{
758 struct map *map_l = NULL;
759 struct map *map_r = NULL;
760
761 if (left->mem_info)
762 map_l = left->mem_info->daddr.map;
763 if (right->mem_info)
764 map_r = right->mem_info->daddr.map;
765
766 return _sort__dso_cmp(map_l, map_r);
767}
768
c824c433 769static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
770 size_t size, unsigned int width)
771{
772 struct map *map = NULL;
773
c824c433
ACM
774 if (he->mem_info)
775 map = he->mem_info->daddr.map;
98a3b32c
SE
776
777 return _hist_entry__dso_snprintf(map, bf, size, width);
778}
779
780static int64_t
781sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
782{
783 union perf_mem_data_src data_src_l;
784 union perf_mem_data_src data_src_r;
785
786 if (left->mem_info)
787 data_src_l = left->mem_info->data_src;
788 else
789 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
790
791 if (right->mem_info)
792 data_src_r = right->mem_info->data_src;
793 else
794 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
795
796 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
797}
798
c824c433 799static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
800 size_t size, unsigned int width)
801{
802 const char *out;
803 u64 mask = PERF_MEM_LOCK_NA;
804
c824c433
ACM
805 if (he->mem_info)
806 mask = he->mem_info->data_src.mem_lock;
98a3b32c
SE
807
808 if (mask & PERF_MEM_LOCK_NA)
809 out = "N/A";
810 else if (mask & PERF_MEM_LOCK_LOCKED)
811 out = "Yes";
812 else
813 out = "No";
814
89fee709 815 return repsep_snprintf(bf, size, "%.*s", width, out);
98a3b32c
SE
816}
817
818static int64_t
819sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
820{
821 union perf_mem_data_src data_src_l;
822 union perf_mem_data_src data_src_r;
823
824 if (left->mem_info)
825 data_src_l = left->mem_info->data_src;
826 else
827 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
828
829 if (right->mem_info)
830 data_src_r = right->mem_info->data_src;
831 else
832 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
833
834 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
835}
836
837static const char * const tlb_access[] = {
838 "N/A",
839 "HIT",
840 "MISS",
841 "L1",
842 "L2",
843 "Walker",
844 "Fault",
845};
846#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
847
c824c433 848static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
849 size_t size, unsigned int width)
850{
851 char out[64];
852 size_t sz = sizeof(out) - 1; /* -1 for null termination */
853 size_t l = 0, i;
854 u64 m = PERF_MEM_TLB_NA;
855 u64 hit, miss;
856
857 out[0] = '\0';
858
c824c433
ACM
859 if (he->mem_info)
860 m = he->mem_info->data_src.mem_dtlb;
98a3b32c
SE
861
862 hit = m & PERF_MEM_TLB_HIT;
863 miss = m & PERF_MEM_TLB_MISS;
864
865 /* already taken care of */
866 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
867
868 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
869 if (!(m & 0x1))
870 continue;
871 if (l) {
872 strcat(out, " or ");
873 l += 4;
874 }
875 strncat(out, tlb_access[i], sz - l);
876 l += strlen(tlb_access[i]);
877 }
878 if (*out == '\0')
879 strcpy(out, "N/A");
880 if (hit)
881 strncat(out, " hit", sz - l);
882 if (miss)
883 strncat(out, " miss", sz - l);
884
885 return repsep_snprintf(bf, size, "%-*s", width, out);
886}
887
888static int64_t
889sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
890{
891 union perf_mem_data_src data_src_l;
892 union perf_mem_data_src data_src_r;
893
894 if (left->mem_info)
895 data_src_l = left->mem_info->data_src;
896 else
897 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
898
899 if (right->mem_info)
900 data_src_r = right->mem_info->data_src;
901 else
902 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
903
904 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
905}
906
907static const char * const mem_lvl[] = {
908 "N/A",
909 "HIT",
910 "MISS",
911 "L1",
912 "LFB",
913 "L2",
914 "L3",
915 "Local RAM",
916 "Remote RAM (1 hop)",
917 "Remote RAM (2 hops)",
918 "Remote Cache (1 hop)",
919 "Remote Cache (2 hops)",
920 "I/O",
921 "Uncached",
922};
923#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
924
c824c433 925static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
926 size_t size, unsigned int width)
927{
928 char out[64];
929 size_t sz = sizeof(out) - 1; /* -1 for null termination */
930 size_t i, l = 0;
931 u64 m = PERF_MEM_LVL_NA;
932 u64 hit, miss;
933
c824c433
ACM
934 if (he->mem_info)
935 m = he->mem_info->data_src.mem_lvl;
98a3b32c
SE
936
937 out[0] = '\0';
938
939 hit = m & PERF_MEM_LVL_HIT;
940 miss = m & PERF_MEM_LVL_MISS;
941
942 /* already taken care of */
943 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
944
945 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
946 if (!(m & 0x1))
947 continue;
948 if (l) {
949 strcat(out, " or ");
950 l += 4;
951 }
952 strncat(out, mem_lvl[i], sz - l);
953 l += strlen(mem_lvl[i]);
954 }
955 if (*out == '\0')
956 strcpy(out, "N/A");
957 if (hit)
958 strncat(out, " hit", sz - l);
959 if (miss)
960 strncat(out, " miss", sz - l);
961
962 return repsep_snprintf(bf, size, "%-*s", width, out);
963}
964
965static int64_t
966sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
967{
968 union perf_mem_data_src data_src_l;
969 union perf_mem_data_src data_src_r;
970
971 if (left->mem_info)
972 data_src_l = left->mem_info->data_src;
973 else
974 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
975
976 if (right->mem_info)
977 data_src_r = right->mem_info->data_src;
978 else
979 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
980
981 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
982}
983
984static const char * const snoop_access[] = {
985 "N/A",
986 "None",
987 "Miss",
988 "Hit",
989 "HitM",
990};
991#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
992
c824c433 993static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
994 size_t size, unsigned int width)
995{
996 char out[64];
997 size_t sz = sizeof(out) - 1; /* -1 for null termination */
998 size_t i, l = 0;
999 u64 m = PERF_MEM_SNOOP_NA;
1000
1001 out[0] = '\0';
1002
c824c433
ACM
1003 if (he->mem_info)
1004 m = he->mem_info->data_src.mem_snoop;
98a3b32c
SE
1005
1006 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1007 if (!(m & 0x1))
1008 continue;
1009 if (l) {
1010 strcat(out, " or ");
1011 l += 4;
1012 }
1013 strncat(out, snoop_access[i], sz - l);
1014 l += strlen(snoop_access[i]);
1015 }
1016
1017 if (*out == '\0')
1018 strcpy(out, "N/A");
1019
1020 return repsep_snprintf(bf, size, "%-*s", width, out);
1021}
1022
9b32ba71
DZ
1023static inline u64 cl_address(u64 address)
1024{
1025 /* return the cacheline of the address */
1026 return (address & ~(cacheline_size - 1));
1027}
1028
1029static int64_t
1030sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1031{
1032 u64 l, r;
1033 struct map *l_map, *r_map;
1034
1035 if (!left->mem_info) return -1;
1036 if (!right->mem_info) return 1;
1037
1038 /* group event types together */
1039 if (left->cpumode > right->cpumode) return -1;
1040 if (left->cpumode < right->cpumode) return 1;
1041
1042 l_map = left->mem_info->daddr.map;
1043 r_map = right->mem_info->daddr.map;
1044
1045 /* if both are NULL, jump to sort on al_addr instead */
1046 if (!l_map && !r_map)
1047 goto addr;
1048
1049 if (!l_map) return -1;
1050 if (!r_map) return 1;
1051
1052 if (l_map->maj > r_map->maj) return -1;
1053 if (l_map->maj < r_map->maj) return 1;
1054
1055 if (l_map->min > r_map->min) return -1;
1056 if (l_map->min < r_map->min) return 1;
1057
1058 if (l_map->ino > r_map->ino) return -1;
1059 if (l_map->ino < r_map->ino) return 1;
1060
1061 if (l_map->ino_generation > r_map->ino_generation) return -1;
1062 if (l_map->ino_generation < r_map->ino_generation) return 1;
1063
1064 /*
1065 * Addresses with no major/minor numbers are assumed to be
1066 * anonymous in userspace. Sort those on pid then address.
1067 *
1068 * The kernel and non-zero major/minor mapped areas are
1069 * assumed to be unity mapped. Sort those on address.
1070 */
1071
1072 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1073 (!(l_map->flags & MAP_SHARED)) &&
1074 !l_map->maj && !l_map->min && !l_map->ino &&
1075 !l_map->ino_generation) {
1076 /* userspace anonymous */
1077
1078 if (left->thread->pid_ > right->thread->pid_) return -1;
1079 if (left->thread->pid_ < right->thread->pid_) return 1;
1080 }
1081
1082addr:
1083 /* al_addr does all the right addr - start + offset calculations */
1084 l = cl_address(left->mem_info->daddr.al_addr);
1085 r = cl_address(right->mem_info->daddr.al_addr);
1086
1087 if (l > r) return -1;
1088 if (l < r) return 1;
1089
1090 return 0;
1091}
1092
1093static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1094 size_t size, unsigned int width)
1095{
1096
1097 uint64_t addr = 0;
1098 struct map *map = NULL;
1099 struct symbol *sym = NULL;
1100 char level = he->level;
1101
1102 if (he->mem_info) {
1103 addr = cl_address(he->mem_info->daddr.al_addr);
1104 map = he->mem_info->daddr.map;
1105 sym = he->mem_info->daddr.sym;
1106
1107 /* print [s] for shared data mmaps */
1108 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1109 map && (map->type == MAP__VARIABLE) &&
1110 (map->flags & MAP_SHARED) &&
1111 (map->maj || map->min || map->ino ||
1112 map->ino_generation))
1113 level = 's';
1114 else if (!map)
1115 level = 'X';
1116 }
1117 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1118 width);
1119}
1120
b5387528
RAV
1121struct sort_entry sort_mispredict = {
1122 .se_header = "Branch Mispredicted",
1123 .se_cmp = sort__mispredict_cmp,
1124 .se_snprintf = hist_entry__mispredict_snprintf,
1125 .se_width_idx = HISTC_MISPREDICT,
1126};
1127
05484298
AK
1128static u64 he_weight(struct hist_entry *he)
1129{
1130 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1131}
1132
1133static int64_t
1134sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1135{
1136 return he_weight(left) - he_weight(right);
1137}
1138
c824c433 1139static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
05484298
AK
1140 size_t size, unsigned int width)
1141{
c824c433 1142 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
05484298
AK
1143}
1144
1145struct sort_entry sort_local_weight = {
1146 .se_header = "Local Weight",
1147 .se_cmp = sort__local_weight_cmp,
1148 .se_snprintf = hist_entry__local_weight_snprintf,
1149 .se_width_idx = HISTC_LOCAL_WEIGHT,
1150};
1151
1152static int64_t
1153sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1154{
1155 return left->stat.weight - right->stat.weight;
1156}
1157
c824c433 1158static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
05484298
AK
1159 size_t size, unsigned int width)
1160{
c824c433 1161 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
05484298
AK
1162}
1163
1164struct sort_entry sort_global_weight = {
1165 .se_header = "Weight",
1166 .se_cmp = sort__global_weight_cmp,
1167 .se_snprintf = hist_entry__global_weight_snprintf,
1168 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1169};
1170
98a3b32c
SE
1171struct sort_entry sort_mem_daddr_sym = {
1172 .se_header = "Data Symbol",
1173 .se_cmp = sort__daddr_cmp,
1174 .se_snprintf = hist_entry__daddr_snprintf,
1175 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1176};
1177
28e6db20
DZ
1178struct sort_entry sort_mem_iaddr_sym = {
1179 .se_header = "Code Symbol",
1180 .se_cmp = sort__iaddr_cmp,
1181 .se_snprintf = hist_entry__iaddr_snprintf,
1182 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1183};
1184
98a3b32c
SE
1185struct sort_entry sort_mem_daddr_dso = {
1186 .se_header = "Data Object",
1187 .se_cmp = sort__dso_daddr_cmp,
1188 .se_snprintf = hist_entry__dso_daddr_snprintf,
1189 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1190};
1191
1192struct sort_entry sort_mem_locked = {
1193 .se_header = "Locked",
1194 .se_cmp = sort__locked_cmp,
1195 .se_snprintf = hist_entry__locked_snprintf,
1196 .se_width_idx = HISTC_MEM_LOCKED,
1197};
1198
1199struct sort_entry sort_mem_tlb = {
1200 .se_header = "TLB access",
1201 .se_cmp = sort__tlb_cmp,
1202 .se_snprintf = hist_entry__tlb_snprintf,
1203 .se_width_idx = HISTC_MEM_TLB,
1204};
1205
1206struct sort_entry sort_mem_lvl = {
1207 .se_header = "Memory access",
1208 .se_cmp = sort__lvl_cmp,
1209 .se_snprintf = hist_entry__lvl_snprintf,
1210 .se_width_idx = HISTC_MEM_LVL,
1211};
1212
1213struct sort_entry sort_mem_snoop = {
1214 .se_header = "Snoop",
1215 .se_cmp = sort__snoop_cmp,
1216 .se_snprintf = hist_entry__snoop_snprintf,
1217 .se_width_idx = HISTC_MEM_SNOOP,
1218};
1219
9b32ba71
DZ
1220struct sort_entry sort_mem_dcacheline = {
1221 .se_header = "Data Cacheline",
1222 .se_cmp = sort__dcacheline_cmp,
1223 .se_snprintf = hist_entry__dcacheline_snprintf,
1224 .se_width_idx = HISTC_MEM_DCACHELINE,
1225};
1226
f5d05bce
AK
1227static int64_t
1228sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1229{
49f47443
JO
1230 if (!left->branch_info || !right->branch_info)
1231 return cmp_null(left->branch_info, right->branch_info);
1232
f5d05bce
AK
1233 return left->branch_info->flags.abort !=
1234 right->branch_info->flags.abort;
1235}
1236
c824c433 1237static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
f5d05bce
AK
1238 size_t size, unsigned int width)
1239{
49f47443
JO
1240 static const char *out = "N/A";
1241
1242 if (he->branch_info) {
1243 if (he->branch_info->flags.abort)
1244 out = "A";
1245 else
1246 out = ".";
1247 }
f5d05bce 1248
f5d05bce
AK
1249 return repsep_snprintf(bf, size, "%-*s", width, out);
1250}
1251
1252struct sort_entry sort_abort = {
1253 .se_header = "Transaction abort",
1254 .se_cmp = sort__abort_cmp,
1255 .se_snprintf = hist_entry__abort_snprintf,
1256 .se_width_idx = HISTC_ABORT,
1257};
1258
1259static int64_t
1260sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1261{
0199d244
JO
1262 if (!left->branch_info || !right->branch_info)
1263 return cmp_null(left->branch_info, right->branch_info);
1264
f5d05bce
AK
1265 return left->branch_info->flags.in_tx !=
1266 right->branch_info->flags.in_tx;
1267}
1268
c824c433 1269static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
f5d05bce
AK
1270 size_t size, unsigned int width)
1271{
0199d244 1272 static const char *out = "N/A";
f5d05bce 1273
0199d244
JO
1274 if (he->branch_info) {
1275 if (he->branch_info->flags.in_tx)
1276 out = "T";
1277 else
1278 out = ".";
1279 }
f5d05bce
AK
1280
1281 return repsep_snprintf(bf, size, "%-*s", width, out);
1282}
1283
1284struct sort_entry sort_in_tx = {
1285 .se_header = "Branch in transaction",
1286 .se_cmp = sort__in_tx_cmp,
1287 .se_snprintf = hist_entry__in_tx_snprintf,
1288 .se_width_idx = HISTC_IN_TX,
1289};
1290
475eeab9
AK
1291static int64_t
1292sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1293{
1294 return left->transaction - right->transaction;
1295}
1296
1297static inline char *add_str(char *p, const char *str)
1298{
1299 strcpy(p, str);
1300 return p + strlen(str);
1301}
1302
1303static struct txbit {
1304 unsigned flag;
1305 const char *name;
1306 int skip_for_len;
1307} txbits[] = {
1308 { PERF_TXN_ELISION, "EL ", 0 },
1309 { PERF_TXN_TRANSACTION, "TX ", 1 },
1310 { PERF_TXN_SYNC, "SYNC ", 1 },
1311 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1312 { PERF_TXN_RETRY, "RETRY ", 0 },
1313 { PERF_TXN_CONFLICT, "CON ", 0 },
1314 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1315 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1316 { 0, NULL, 0 }
1317};
1318
1319int hist_entry__transaction_len(void)
1320{
1321 int i;
1322 int len = 0;
1323
1324 for (i = 0; txbits[i].name; i++) {
1325 if (!txbits[i].skip_for_len)
1326 len += strlen(txbits[i].name);
1327 }
1328 len += 4; /* :XX<space> */
1329 return len;
1330}
1331
c824c433 1332static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
475eeab9
AK
1333 size_t size, unsigned int width)
1334{
c824c433 1335 u64 t = he->transaction;
475eeab9
AK
1336 char buf[128];
1337 char *p = buf;
1338 int i;
1339
1340 buf[0] = 0;
1341 for (i = 0; txbits[i].name; i++)
1342 if (txbits[i].flag & t)
1343 p = add_str(p, txbits[i].name);
1344 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1345 p = add_str(p, "NEITHER ");
1346 if (t & PERF_TXN_ABORT_MASK) {
1347 sprintf(p, ":%" PRIx64,
1348 (t & PERF_TXN_ABORT_MASK) >>
1349 PERF_TXN_ABORT_SHIFT);
1350 p += strlen(p);
1351 }
1352
1353 return repsep_snprintf(bf, size, "%-*s", width, buf);
1354}
1355
1356struct sort_entry sort_transaction = {
1357 .se_header = "Transaction ",
1358 .se_cmp = sort__transaction_cmp,
1359 .se_snprintf = hist_entry__transaction_snprintf,
1360 .se_width_idx = HISTC_TRANSACTION,
1361};
1362
872a878f
FW
1363struct sort_dimension {
1364 const char *name;
1365 struct sort_entry *entry;
1366 int taken;
1367};
1368
b5387528
RAV
1369#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1370
fc5871ed 1371static struct sort_dimension common_sort_dimensions[] = {
b5387528
RAV
1372 DIM(SORT_PID, "pid", sort_thread),
1373 DIM(SORT_COMM, "comm", sort_comm),
1374 DIM(SORT_DSO, "dso", sort_dso),
b5387528 1375 DIM(SORT_SYM, "symbol", sort_sym),
b5387528
RAV
1376 DIM(SORT_PARENT, "parent", sort_parent),
1377 DIM(SORT_CPU, "cpu", sort_cpu),
2e7ea3ab 1378 DIM(SORT_SOCKET, "socket", sort_socket),
409a8be6 1379 DIM(SORT_SRCLINE, "srcline", sort_srcline),
31191a85 1380 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
f9ea55d0
AK
1381 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1382 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
475eeab9 1383 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
a34bb6a0 1384 DIM(SORT_TRACE, "trace", sort_trace),
872a878f
FW
1385};
1386
fc5871ed
NK
1387#undef DIM
1388
1389#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1390
1391static struct sort_dimension bstack_sort_dimensions[] = {
1392 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1393 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1394 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1395 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1396 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
f5d05bce
AK
1397 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1398 DIM(SORT_ABORT, "abort", sort_abort),
0e332f03 1399 DIM(SORT_CYCLES, "cycles", sort_cycles),
fc5871ed
NK
1400};
1401
1402#undef DIM
1403
afab87b9
NK
1404#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1405
1406static struct sort_dimension memory_sort_dimensions[] = {
afab87b9 1407 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
28e6db20 1408 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
afab87b9
NK
1409 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1410 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1411 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1412 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1413 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
9b32ba71 1414 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
afab87b9
NK
1415};
1416
1417#undef DIM
1418
a2ce067e
NK
1419struct hpp_dimension {
1420 const char *name;
1421 struct perf_hpp_fmt *fmt;
1422 int taken;
1423};
1424
1425#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1426
1427static struct hpp_dimension hpp_sort_dimensions[] = {
1428 DIM(PERF_HPP__OVERHEAD, "overhead"),
1429 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1430 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1431 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1432 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
594dcbf3 1433 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
a2ce067e
NK
1434 DIM(PERF_HPP__SAMPLES, "sample"),
1435 DIM(PERF_HPP__PERIOD, "period"),
1436};
1437
1438#undef DIM
1439
8b536999
NK
1440struct hpp_sort_entry {
1441 struct perf_hpp_fmt hpp;
1442 struct sort_entry *se;
1443};
1444
e0d66c74 1445void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
678a500d
NK
1446{
1447 struct hpp_sort_entry *hse;
1448
1449 if (!perf_hpp__is_sort_entry(fmt))
1450 return;
1451
1452 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1ecd4453 1453 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
678a500d
NK
1454}
1455
8b536999
NK
1456static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1457 struct perf_evsel *evsel)
1458{
1459 struct hpp_sort_entry *hse;
5b591669 1460 size_t len = fmt->user_len;
8b536999
NK
1461
1462 hse = container_of(fmt, struct hpp_sort_entry, hpp);
8b536999 1463
5b591669 1464 if (!len)
4ea062ed 1465 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
5b591669 1466
1ecd4453 1467 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
8b536999
NK
1468}
1469
1470static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1471 struct perf_hpp *hpp __maybe_unused,
1472 struct perf_evsel *evsel)
1473{
1474 struct hpp_sort_entry *hse;
5b591669 1475 size_t len = fmt->user_len;
8b536999
NK
1476
1477 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1478
5b591669 1479 if (!len)
4ea062ed 1480 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
5b591669
NK
1481
1482 return len;
8b536999
NK
1483}
1484
1485static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1486 struct hist_entry *he)
1487{
1488 struct hpp_sort_entry *hse;
5b591669 1489 size_t len = fmt->user_len;
8b536999
NK
1490
1491 hse = container_of(fmt, struct hpp_sort_entry, hpp);
5b591669
NK
1492
1493 if (!len)
1494 len = hists__col_len(he->hists, hse->se->se_width_idx);
8b536999
NK
1495
1496 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1497}
1498
87bbdf76
NK
1499static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1500 struct hist_entry *a, struct hist_entry *b)
1501{
1502 struct hpp_sort_entry *hse;
1503
1504 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1505 return hse->se->se_cmp(a, b);
1506}
1507
1508static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1509 struct hist_entry *a, struct hist_entry *b)
1510{
1511 struct hpp_sort_entry *hse;
1512 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1513
1514 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1515 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1516 return collapse_fn(a, b);
1517}
1518
1519static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1520 struct hist_entry *a, struct hist_entry *b)
1521{
1522 struct hpp_sort_entry *hse;
1523 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1524
1525 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1526 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1527 return sort_fn(a, b);
1528}
1529
97358084
JO
1530bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1531{
1532 return format->header == __sort__hpp_header;
1533}
1534
1535static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1536{
1537 struct hpp_sort_entry *hse_a;
1538 struct hpp_sort_entry *hse_b;
1539
1540 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1541 return false;
1542
1543 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1544 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1545
1546 return hse_a->se == hse_b->se;
1547}
1548
564132f3
JO
1549static void hse_free(struct perf_hpp_fmt *fmt)
1550{
1551 struct hpp_sort_entry *hse;
1552
1553 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1554 free(hse);
1555}
1556
a7d945bc
NK
1557static struct hpp_sort_entry *
1558__sort_dimension__alloc_hpp(struct sort_dimension *sd)
8b536999
NK
1559{
1560 struct hpp_sort_entry *hse;
1561
1562 hse = malloc(sizeof(*hse));
1563 if (hse == NULL) {
1564 pr_err("Memory allocation failed\n");
a7d945bc 1565 return NULL;
8b536999
NK
1566 }
1567
1568 hse->se = sd->entry;
1ecd4453 1569 hse->hpp.name = sd->entry->se_header;
8b536999
NK
1570 hse->hpp.header = __sort__hpp_header;
1571 hse->hpp.width = __sort__hpp_width;
1572 hse->hpp.entry = __sort__hpp_entry;
1573 hse->hpp.color = NULL;
1574
87bbdf76
NK
1575 hse->hpp.cmp = __sort__hpp_cmp;
1576 hse->hpp.collapse = __sort__hpp_collapse;
1577 hse->hpp.sort = __sort__hpp_sort;
97358084 1578 hse->hpp.equal = __sort__hpp_equal;
564132f3 1579 hse->hpp.free = hse_free;
8b536999
NK
1580
1581 INIT_LIST_HEAD(&hse->hpp.list);
1582 INIT_LIST_HEAD(&hse->hpp.sort_list);
f2998422 1583 hse->hpp.elide = false;
e0d66c74 1584 hse->hpp.len = 0;
5b591669 1585 hse->hpp.user_len = 0;
8b536999 1586
a7d945bc
NK
1587 return hse;
1588}
1589
564132f3
JO
1590static void hpp_free(struct perf_hpp_fmt *fmt)
1591{
1592 free(fmt);
1593}
1594
1945c3e7
JO
1595static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
1596{
1597 struct perf_hpp_fmt *fmt;
1598
1599 fmt = memdup(hd->fmt, sizeof(*fmt));
1600 if (fmt) {
1601 INIT_LIST_HEAD(&fmt->list);
1602 INIT_LIST_HEAD(&fmt->sort_list);
564132f3 1603 fmt->free = hpp_free;
1945c3e7
JO
1604 }
1605
1606 return fmt;
1607}
1608
a7d945bc
NK
1609static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1610{
1611 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1612
1613 if (hse == NULL)
1614 return -1;
1615
8b536999
NK
1616 perf_hpp__register_sort_field(&hse->hpp);
1617 return 0;
1618}
1619
07600027
JO
1620static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
1621 struct sort_dimension *sd)
a7d945bc
NK
1622{
1623 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1624
1625 if (hse == NULL)
1626 return -1;
1627
07600027 1628 perf_hpp_list__column_register(list, &hse->hpp);
a7d945bc
NK
1629 return 0;
1630}
1631
c7c2a5e4
NK
1632struct hpp_dynamic_entry {
1633 struct perf_hpp_fmt hpp;
1634 struct perf_evsel *evsel;
1635 struct format_field *field;
1636 unsigned dynamic_len;
053a3989 1637 bool raw_trace;
c7c2a5e4
NK
1638};
1639
1640static int hde_width(struct hpp_dynamic_entry *hde)
1641{
1642 if (!hde->hpp.len) {
1643 int len = hde->dynamic_len;
1644 int namelen = strlen(hde->field->name);
1645 int fieldlen = hde->field->size;
1646
1647 if (namelen > len)
1648 len = namelen;
1649
1650 if (!(hde->field->flags & FIELD_IS_STRING)) {
1651 /* length for print hex numbers */
1652 fieldlen = hde->field->size * 2 + 2;
1653 }
1654 if (fieldlen > len)
1655 len = fieldlen;
1656
1657 hde->hpp.len = len;
1658 }
1659 return hde->hpp.len;
1660}
1661
60517d28
NK
1662static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1663 struct hist_entry *he)
1664{
1665 char *str, *pos;
1666 struct format_field *field = hde->field;
1667 size_t namelen;
1668 bool last = false;
1669
053a3989
NK
1670 if (hde->raw_trace)
1671 return;
1672
60517d28
NK
1673 /* parse pretty print result and update max length */
1674 if (!he->trace_output)
1675 he->trace_output = get_trace_output(he);
1676
1677 namelen = strlen(field->name);
1678 str = he->trace_output;
1679
1680 while (str) {
1681 pos = strchr(str, ' ');
1682 if (pos == NULL) {
1683 last = true;
1684 pos = str + strlen(str);
1685 }
1686
1687 if (!strncmp(str, field->name, namelen)) {
1688 size_t len;
1689
1690 str += namelen + 1;
1691 len = pos - str;
1692
1693 if (len > hde->dynamic_len)
1694 hde->dynamic_len = len;
1695 break;
1696 }
1697
1698 if (last)
1699 str = NULL;
1700 else
1701 str = pos + 1;
1702 }
1703}
1704
c7c2a5e4
NK
1705static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1706 struct perf_evsel *evsel __maybe_unused)
1707{
1708 struct hpp_dynamic_entry *hde;
1709 size_t len = fmt->user_len;
1710
1711 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1712
1713 if (!len)
1714 len = hde_width(hde);
1715
1716 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1717}
1718
1719static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1720 struct perf_hpp *hpp __maybe_unused,
1721 struct perf_evsel *evsel __maybe_unused)
1722{
1723 struct hpp_dynamic_entry *hde;
1724 size_t len = fmt->user_len;
1725
1726 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1727
1728 if (!len)
1729 len = hde_width(hde);
1730
1731 return len;
1732}
1733
361459f1
NK
1734bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1735{
1736 struct hpp_dynamic_entry *hde;
1737
1738 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1739
1740 return hists_to_evsel(hists) == hde->evsel;
1741}
1742
c7c2a5e4
NK
1743static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1744 struct hist_entry *he)
1745{
1746 struct hpp_dynamic_entry *hde;
1747 size_t len = fmt->user_len;
60517d28
NK
1748 char *str, *pos;
1749 struct format_field *field;
1750 size_t namelen;
1751 bool last = false;
c7c2a5e4
NK
1752 int ret;
1753
1754 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1755
1756 if (!len)
1757 len = hde_width(hde);
1758
053a3989
NK
1759 if (hde->raw_trace)
1760 goto raw_field;
60517d28 1761
053a3989 1762 field = hde->field;
60517d28
NK
1763 namelen = strlen(field->name);
1764 str = he->trace_output;
1765
1766 while (str) {
1767 pos = strchr(str, ' ');
1768 if (pos == NULL) {
1769 last = true;
1770 pos = str + strlen(str);
1771 }
1772
1773 if (!strncmp(str, field->name, namelen)) {
1774 str += namelen + 1;
1775 str = strndup(str, pos - str);
1776
1777 if (str == NULL)
1778 return scnprintf(hpp->buf, hpp->size,
1779 "%*.*s", len, len, "ERROR");
1780 break;
1781 }
1782
1783 if (last)
1784 str = NULL;
1785 else
1786 str = pos + 1;
1787 }
1788
1789 if (str == NULL) {
1790 struct trace_seq seq;
053a3989 1791raw_field:
60517d28
NK
1792 trace_seq_init(&seq);
1793 pevent_print_field(&seq, he->raw_data, hde->field);
1794 str = seq.buffer;
1795 }
1796
1797 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1798 free(str);
c7c2a5e4
NK
1799 return ret;
1800}
1801
1802static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1803 struct hist_entry *a, struct hist_entry *b)
1804{
1805 struct hpp_dynamic_entry *hde;
1806 struct format_field *field;
1807 unsigned offset, size;
1808
1809 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1810
c7c2a5e4
NK
1811 field = hde->field;
1812 if (field->flags & FIELD_IS_DYNAMIC) {
1813 unsigned long long dyn;
1814
1815 pevent_read_number_field(field, a->raw_data, &dyn);
1816 offset = dyn & 0xffff;
1817 size = (dyn >> 16) & 0xffff;
1818
1819 /* record max width for output */
1820 if (size > hde->dynamic_len)
1821 hde->dynamic_len = size;
1822 } else {
1823 offset = field->offset;
1824 size = field->size;
60517d28
NK
1825
1826 update_dynamic_len(hde, a);
1827 update_dynamic_len(hde, b);
c7c2a5e4
NK
1828 }
1829
1830 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1831}
1832
361459f1
NK
1833bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1834{
1835 return fmt->cmp == __sort__hde_cmp;
1836}
1837
665aa757
NK
1838static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1839{
1840 struct hpp_dynamic_entry *hde_a;
1841 struct hpp_dynamic_entry *hde_b;
1842
1843 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1844 return false;
1845
1846 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1847 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1848
1849 return hde_a->field == hde_b->field;
1850}
1851
564132f3
JO
1852static void hde_free(struct perf_hpp_fmt *fmt)
1853{
1854 struct hpp_dynamic_entry *hde;
1855
1856 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1857 free(hde);
1858}
1859
c7c2a5e4
NK
1860static struct hpp_dynamic_entry *
1861__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1862{
1863 struct hpp_dynamic_entry *hde;
1864
1865 hde = malloc(sizeof(*hde));
1866 if (hde == NULL) {
1867 pr_debug("Memory allocation failed\n");
1868 return NULL;
1869 }
1870
1871 hde->evsel = evsel;
1872 hde->field = field;
1873 hde->dynamic_len = 0;
1874
1875 hde->hpp.name = field->name;
1876 hde->hpp.header = __sort__hde_header;
1877 hde->hpp.width = __sort__hde_width;
1878 hde->hpp.entry = __sort__hde_entry;
1879 hde->hpp.color = NULL;
1880
1881 hde->hpp.cmp = __sort__hde_cmp;
1882 hde->hpp.collapse = __sort__hde_cmp;
1883 hde->hpp.sort = __sort__hde_cmp;
665aa757 1884 hde->hpp.equal = __sort__hde_equal;
564132f3 1885 hde->hpp.free = hde_free;
c7c2a5e4
NK
1886
1887 INIT_LIST_HEAD(&hde->hpp.list);
1888 INIT_LIST_HEAD(&hde->hpp.sort_list);
1889 hde->hpp.elide = false;
1890 hde->hpp.len = 0;
1891 hde->hpp.user_len = 0;
1892
1893 return hde;
1894}
1895
5d0cff93
NK
1896static int parse_field_name(char *str, char **event, char **field, char **opt)
1897{
1898 char *event_name, *field_name, *opt_name;
1899
1900 event_name = str;
1901 field_name = strchr(str, '.');
1902
1903 if (field_name) {
1904 *field_name++ = '\0';
1905 } else {
1906 event_name = NULL;
1907 field_name = str;
1908 }
1909
1910 opt_name = strchr(field_name, '/');
1911 if (opt_name)
1912 *opt_name++ = '\0';
1913
1914 *event = event_name;
1915 *field = field_name;
1916 *opt = opt_name;
1917
1918 return 0;
1919}
1920
1921/* find match evsel using a given event name. The event name can be:
9735be24
NK
1922 * 1. '%' + event index (e.g. '%1' for first event)
1923 * 2. full event name (e.g. sched:sched_switch)
1924 * 3. partial event name (should not contain ':')
5d0cff93
NK
1925 */
1926static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1927{
1928 struct perf_evsel *evsel = NULL;
1929 struct perf_evsel *pos;
1930 bool full_name;
1931
1932 /* case 1 */
5d0cff93
NK
1933 if (event_name[0] == '%') {
1934 int nr = strtol(event_name+1, NULL, 0);
1935
1936 if (nr > evlist->nr_entries)
1937 return NULL;
1938
1939 evsel = perf_evlist__first(evlist);
1940 while (--nr > 0)
1941 evsel = perf_evsel__next(evsel);
1942
1943 return evsel;
1944 }
1945
1946 full_name = !!strchr(event_name, ':');
1947 evlist__for_each(evlist, pos) {
9735be24 1948 /* case 2 */
5d0cff93
NK
1949 if (full_name && !strcmp(pos->name, event_name))
1950 return pos;
9735be24 1951 /* case 3 */
5d0cff93
NK
1952 if (!full_name && strstr(pos->name, event_name)) {
1953 if (evsel) {
1954 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1955 event_name, evsel->name, pos->name);
1956 return NULL;
1957 }
1958 evsel = pos;
1959 }
1960 }
1961
1962 return evsel;
1963}
1964
3b099bf5
NK
1965static int __dynamic_dimension__add(struct perf_evsel *evsel,
1966 struct format_field *field,
1967 bool raw_trace)
1968{
1969 struct hpp_dynamic_entry *hde;
1970
1971 hde = __alloc_dynamic_entry(evsel, field);
1972 if (hde == NULL)
1973 return -ENOMEM;
1974
1975 hde->raw_trace = raw_trace;
1976
1977 perf_hpp__register_sort_field(&hde->hpp);
1978 return 0;
1979}
1980
2e422fd1
NK
1981static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1982{
1983 int ret;
1984 struct format_field *field;
1985
1986 field = evsel->tp_format->format.fields;
1987 while (field) {
1988 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1989 if (ret < 0)
1990 return ret;
1991
1992 field = field->next;
1993 }
1994 return 0;
1995}
1996
1997static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1998{
1999 int ret;
2000 struct perf_evsel *evsel;
2001
2002 evlist__for_each(evlist, evsel) {
2003 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2004 continue;
2005
2006 ret = add_evsel_fields(evsel, raw_trace);
2007 if (ret < 0)
2008 return ret;
2009 }
2010 return 0;
2011}
2012
9735be24
NK
2013static int add_all_matching_fields(struct perf_evlist *evlist,
2014 char *field_name, bool raw_trace)
2015{
2016 int ret = -ESRCH;
2017 struct perf_evsel *evsel;
2018 struct format_field *field;
2019
2020 evlist__for_each(evlist, evsel) {
2021 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2022 continue;
2023
2024 field = pevent_find_any_field(evsel->tp_format, field_name);
2025 if (field == NULL)
2026 continue;
2027
2028 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2029 if (ret < 0)
2030 break;
2031 }
2032 return ret;
2033}
2034
c7c2a5e4
NK
2035static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2036{
5d0cff93
NK
2037 char *str, *event_name, *field_name, *opt_name;
2038 struct perf_evsel *evsel;
c7c2a5e4 2039 struct format_field *field;
053a3989 2040 bool raw_trace = symbol_conf.raw_trace;
c7c2a5e4
NK
2041 int ret = 0;
2042
2043 if (evlist == NULL)
2044 return -ENOENT;
2045
2046 str = strdup(tok);
2047 if (str == NULL)
2048 return -ENOMEM;
2049
5d0cff93 2050 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
c7c2a5e4
NK
2051 ret = -EINVAL;
2052 goto out;
2053 }
c7c2a5e4 2054
5d0cff93
NK
2055 if (opt_name) {
2056 if (strcmp(opt_name, "raw")) {
2057 pr_debug("unsupported field option %s\n", opt_name);
053a3989
NK
2058 ret = -EINVAL;
2059 goto out;
2060 }
2061 raw_trace = true;
2062 }
2063
2e422fd1
NK
2064 if (!strcmp(field_name, "trace_fields")) {
2065 ret = add_all_dynamic_fields(evlist, raw_trace);
2066 goto out;
2067 }
2068
9735be24
NK
2069 if (event_name == NULL) {
2070 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2071 goto out;
2072 }
2073
5d0cff93 2074 evsel = find_evsel(evlist, event_name);
c7c2a5e4
NK
2075 if (evsel == NULL) {
2076 pr_debug("Cannot find event: %s\n", event_name);
2077 ret = -ENOENT;
2078 goto out;
2079 }
2080
2081 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2082 pr_debug("%s is not a tracepoint event\n", event_name);
2083 ret = -EINVAL;
2084 goto out;
2085 }
2086
3b099bf5 2087 if (!strcmp(field_name, "*")) {
2e422fd1 2088 ret = add_evsel_fields(evsel, raw_trace);
3b099bf5
NK
2089 } else {
2090 field = pevent_find_any_field(evsel->tp_format, field_name);
2091 if (field == NULL) {
2092 pr_debug("Cannot find event field for %s.%s\n",
2093 event_name, field_name);
2094 return -ENOENT;
2095 }
2096
2097 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2098 }
c7c2a5e4
NK
2099
2100out:
2101 free(str);
2102 return ret;
2103}
2104
cfaa154b 2105static int __sort_dimension__add(struct sort_dimension *sd)
2f532d09
NK
2106{
2107 if (sd->taken)
8b536999
NK
2108 return 0;
2109
a7d945bc 2110 if (__sort_dimension__add_hpp_sort(sd) < 0)
8b536999 2111 return -1;
2f532d09
NK
2112
2113 if (sd->entry->se_collapse)
2114 sort__need_collapse = 1;
2115
2f532d09 2116 sd->taken = 1;
8b536999
NK
2117
2118 return 0;
2f532d09
NK
2119}
2120
a2ce067e
NK
2121static int __hpp_dimension__add(struct hpp_dimension *hd)
2122{
1945c3e7 2123 struct perf_hpp_fmt *fmt;
a2ce067e 2124
1945c3e7
JO
2125 if (hd->taken)
2126 return 0;
2127
2128 fmt = __hpp_dimension__alloc_hpp(hd);
2129 if (!fmt)
2130 return -1;
2131
2132 hd->taken = 1;
2133 perf_hpp__register_sort_field(fmt);
a2ce067e
NK
2134 return 0;
2135}
2136
07600027
JO
2137static int __sort_dimension__add_output(struct perf_hpp_list *list,
2138 struct sort_dimension *sd)
a7d945bc
NK
2139{
2140 if (sd->taken)
2141 return 0;
2142
07600027 2143 if (__sort_dimension__add_hpp_output(list, sd) < 0)
a7d945bc
NK
2144 return -1;
2145
2146 sd->taken = 1;
2147 return 0;
2148}
2149
07600027
JO
2150static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2151 struct hpp_dimension *hd)
a7d945bc 2152{
1945c3e7 2153 struct perf_hpp_fmt *fmt;
a7d945bc 2154
1945c3e7
JO
2155 if (hd->taken)
2156 return 0;
2157
2158 fmt = __hpp_dimension__alloc_hpp(hd);
2159 if (!fmt)
2160 return -1;
2161
2162 hd->taken = 1;
07600027 2163 perf_hpp_list__column_register(list, fmt);
a7d945bc
NK
2164 return 0;
2165}
2166
beeaaeb3
JO
2167int hpp_dimension__add_output(unsigned col)
2168{
2169 BUG_ON(col >= PERF_HPP__MAX_INDEX);
07600027 2170 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
beeaaeb3
JO
2171}
2172
40184c46
NK
2173static int sort_dimension__add(const char *tok,
2174 struct perf_evlist *evlist __maybe_unused)
dd68ada2
JK
2175{
2176 unsigned int i;
2177
fc5871ed
NK
2178 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2179 struct sort_dimension *sd = &common_sort_dimensions[i];
dd68ada2 2180
dd68ada2
JK
2181 if (strncasecmp(tok, sd->name, strlen(tok)))
2182 continue;
fc5871ed 2183
dd68ada2
JK
2184 if (sd->entry == &sort_parent) {
2185 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2186 if (ret) {
2187 char err[BUFSIZ];
2188
2189 regerror(ret, &parent_regex, err, sizeof(err));
2aefa4f7
ACM
2190 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2191 return -EINVAL;
dd68ada2
JK
2192 }
2193 sort__has_parent = 1;
930477bd 2194 } else if (sd->entry == &sort_sym) {
1af55640 2195 sort__has_sym = 1;
94ba462d
KL
2196 /*
2197 * perf diff displays the performance difference amongst
2198 * two or more perf.data files. Those files could come
2199 * from different binaries. So we should not compare
2200 * their ips, but the name of symbol.
2201 */
2202 if (sort__mode == SORT_MODE__DIFF)
2203 sd->entry->se_collapse = sort__sym_sort;
2204
68f6d022
NK
2205 } else if (sd->entry == &sort_dso) {
2206 sort__has_dso = 1;
2e7ea3ab
KL
2207 } else if (sd->entry == &sort_socket) {
2208 sort__has_socket = 1;
cfd92dad
NK
2209 } else if (sd->entry == &sort_thread) {
2210 sort__has_thread = 1;
dd68ada2
JK
2211 }
2212
cfaa154b 2213 return __sort_dimension__add(sd);
dd68ada2 2214 }
fc5871ed 2215
a2ce067e
NK
2216 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2217 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2218
2219 if (strncasecmp(tok, hd->name, strlen(tok)))
2220 continue;
2221
2222 return __hpp_dimension__add(hd);
2223 }
2224
fc5871ed
NK
2225 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2226 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2227
2228 if (strncasecmp(tok, sd->name, strlen(tok)))
2229 continue;
2230
55369fc1 2231 if (sort__mode != SORT_MODE__BRANCH)
fc5871ed
NK
2232 return -EINVAL;
2233
2234 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2235 sort__has_sym = 1;
2236
cfaa154b 2237 __sort_dimension__add(sd);
fc5871ed
NK
2238 return 0;
2239 }
2240
afab87b9
NK
2241 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2242 struct sort_dimension *sd = &memory_sort_dimensions[i];
2243
2244 if (strncasecmp(tok, sd->name, strlen(tok)))
2245 continue;
2246
2247 if (sort__mode != SORT_MODE__MEMORY)
2248 return -EINVAL;
2249
2250 if (sd->entry == &sort_mem_daddr_sym)
2251 sort__has_sym = 1;
2252
cfaa154b 2253 __sort_dimension__add(sd);
afab87b9
NK
2254 return 0;
2255 }
2256
c7c2a5e4
NK
2257 if (!add_dynamic_entry(evlist, tok))
2258 return 0;
2259
dd68ada2
JK
2260 return -ESRCH;
2261}
c8829c7a 2262
2fbaa390
JO
2263static int setup_sort_list(char *str, struct perf_evlist *evlist)
2264{
2265 char *tmp, *tok;
2266 int ret = 0;
2267
2268 for (tok = strtok_r(str, ", ", &tmp);
2269 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2270 ret = sort_dimension__add(tok, evlist);
2271 if (ret == -EINVAL) {
2272 error("Invalid --sort key: `%s'", tok);
2273 break;
2274 } else if (ret == -ESRCH) {
2275 error("Unknown --sort key: `%s'", tok);
2276 break;
2277 }
2278 }
2279
2280 return ret;
2281}
2282
d49dadea 2283static const char *get_default_sort_order(struct perf_evlist *evlist)
512ae1bd
NK
2284{
2285 const char *default_sort_orders[] = {
2286 default_sort_order,
2287 default_branch_sort_order,
2288 default_mem_sort_order,
2289 default_top_sort_order,
2290 default_diff_sort_order,
d49dadea 2291 default_tracepoint_sort_order,
512ae1bd 2292 };
d49dadea
NK
2293 bool use_trace = true;
2294 struct perf_evsel *evsel;
512ae1bd
NK
2295
2296 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2297
d49dadea
NK
2298 if (evlist == NULL)
2299 goto out_no_evlist;
2300
2301 evlist__for_each(evlist, evsel) {
2302 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2303 use_trace = false;
2304 break;
2305 }
2306 }
2307
2308 if (use_trace) {
2309 sort__mode = SORT_MODE__TRACEPOINT;
2310 if (symbol_conf.raw_trace)
2311 return "trace_fields";
2312 }
2313out_no_evlist:
512ae1bd
NK
2314 return default_sort_orders[sort__mode];
2315}
2316
d49dadea 2317static int setup_sort_order(struct perf_evlist *evlist)
1a1c0ffb
JO
2318{
2319 char *new_sort_order;
2320
2321 /*
2322 * Append '+'-prefixed sort order to the default sort
2323 * order string.
2324 */
2325 if (!sort_order || is_strict_order(sort_order))
2326 return 0;
2327
2328 if (sort_order[1] == '\0') {
2329 error("Invalid --sort key: `+'");
2330 return -EINVAL;
2331 }
2332
2333 /*
2334 * We allocate new sort_order string, but we never free it,
2335 * because it's checked over the rest of the code.
2336 */
2337 if (asprintf(&new_sort_order, "%s,%s",
d49dadea 2338 get_default_sort_order(evlist), sort_order + 1) < 0) {
1a1c0ffb
JO
2339 error("Not enough memory to set up --sort");
2340 return -ENOMEM;
2341 }
2342
2343 sort_order = new_sort_order;
2344 return 0;
2345}
2346
b97511c5
JO
2347/*
2348 * Adds 'pre,' prefix into 'str' is 'pre' is
2349 * not already part of 'str'.
2350 */
2351static char *prefix_if_not_in(const char *pre, char *str)
2352{
2353 char *n;
2354
2355 if (!str || strstr(str, pre))
2356 return str;
2357
2358 if (asprintf(&n, "%s,%s", pre, str) < 0)
2359 return NULL;
2360
2361 free(str);
2362 return n;
2363}
2364
2365static char *setup_overhead(char *keys)
2366{
2367 keys = prefix_if_not_in("overhead", keys);
2368
2369 if (symbol_conf.cumulate_callchain)
2370 keys = prefix_if_not_in("overhead_children", keys);
2371
2372 return keys;
2373}
2374
40184c46 2375static int __setup_sorting(struct perf_evlist *evlist)
c8829c7a 2376{
2fbaa390 2377 char *str;
1a1c0ffb 2378 const char *sort_keys;
55309985 2379 int ret = 0;
c8829c7a 2380
d49dadea 2381 ret = setup_sort_order(evlist);
1a1c0ffb
JO
2382 if (ret)
2383 return ret;
2384
2385 sort_keys = sort_order;
a7d945bc 2386 if (sort_keys == NULL) {
2f3f9bcf 2387 if (is_strict_order(field_order)) {
a7d945bc
NK
2388 /*
2389 * If user specified field order but no sort order,
2390 * we'll honor it and not add default sort orders.
2391 */
2392 return 0;
2393 }
2394
d49dadea 2395 sort_keys = get_default_sort_order(evlist);
a7d945bc 2396 }
512ae1bd
NK
2397
2398 str = strdup(sort_keys);
5936f54d
NK
2399 if (str == NULL) {
2400 error("Not enough memory to setup sort keys");
2401 return -ENOMEM;
2402 }
2403
b97511c5
JO
2404 /*
2405 * Prepend overhead fields for backward compatibility.
2406 */
2407 if (!is_strict_order(field_order)) {
2408 str = setup_overhead(str);
2409 if (str == NULL) {
2410 error("Not enough memory to setup overhead keys");
2411 return -ENOMEM;
2412 }
2413 }
2414
2fbaa390 2415 ret = setup_sort_list(str, evlist);
c8829c7a
ACM
2416
2417 free(str);
55309985 2418 return ret;
c8829c7a 2419}
c351c281 2420
f2998422 2421void perf_hpp__set_elide(int idx, bool elide)
e67d49a7 2422{
f2998422
JO
2423 struct perf_hpp_fmt *fmt;
2424 struct hpp_sort_entry *hse;
e67d49a7 2425
cf094045 2426 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
f2998422
JO
2427 if (!perf_hpp__is_sort_entry(fmt))
2428 continue;
2429
2430 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2431 if (hse->se->se_width_idx == idx) {
2432 fmt->elide = elide;
2433 break;
2434 }
e67d49a7 2435 }
e67d49a7
NK
2436}
2437
f2998422 2438static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
c351c281
ACM
2439{
2440 if (list && strlist__nr_entries(list) == 1) {
2441 if (fp != NULL)
2442 fprintf(fp, "# %s: %s\n", list_name,
2443 strlist__entry(list, 0)->s);
f2998422
JO
2444 return true;
2445 }
2446 return false;
2447}
2448
2449static bool get_elide(int idx, FILE *output)
2450{
2451 switch (idx) {
2452 case HISTC_SYMBOL:
2453 return __get_elide(symbol_conf.sym_list, "symbol", output);
2454 case HISTC_DSO:
2455 return __get_elide(symbol_conf.dso_list, "dso", output);
2456 case HISTC_COMM:
2457 return __get_elide(symbol_conf.comm_list, "comm", output);
2458 default:
2459 break;
c351c281 2460 }
f2998422
JO
2461
2462 if (sort__mode != SORT_MODE__BRANCH)
2463 return false;
2464
2465 switch (idx) {
2466 case HISTC_SYMBOL_FROM:
2467 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2468 case HISTC_SYMBOL_TO:
2469 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2470 case HISTC_DSO_FROM:
2471 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2472 case HISTC_DSO_TO:
2473 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2474 default:
2475 break;
2476 }
2477
2478 return false;
c351c281 2479}
08e71542
NK
2480
2481void sort__setup_elide(FILE *output)
2482{
cfaa154b
NK
2483 struct perf_hpp_fmt *fmt;
2484 struct hpp_sort_entry *hse;
7524f63b 2485
cf094045 2486 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
f2998422
JO
2487 if (!perf_hpp__is_sort_entry(fmt))
2488 continue;
2489
2490 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2491 fmt->elide = get_elide(hse->se->se_width_idx, output);
08e71542
NK
2492 }
2493
7524f63b
NK
2494 /*
2495 * It makes no sense to elide all of sort entries.
2496 * Just revert them to show up again.
2497 */
cf094045 2498 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
cfaa154b
NK
2499 if (!perf_hpp__is_sort_entry(fmt))
2500 continue;
2501
f2998422 2502 if (!fmt->elide)
7524f63b
NK
2503 return;
2504 }
2505
cf094045 2506 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
cfaa154b
NK
2507 if (!perf_hpp__is_sort_entry(fmt))
2508 continue;
2509
f2998422 2510 fmt->elide = false;
cfaa154b 2511 }
08e71542 2512}
a7d945bc 2513
07600027 2514static int output_field_add(struct perf_hpp_list *list, char *tok)
a7d945bc
NK
2515{
2516 unsigned int i;
2517
2518 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2519 struct sort_dimension *sd = &common_sort_dimensions[i];
2520
2521 if (strncasecmp(tok, sd->name, strlen(tok)))
2522 continue;
2523
07600027 2524 return __sort_dimension__add_output(list, sd);
a7d945bc
NK
2525 }
2526
2527 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2528 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2529
2530 if (strncasecmp(tok, hd->name, strlen(tok)))
2531 continue;
2532
07600027 2533 return __hpp_dimension__add_output(list, hd);
a7d945bc
NK
2534 }
2535
2536 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2537 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2538
2539 if (strncasecmp(tok, sd->name, strlen(tok)))
2540 continue;
2541
07600027 2542 return __sort_dimension__add_output(list, sd);
a7d945bc
NK
2543 }
2544
2545 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2546 struct sort_dimension *sd = &memory_sort_dimensions[i];
2547
2548 if (strncasecmp(tok, sd->name, strlen(tok)))
2549 continue;
2550
07600027 2551 return __sort_dimension__add_output(list, sd);
a7d945bc
NK
2552 }
2553
2554 return -ESRCH;
2555}
2556
07600027 2557static int setup_output_list(struct perf_hpp_list *list, char *str)
6d3375ef
JO
2558{
2559 char *tmp, *tok;
2560 int ret = 0;
2561
2562 for (tok = strtok_r(str, ", ", &tmp);
2563 tok; tok = strtok_r(NULL, ", ", &tmp)) {
07600027 2564 ret = output_field_add(list, tok);
6d3375ef
JO
2565 if (ret == -EINVAL) {
2566 error("Invalid --fields key: `%s'", tok);
2567 break;
2568 } else if (ret == -ESRCH) {
2569 error("Unknown --fields key: `%s'", tok);
2570 break;
2571 }
2572 }
2573
2574 return ret;
2575}
2576
a7d945bc
NK
2577static void reset_dimensions(void)
2578{
2579 unsigned int i;
2580
2581 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2582 common_sort_dimensions[i].taken = 0;
2583
2584 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2585 hpp_sort_dimensions[i].taken = 0;
2586
2587 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2588 bstack_sort_dimensions[i].taken = 0;
2589
2590 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2591 memory_sort_dimensions[i].taken = 0;
2592}
2593
2f3f9bcf
JO
2594bool is_strict_order(const char *order)
2595{
2596 return order && (*order != '+');
2597}
2598
a7d945bc
NK
2599static int __setup_output_field(void)
2600{
6d3375ef 2601 char *str, *strp;
2f3f9bcf 2602 int ret = -EINVAL;
a7d945bc
NK
2603
2604 if (field_order == NULL)
2605 return 0;
2606
2f3f9bcf 2607 strp = str = strdup(field_order);
a7d945bc
NK
2608 if (str == NULL) {
2609 error("Not enough memory to setup output fields");
2610 return -ENOMEM;
2611 }
2612
2f3f9bcf
JO
2613 if (!is_strict_order(field_order))
2614 strp++;
2615
2616 if (!strlen(strp)) {
2617 error("Invalid --fields key: `+'");
2618 goto out;
2619 }
2620
07600027 2621 ret = setup_output_list(&perf_hpp_list, strp);
a7d945bc 2622
2f3f9bcf 2623out:
a7d945bc
NK
2624 free(str);
2625 return ret;
2626}
2627
40184c46 2628int setup_sorting(struct perf_evlist *evlist)
a7d945bc
NK
2629{
2630 int err;
2631
40184c46 2632 err = __setup_sorting(evlist);
a7d945bc
NK
2633 if (err < 0)
2634 return err;
2635
2636 if (parent_pattern != default_parent_pattern) {
40184c46 2637 err = sort_dimension__add("parent", evlist);
a7d945bc
NK
2638 if (err < 0)
2639 return err;
2640 }
2641
2642 reset_dimensions();
2643
2644 /*
2645 * perf diff doesn't use default hpp output fields.
2646 */
2647 if (sort__mode != SORT_MODE__DIFF)
2648 perf_hpp__init();
2649
2650 err = __setup_output_field();
2651 if (err < 0)
2652 return err;
2653
2654 /* copy sort keys to output fields */
43e0a68f 2655 perf_hpp__setup_output_field(&perf_hpp_list);
a7d945bc 2656 /* and then copy output fields to sort keys */
43e0a68f 2657 perf_hpp__append_sort_keys(&perf_hpp_list);
a7d945bc
NK
2658
2659 return 0;
2660}
1c89fe9b
NK
2661
2662void reset_output_field(void)
2663{
2664 sort__need_collapse = 0;
2665 sort__has_parent = 0;
2666 sort__has_sym = 0;
2667 sort__has_dso = 0;
2668
d69b2962
NK
2669 field_order = NULL;
2670 sort_order = NULL;
2671
1c89fe9b 2672 reset_dimensions();
43e0a68f 2673 perf_hpp__reset_output_field(&perf_hpp_list);
1c89fe9b 2674}