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