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