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