Merge remote-tracking branches 'regulator/fix/bcm590xx', 'regulator/fix/palmas' and...
[linux-2.6-block.git] / tools / perf / util / sort.c
CommitLineData
9b32ba71 1#include <sys/mman.h>
dd68ada2 2#include "sort.h"
8a6c5b26 3#include "hist.h"
4dfced35 4#include "comm.h"
08e71542 5#include "symbol.h"
8b536999 6#include "evsel.h"
dd68ada2
JK
7
8regex_t parent_regex;
edb7c60e
ACM
9const char default_parent_pattern[] = "^sys_|^do_page_fault";
10const char *parent_pattern = default_parent_pattern;
11const char default_sort_order[] = "comm,dso,symbol";
512ae1bd
NK
12const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
a7d945bc 17const char *field_order;
b21484f1
GP
18regex_t ignore_callees_regex;
19int have_ignore_callees = 0;
af0a6fa4
FW
20int sort__need_collapse = 0;
21int sort__has_parent = 0;
1af55640 22int sort__has_sym = 0;
68f6d022 23int sort__has_dso = 0;
55369fc1 24enum sort_mode sort__mode = SORT_MODE__NORMAL;
a4fb581b 25
dd68ada2 26
a4e3b956 27static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
dd68ada2
JK
28{
29 int n;
30 va_list ap;
31
32 va_start(ap, fmt);
a4e3b956 33 n = vsnprintf(bf, size, fmt, ap);
0ca0c130 34 if (symbol_conf.field_sep && n > 0) {
a4e3b956
ACM
35 char *sep = bf;
36
37 while (1) {
0ca0c130 38 sep = strchr(sep, *symbol_conf.field_sep);
a4e3b956
ACM
39 if (sep == NULL)
40 break;
41 *sep = '.';
dd68ada2 42 }
dd68ada2
JK
43 }
44 va_end(ap);
b832796c
AB
45
46 if (n >= (int)size)
47 return size - 1;
dd68ada2
JK
48 return n;
49}
50
b9c5143a 51static int64_t cmp_null(const void *l, const void *r)
872a878f
FW
52{
53 if (!l && !r)
54 return 0;
55 else if (!l)
56 return -1;
57 else
58 return 1;
59}
60
61/* --sort pid */
62
63static int64_t
64sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
65{
38051234 66 return right->thread->tid - left->thread->tid;
872a878f
FW
67}
68
c824c433 69static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
a4e3b956 70 size_t size, unsigned int width)
dd68ada2 71{
b9c5143a 72 const char *comm = thread__comm_str(he->thread);
fb29a338 73 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
b9c5143a 74 comm ?: "", he->thread->tid);
dd68ada2
JK
75}
76
872a878f
FW
77struct sort_entry sort_thread = {
78 .se_header = "Command: Pid",
79 .se_cmp = sort__thread_cmp,
80 .se_snprintf = hist_entry__thread_snprintf,
81 .se_width_idx = HISTC_THREAD,
82};
83
84/* --sort comm */
85
86static int64_t
87sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
88{
fedd63d3 89 /* Compare the addr that should be unique among comm */
4dfced35 90 return comm__str(right->comm) - comm__str(left->comm);
872a878f
FW
91}
92
93static int64_t
94sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
95{
4dfced35
NK
96 /* Compare the addr that should be unique among comm */
97 return comm__str(right->comm) - comm__str(left->comm);
872a878f
FW
98}
99
202e7a6d
NK
100static int64_t
101sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
102{
103 return strcmp(comm__str(right->comm), comm__str(left->comm));
104}
105
c824c433 106static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
a4e3b956 107 size_t size, unsigned int width)
dd68ada2 108{
4dfced35 109 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
dd68ada2
JK
110}
111
14d1ac74
NK
112struct sort_entry sort_comm = {
113 .se_header = "Command",
114 .se_cmp = sort__comm_cmp,
115 .se_collapse = sort__comm_collapse,
202e7a6d 116 .se_sort = sort__comm_sort,
14d1ac74
NK
117 .se_snprintf = hist_entry__comm_snprintf,
118 .se_width_idx = HISTC_COMM,
119};
120
121/* --sort dso */
122
b5387528
RAV
123static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
124{
125 struct dso *dso_l = map_l ? map_l->dso : NULL;
126 struct dso *dso_r = map_r ? map_r->dso : NULL;
127 const char *dso_name_l, *dso_name_r;
128
129 if (!dso_l || !dso_r)
202e7a6d 130 return cmp_null(dso_r, dso_l);
b5387528
RAV
131
132 if (verbose) {
133 dso_name_l = dso_l->long_name;
134 dso_name_r = dso_r->long_name;
135 } else {
136 dso_name_l = dso_l->short_name;
137 dso_name_r = dso_r->short_name;
138 }
139
140 return strcmp(dso_name_l, dso_name_r);
141}
142
872a878f 143static int64_t
dd68ada2
JK
144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
145{
202e7a6d 146 return _sort__dso_cmp(right->ms.map, left->ms.map);
b5387528 147}
dd68ada2 148
14d1ac74
NK
149static int _hist_entry__dso_snprintf(struct map *map, char *bf,
150 size_t size, unsigned int width)
151{
152 if (map && map->dso) {
153 const char *dso_name = !verbose ? map->dso->short_name :
154 map->dso->long_name;
155 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
156 }
157
158 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
159}
160
c824c433 161static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
14d1ac74
NK
162 size_t size, unsigned int width)
163{
c824c433 164 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
14d1ac74
NK
165}
166
167struct sort_entry sort_dso = {
168 .se_header = "Shared Object",
169 .se_cmp = sort__dso_cmp,
170 .se_snprintf = hist_entry__dso_snprintf,
171 .se_width_idx = HISTC_DSO,
172};
173
174/* --sort symbol */
dd68ada2 175
2037be53
NK
176static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
177{
178 return (int64_t)(right_ip - left_ip);
179}
180
51f27d14 181static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
b5387528 182{
51f27d14
NK
183 u64 ip_l, ip_r;
184
b5387528
RAV
185 if (!sym_l || !sym_r)
186 return cmp_null(sym_l, sym_r);
187
188 if (sym_l == sym_r)
189 return 0;
190
53985a7b
SL
191 ip_l = sym_l->start;
192 ip_r = sym_r->start;
b5387528
RAV
193
194 return (int64_t)(ip_r - ip_l);
195}
196
14d1ac74
NK
197static int64_t
198sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
b5387528 199{
09600e0f
NK
200 int64_t ret;
201
14d1ac74 202 if (!left->ms.sym && !right->ms.sym)
2037be53 203 return _sort__addr_cmp(left->ip, right->ip);
dd68ada2 204
09600e0f
NK
205 /*
206 * comparing symbol address alone is not enough since it's a
207 * relative address within a dso.
208 */
68f6d022
NK
209 if (!sort__has_dso) {
210 ret = sort__dso_cmp(left, right);
211 if (ret != 0)
212 return ret;
213 }
09600e0f 214
51f27d14 215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
b5387528
RAV
216}
217
202e7a6d
NK
218static int64_t
219sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220{
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
223
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
225}
226
b5387528
RAV
227static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
228 u64 ip, char level, char *bf, size_t size,
43355522 229 unsigned int width)
b5387528
RAV
230{
231 size_t ret = 0;
232
233 if (verbose) {
234 char o = map ? dso__symtab_origin(map->dso) : '!';
235 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
ded19d57 236 BITS_PER_LONG / 4 + 2, ip, o);
439d473b 237 }
dd68ada2 238
b5387528 239 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
98a3b32c
SE
240 if (sym && map) {
241 if (map->type == MAP__VARIABLE) {
242 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
243 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
62667746 244 ip - map->unmap_ip(map, sym->start));
98a3b32c
SE
245 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
246 width - ret, "");
247 } else {
248 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
249 width - ret,
250 sym->name);
251 }
252 } else {
b5387528
RAV
253 size_t len = BITS_PER_LONG / 4;
254 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
255 len, ip);
256 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
257 width - ret, "");
258 }
259
260 return ret;
dd68ada2
JK
261}
262
c824c433 263static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
43355522 264 size_t size, unsigned int width)
b5387528 265{
c824c433
ACM
266 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
267 he->level, bf, size, width);
b5387528 268}
dd68ada2 269
872a878f
FW
270struct sort_entry sort_sym = {
271 .se_header = "Symbol",
272 .se_cmp = sort__sym_cmp,
202e7a6d 273 .se_sort = sort__sym_sort,
872a878f
FW
274 .se_snprintf = hist_entry__sym_snprintf,
275 .se_width_idx = HISTC_SYMBOL,
276};
dd68ada2 277
409a8be6
ACM
278/* --sort srcline */
279
280static int64_t
281sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
282{
4adcc430
NK
283 if (!left->srcline) {
284 if (!left->ms.map)
285 left->srcline = SRCLINE_UNKNOWN;
286 else {
287 struct map *map = left->ms.map;
288 left->srcline = get_srcline(map->dso,
289 map__rip_2objdump(map, left->ip));
290 }
291 }
292 if (!right->srcline) {
293 if (!right->ms.map)
294 right->srcline = SRCLINE_UNKNOWN;
295 else {
296 struct map *map = right->ms.map;
297 right->srcline = get_srcline(map->dso,
298 map__rip_2objdump(map, right->ip));
299 }
300 }
202e7a6d 301 return strcmp(right->srcline, left->srcline);
409a8be6
ACM
302}
303
c824c433 304static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
1d037ca1
IT
305 size_t size,
306 unsigned int width __maybe_unused)
409a8be6 307{
c824c433 308 return repsep_snprintf(bf, size, "%s", he->srcline);
409a8be6
ACM
309}
310
311struct sort_entry sort_srcline = {
312 .se_header = "Source:Line",
313 .se_cmp = sort__srcline_cmp,
314 .se_snprintf = hist_entry__srcline_snprintf,
315 .se_width_idx = HISTC_SRCLINE,
316};
317
dd68ada2
JK
318/* --sort parent */
319
872a878f 320static int64_t
dd68ada2
JK
321sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
322{
323 struct symbol *sym_l = left->parent;
324 struct symbol *sym_r = right->parent;
325
326 if (!sym_l || !sym_r)
327 return cmp_null(sym_l, sym_r);
328
202e7a6d 329 return strcmp(sym_r->name, sym_l->name);
dd68ada2
JK
330}
331
c824c433 332static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
a4e3b956 333 size_t size, unsigned int width)
dd68ada2 334{
a4e3b956 335 return repsep_snprintf(bf, size, "%-*s", width,
c824c433 336 he->parent ? he->parent->name : "[other]");
dd68ada2
JK
337}
338
872a878f
FW
339struct sort_entry sort_parent = {
340 .se_header = "Parent symbol",
341 .se_cmp = sort__parent_cmp,
342 .se_snprintf = hist_entry__parent_snprintf,
343 .se_width_idx = HISTC_PARENT,
344};
345
f60f3593
AS
346/* --sort cpu */
347
872a878f 348static int64_t
f60f3593
AS
349sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
350{
351 return right->cpu - left->cpu;
352}
353
c824c433
ACM
354static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
355 size_t size, unsigned int width)
f60f3593 356{
c824c433 357 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
f60f3593
AS
358}
359
872a878f
FW
360struct sort_entry sort_cpu = {
361 .se_header = "CPU",
362 .se_cmp = sort__cpu_cmp,
363 .se_snprintf = hist_entry__cpu_snprintf,
364 .se_width_idx = HISTC_CPU,
365};
366
14d1ac74
NK
367/* sort keys for branch stacks */
368
b5387528
RAV
369static int64_t
370sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
371{
372 return _sort__dso_cmp(left->branch_info->from.map,
373 right->branch_info->from.map);
374}
375
c824c433 376static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
377 size_t size, unsigned int width)
378{
c824c433 379 return _hist_entry__dso_snprintf(he->branch_info->from.map,
b5387528
RAV
380 bf, size, width);
381}
382
b5387528
RAV
383static int64_t
384sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 return _sort__dso_cmp(left->branch_info->to.map,
387 right->branch_info->to.map);
388}
389
c824c433 390static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
391 size_t size, unsigned int width)
392{
c824c433 393 return _hist_entry__dso_snprintf(he->branch_info->to.map,
b5387528
RAV
394 bf, size, width);
395}
396
397static int64_t
398sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
399{
400 struct addr_map_symbol *from_l = &left->branch_info->from;
401 struct addr_map_symbol *from_r = &right->branch_info->from;
402
403 if (!from_l->sym && !from_r->sym)
2037be53 404 return _sort__addr_cmp(from_l->addr, from_r->addr);
b5387528 405
51f27d14 406 return _sort__sym_cmp(from_l->sym, from_r->sym);
b5387528
RAV
407}
408
409static int64_t
410sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
411{
412 struct addr_map_symbol *to_l = &left->branch_info->to;
413 struct addr_map_symbol *to_r = &right->branch_info->to;
414
415 if (!to_l->sym && !to_r->sym)
2037be53 416 return _sort__addr_cmp(to_l->addr, to_r->addr);
b5387528 417
51f27d14 418 return _sort__sym_cmp(to_l->sym, to_r->sym);
b5387528
RAV
419}
420
c824c433 421static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
43355522 422 size_t size, unsigned int width)
b5387528 423{
c824c433 424 struct addr_map_symbol *from = &he->branch_info->from;
b5387528 425 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
c824c433 426 he->level, bf, size, width);
b5387528
RAV
427
428}
429
c824c433 430static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
43355522 431 size_t size, unsigned int width)
b5387528 432{
c824c433 433 struct addr_map_symbol *to = &he->branch_info->to;
b5387528 434 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
c824c433 435 he->level, bf, size, width);
b5387528
RAV
436
437}
438
14d1ac74
NK
439struct sort_entry sort_dso_from = {
440 .se_header = "Source Shared Object",
441 .se_cmp = sort__dso_from_cmp,
442 .se_snprintf = hist_entry__dso_from_snprintf,
443 .se_width_idx = HISTC_DSO_FROM,
444};
445
b5387528
RAV
446struct sort_entry sort_dso_to = {
447 .se_header = "Target Shared Object",
448 .se_cmp = sort__dso_to_cmp,
449 .se_snprintf = hist_entry__dso_to_snprintf,
450 .se_width_idx = HISTC_DSO_TO,
451};
452
453struct sort_entry sort_sym_from = {
454 .se_header = "Source Symbol",
455 .se_cmp = sort__sym_from_cmp,
456 .se_snprintf = hist_entry__sym_from_snprintf,
457 .se_width_idx = HISTC_SYMBOL_FROM,
458};
459
460struct sort_entry sort_sym_to = {
461 .se_header = "Target Symbol",
462 .se_cmp = sort__sym_to_cmp,
463 .se_snprintf = hist_entry__sym_to_snprintf,
464 .se_width_idx = HISTC_SYMBOL_TO,
465};
466
467static int64_t
468sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
469{
470 const unsigned char mp = left->branch_info->flags.mispred !=
471 right->branch_info->flags.mispred;
472 const unsigned char p = left->branch_info->flags.predicted !=
473 right->branch_info->flags.predicted;
474
475 return mp || p;
476}
477
c824c433 478static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
b5387528
RAV
479 size_t size, unsigned int width){
480 static const char *out = "N/A";
481
c824c433 482 if (he->branch_info->flags.predicted)
b5387528 483 out = "N";
c824c433 484 else if (he->branch_info->flags.mispred)
b5387528
RAV
485 out = "Y";
486
487 return repsep_snprintf(bf, size, "%-*s", width, out);
488}
489
98a3b32c
SE
490/* --sort daddr_sym */
491static int64_t
492sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
493{
494 uint64_t l = 0, r = 0;
495
496 if (left->mem_info)
497 l = left->mem_info->daddr.addr;
498 if (right->mem_info)
499 r = right->mem_info->daddr.addr;
500
501 return (int64_t)(r - l);
502}
503
c824c433 504static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
505 size_t size, unsigned int width)
506{
507 uint64_t addr = 0;
508 struct map *map = NULL;
509 struct symbol *sym = NULL;
510
c824c433
ACM
511 if (he->mem_info) {
512 addr = he->mem_info->daddr.addr;
513 map = he->mem_info->daddr.map;
514 sym = he->mem_info->daddr.sym;
98a3b32c 515 }
c824c433 516 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
98a3b32c
SE
517 width);
518}
519
520static int64_t
521sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
522{
523 struct map *map_l = NULL;
524 struct map *map_r = NULL;
525
526 if (left->mem_info)
527 map_l = left->mem_info->daddr.map;
528 if (right->mem_info)
529 map_r = right->mem_info->daddr.map;
530
531 return _sort__dso_cmp(map_l, map_r);
532}
533
c824c433 534static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
535 size_t size, unsigned int width)
536{
537 struct map *map = NULL;
538
c824c433
ACM
539 if (he->mem_info)
540 map = he->mem_info->daddr.map;
98a3b32c
SE
541
542 return _hist_entry__dso_snprintf(map, bf, size, width);
543}
544
545static int64_t
546sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
547{
548 union perf_mem_data_src data_src_l;
549 union perf_mem_data_src data_src_r;
550
551 if (left->mem_info)
552 data_src_l = left->mem_info->data_src;
553 else
554 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
555
556 if (right->mem_info)
557 data_src_r = right->mem_info->data_src;
558 else
559 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
560
561 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
562}
563
c824c433 564static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
565 size_t size, unsigned int width)
566{
567 const char *out;
568 u64 mask = PERF_MEM_LOCK_NA;
569
c824c433
ACM
570 if (he->mem_info)
571 mask = he->mem_info->data_src.mem_lock;
98a3b32c
SE
572
573 if (mask & PERF_MEM_LOCK_NA)
574 out = "N/A";
575 else if (mask & PERF_MEM_LOCK_LOCKED)
576 out = "Yes";
577 else
578 out = "No";
579
580 return repsep_snprintf(bf, size, "%-*s", width, out);
581}
582
583static int64_t
584sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
585{
586 union perf_mem_data_src data_src_l;
587 union perf_mem_data_src data_src_r;
588
589 if (left->mem_info)
590 data_src_l = left->mem_info->data_src;
591 else
592 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
593
594 if (right->mem_info)
595 data_src_r = right->mem_info->data_src;
596 else
597 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
598
599 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
600}
601
602static const char * const tlb_access[] = {
603 "N/A",
604 "HIT",
605 "MISS",
606 "L1",
607 "L2",
608 "Walker",
609 "Fault",
610};
611#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
612
c824c433 613static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
614 size_t size, unsigned int width)
615{
616 char out[64];
617 size_t sz = sizeof(out) - 1; /* -1 for null termination */
618 size_t l = 0, i;
619 u64 m = PERF_MEM_TLB_NA;
620 u64 hit, miss;
621
622 out[0] = '\0';
623
c824c433
ACM
624 if (he->mem_info)
625 m = he->mem_info->data_src.mem_dtlb;
98a3b32c
SE
626
627 hit = m & PERF_MEM_TLB_HIT;
628 miss = m & PERF_MEM_TLB_MISS;
629
630 /* already taken care of */
631 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
632
633 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
634 if (!(m & 0x1))
635 continue;
636 if (l) {
637 strcat(out, " or ");
638 l += 4;
639 }
640 strncat(out, tlb_access[i], sz - l);
641 l += strlen(tlb_access[i]);
642 }
643 if (*out == '\0')
644 strcpy(out, "N/A");
645 if (hit)
646 strncat(out, " hit", sz - l);
647 if (miss)
648 strncat(out, " miss", sz - l);
649
650 return repsep_snprintf(bf, size, "%-*s", width, out);
651}
652
653static int64_t
654sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
655{
656 union perf_mem_data_src data_src_l;
657 union perf_mem_data_src data_src_r;
658
659 if (left->mem_info)
660 data_src_l = left->mem_info->data_src;
661 else
662 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
663
664 if (right->mem_info)
665 data_src_r = right->mem_info->data_src;
666 else
667 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
668
669 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
670}
671
672static const char * const mem_lvl[] = {
673 "N/A",
674 "HIT",
675 "MISS",
676 "L1",
677 "LFB",
678 "L2",
679 "L3",
680 "Local RAM",
681 "Remote RAM (1 hop)",
682 "Remote RAM (2 hops)",
683 "Remote Cache (1 hop)",
684 "Remote Cache (2 hops)",
685 "I/O",
686 "Uncached",
687};
688#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
689
c824c433 690static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
691 size_t size, unsigned int width)
692{
693 char out[64];
694 size_t sz = sizeof(out) - 1; /* -1 for null termination */
695 size_t i, l = 0;
696 u64 m = PERF_MEM_LVL_NA;
697 u64 hit, miss;
698
c824c433
ACM
699 if (he->mem_info)
700 m = he->mem_info->data_src.mem_lvl;
98a3b32c
SE
701
702 out[0] = '\0';
703
704 hit = m & PERF_MEM_LVL_HIT;
705 miss = m & PERF_MEM_LVL_MISS;
706
707 /* already taken care of */
708 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
709
710 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
711 if (!(m & 0x1))
712 continue;
713 if (l) {
714 strcat(out, " or ");
715 l += 4;
716 }
717 strncat(out, mem_lvl[i], sz - l);
718 l += strlen(mem_lvl[i]);
719 }
720 if (*out == '\0')
721 strcpy(out, "N/A");
722 if (hit)
723 strncat(out, " hit", sz - l);
724 if (miss)
725 strncat(out, " miss", sz - l);
726
727 return repsep_snprintf(bf, size, "%-*s", width, out);
728}
729
730static int64_t
731sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
732{
733 union perf_mem_data_src data_src_l;
734 union perf_mem_data_src data_src_r;
735
736 if (left->mem_info)
737 data_src_l = left->mem_info->data_src;
738 else
739 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
740
741 if (right->mem_info)
742 data_src_r = right->mem_info->data_src;
743 else
744 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
745
746 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
747}
748
749static const char * const snoop_access[] = {
750 "N/A",
751 "None",
752 "Miss",
753 "Hit",
754 "HitM",
755};
756#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
757
c824c433 758static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
98a3b32c
SE
759 size_t size, unsigned int width)
760{
761 char out[64];
762 size_t sz = sizeof(out) - 1; /* -1 for null termination */
763 size_t i, l = 0;
764 u64 m = PERF_MEM_SNOOP_NA;
765
766 out[0] = '\0';
767
c824c433
ACM
768 if (he->mem_info)
769 m = he->mem_info->data_src.mem_snoop;
98a3b32c
SE
770
771 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
772 if (!(m & 0x1))
773 continue;
774 if (l) {
775 strcat(out, " or ");
776 l += 4;
777 }
778 strncat(out, snoop_access[i], sz - l);
779 l += strlen(snoop_access[i]);
780 }
781
782 if (*out == '\0')
783 strcpy(out, "N/A");
784
785 return repsep_snprintf(bf, size, "%-*s", width, out);
786}
787
9b32ba71
DZ
788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
b5387528
RAV
886struct sort_entry sort_mispredict = {
887 .se_header = "Branch Mispredicted",
888 .se_cmp = sort__mispredict_cmp,
889 .se_snprintf = hist_entry__mispredict_snprintf,
890 .se_width_idx = HISTC_MISPREDICT,
891};
892
05484298
AK
893static u64 he_weight(struct hist_entry *he)
894{
895 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
896}
897
898static int64_t
899sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
900{
901 return he_weight(left) - he_weight(right);
902}
903
c824c433 904static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
05484298
AK
905 size_t size, unsigned int width)
906{
c824c433 907 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
05484298
AK
908}
909
910struct sort_entry sort_local_weight = {
911 .se_header = "Local Weight",
912 .se_cmp = sort__local_weight_cmp,
913 .se_snprintf = hist_entry__local_weight_snprintf,
914 .se_width_idx = HISTC_LOCAL_WEIGHT,
915};
916
917static int64_t
918sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
919{
920 return left->stat.weight - right->stat.weight;
921}
922
c824c433 923static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
05484298
AK
924 size_t size, unsigned int width)
925{
c824c433 926 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
05484298
AK
927}
928
929struct sort_entry sort_global_weight = {
930 .se_header = "Weight",
931 .se_cmp = sort__global_weight_cmp,
932 .se_snprintf = hist_entry__global_weight_snprintf,
933 .se_width_idx = HISTC_GLOBAL_WEIGHT,
934};
935
98a3b32c
SE
936struct sort_entry sort_mem_daddr_sym = {
937 .se_header = "Data Symbol",
938 .se_cmp = sort__daddr_cmp,
939 .se_snprintf = hist_entry__daddr_snprintf,
940 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
941};
942
943struct sort_entry sort_mem_daddr_dso = {
944 .se_header = "Data Object",
945 .se_cmp = sort__dso_daddr_cmp,
946 .se_snprintf = hist_entry__dso_daddr_snprintf,
947 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
948};
949
950struct sort_entry sort_mem_locked = {
951 .se_header = "Locked",
952 .se_cmp = sort__locked_cmp,
953 .se_snprintf = hist_entry__locked_snprintf,
954 .se_width_idx = HISTC_MEM_LOCKED,
955};
956
957struct sort_entry sort_mem_tlb = {
958 .se_header = "TLB access",
959 .se_cmp = sort__tlb_cmp,
960 .se_snprintf = hist_entry__tlb_snprintf,
961 .se_width_idx = HISTC_MEM_TLB,
962};
963
964struct sort_entry sort_mem_lvl = {
965 .se_header = "Memory access",
966 .se_cmp = sort__lvl_cmp,
967 .se_snprintf = hist_entry__lvl_snprintf,
968 .se_width_idx = HISTC_MEM_LVL,
969};
970
971struct sort_entry sort_mem_snoop = {
972 .se_header = "Snoop",
973 .se_cmp = sort__snoop_cmp,
974 .se_snprintf = hist_entry__snoop_snprintf,
975 .se_width_idx = HISTC_MEM_SNOOP,
976};
977
9b32ba71
DZ
978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
f5d05bce
AK
985static int64_t
986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
987{
988 return left->branch_info->flags.abort !=
989 right->branch_info->flags.abort;
990}
991
c824c433 992static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
f5d05bce
AK
993 size_t size, unsigned int width)
994{
995 static const char *out = ".";
996
c824c433 997 if (he->branch_info->flags.abort)
f5d05bce
AK
998 out = "A";
999 return repsep_snprintf(bf, size, "%-*s", width, out);
1000}
1001
1002struct sort_entry sort_abort = {
1003 .se_header = "Transaction abort",
1004 .se_cmp = sort__abort_cmp,
1005 .se_snprintf = hist_entry__abort_snprintf,
1006 .se_width_idx = HISTC_ABORT,
1007};
1008
1009static int64_t
1010sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1011{
1012 return left->branch_info->flags.in_tx !=
1013 right->branch_info->flags.in_tx;
1014}
1015
c824c433 1016static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
f5d05bce
AK
1017 size_t size, unsigned int width)
1018{
1019 static const char *out = ".";
1020
c824c433 1021 if (he->branch_info->flags.in_tx)
f5d05bce
AK
1022 out = "T";
1023
1024 return repsep_snprintf(bf, size, "%-*s", width, out);
1025}
1026
1027struct sort_entry sort_in_tx = {
1028 .se_header = "Branch in transaction",
1029 .se_cmp = sort__in_tx_cmp,
1030 .se_snprintf = hist_entry__in_tx_snprintf,
1031 .se_width_idx = HISTC_IN_TX,
1032};
1033
475eeab9
AK
1034static int64_t
1035sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1036{
1037 return left->transaction - right->transaction;
1038}
1039
1040static inline char *add_str(char *p, const char *str)
1041{
1042 strcpy(p, str);
1043 return p + strlen(str);
1044}
1045
1046static struct txbit {
1047 unsigned flag;
1048 const char *name;
1049 int skip_for_len;
1050} txbits[] = {
1051 { PERF_TXN_ELISION, "EL ", 0 },
1052 { PERF_TXN_TRANSACTION, "TX ", 1 },
1053 { PERF_TXN_SYNC, "SYNC ", 1 },
1054 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1055 { PERF_TXN_RETRY, "RETRY ", 0 },
1056 { PERF_TXN_CONFLICT, "CON ", 0 },
1057 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1058 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1059 { 0, NULL, 0 }
1060};
1061
1062int hist_entry__transaction_len(void)
1063{
1064 int i;
1065 int len = 0;
1066
1067 for (i = 0; txbits[i].name; i++) {
1068 if (!txbits[i].skip_for_len)
1069 len += strlen(txbits[i].name);
1070 }
1071 len += 4; /* :XX<space> */
1072 return len;
1073}
1074
c824c433 1075static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
475eeab9
AK
1076 size_t size, unsigned int width)
1077{
c824c433 1078 u64 t = he->transaction;
475eeab9
AK
1079 char buf[128];
1080 char *p = buf;
1081 int i;
1082
1083 buf[0] = 0;
1084 for (i = 0; txbits[i].name; i++)
1085 if (txbits[i].flag & t)
1086 p = add_str(p, txbits[i].name);
1087 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1088 p = add_str(p, "NEITHER ");
1089 if (t & PERF_TXN_ABORT_MASK) {
1090 sprintf(p, ":%" PRIx64,
1091 (t & PERF_TXN_ABORT_MASK) >>
1092 PERF_TXN_ABORT_SHIFT);
1093 p += strlen(p);
1094 }
1095
1096 return repsep_snprintf(bf, size, "%-*s", width, buf);
1097}
1098
1099struct sort_entry sort_transaction = {
1100 .se_header = "Transaction ",
1101 .se_cmp = sort__transaction_cmp,
1102 .se_snprintf = hist_entry__transaction_snprintf,
1103 .se_width_idx = HISTC_TRANSACTION,
1104};
1105
872a878f
FW
1106struct sort_dimension {
1107 const char *name;
1108 struct sort_entry *entry;
1109 int taken;
1110};
1111
b5387528
RAV
1112#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1113
fc5871ed 1114static struct sort_dimension common_sort_dimensions[] = {
b5387528
RAV
1115 DIM(SORT_PID, "pid", sort_thread),
1116 DIM(SORT_COMM, "comm", sort_comm),
1117 DIM(SORT_DSO, "dso", sort_dso),
b5387528 1118 DIM(SORT_SYM, "symbol", sort_sym),
b5387528
RAV
1119 DIM(SORT_PARENT, "parent", sort_parent),
1120 DIM(SORT_CPU, "cpu", sort_cpu),
409a8be6 1121 DIM(SORT_SRCLINE, "srcline", sort_srcline),
f9ea55d0
AK
1122 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1123 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
475eeab9 1124 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
872a878f
FW
1125};
1126
fc5871ed
NK
1127#undef DIM
1128
1129#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1130
1131static struct sort_dimension bstack_sort_dimensions[] = {
1132 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1133 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1134 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1135 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1136 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
f5d05bce
AK
1137 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1138 DIM(SORT_ABORT, "abort", sort_abort),
fc5871ed
NK
1139};
1140
1141#undef DIM
1142
afab87b9
NK
1143#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1144
1145static struct sort_dimension memory_sort_dimensions[] = {
afab87b9
NK
1146 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1147 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1148 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
9b32ba71 1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
afab87b9
NK
1153};
1154
1155#undef DIM
1156
a2ce067e
NK
1157struct hpp_dimension {
1158 const char *name;
1159 struct perf_hpp_fmt *fmt;
1160 int taken;
1161};
1162
1163#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1164
1165static struct hpp_dimension hpp_sort_dimensions[] = {
1166 DIM(PERF_HPP__OVERHEAD, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
594dcbf3 1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
a2ce067e
NK
1172 DIM(PERF_HPP__SAMPLES, "sample"),
1173 DIM(PERF_HPP__PERIOD, "period"),
1174};
1175
1176#undef DIM
1177
8b536999
NK
1178struct hpp_sort_entry {
1179 struct perf_hpp_fmt hpp;
1180 struct sort_entry *se;
1181};
1182
a7d945bc
NK
1183bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1184{
1185 struct hpp_sort_entry *hse_a;
1186 struct hpp_sort_entry *hse_b;
1187
1188 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1189 return false;
1190
1191 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1192 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1193
1194 return hse_a->se == hse_b->se;
1195}
1196
678a500d
NK
1197void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1198{
1199 struct hpp_sort_entry *hse;
1200
1201 if (!perf_hpp__is_sort_entry(fmt))
1202 return;
1203
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx,
1206 strlen(hse->se->se_header));
1207}
1208
8b536999
NK
1209static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel)
1211{
1212 struct hpp_sort_entry *hse;
1213 size_t len;
1214
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1219}
1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1222 struct perf_hpp *hpp __maybe_unused,
1223 struct perf_evsel *evsel)
1224{
1225 struct hpp_sort_entry *hse;
1226
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1228
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1230}
1231
1232static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he)
1234{
1235 struct hpp_sort_entry *hse;
1236 size_t len;
1237
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx);
1240
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1242}
1243
a7d945bc
NK
1244static struct hpp_sort_entry *
1245__sort_dimension__alloc_hpp(struct sort_dimension *sd)
8b536999
NK
1246{
1247 struct hpp_sort_entry *hse;
1248
1249 hse = malloc(sizeof(*hse));
1250 if (hse == NULL) {
1251 pr_err("Memory allocation failed\n");
a7d945bc 1252 return NULL;
8b536999
NK
1253 }
1254
1255 hse->se = sd->entry;
1256 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry;
1259 hse->hpp.color = NULL;
1260
1261 hse->hpp.cmp = sd->entry->se_cmp;
1262 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
202e7a6d 1263 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
8b536999
NK
1264
1265 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
f2998422 1267 hse->hpp.elide = false;
8b536999 1268
a7d945bc
NK
1269 return hse;
1270}
1271
1272bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1273{
1274 return format->header == __sort__hpp_header;
1275}
1276
1277static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1278{
1279 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1280
1281 if (hse == NULL)
1282 return -1;
1283
8b536999
NK
1284 perf_hpp__register_sort_field(&hse->hpp);
1285 return 0;
1286}
1287
a7d945bc
NK
1288static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1289{
1290 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1291
1292 if (hse == NULL)
1293 return -1;
1294
1295 perf_hpp__column_register(&hse->hpp);
1296 return 0;
1297}
1298
cfaa154b 1299static int __sort_dimension__add(struct sort_dimension *sd)
2f532d09
NK
1300{
1301 if (sd->taken)
8b536999
NK
1302 return 0;
1303
a7d945bc 1304 if (__sort_dimension__add_hpp_sort(sd) < 0)
8b536999 1305 return -1;
2f532d09
NK
1306
1307 if (sd->entry->se_collapse)
1308 sort__need_collapse = 1;
1309
2f532d09 1310 sd->taken = 1;
8b536999
NK
1311
1312 return 0;
2f532d09
NK
1313}
1314
a2ce067e
NK
1315static int __hpp_dimension__add(struct hpp_dimension *hd)
1316{
1317 if (!hd->taken) {
1318 hd->taken = 1;
1319
1320 perf_hpp__register_sort_field(hd->fmt);
1321 }
1322 return 0;
1323}
1324
a7d945bc
NK
1325static int __sort_dimension__add_output(struct sort_dimension *sd)
1326{
1327 if (sd->taken)
1328 return 0;
1329
1330 if (__sort_dimension__add_hpp_output(sd) < 0)
1331 return -1;
1332
1333 sd->taken = 1;
1334 return 0;
1335}
1336
1337static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1338{
1339 if (!hd->taken) {
1340 hd->taken = 1;
1341
1342 perf_hpp__column_register(hd->fmt);
1343 }
1344 return 0;
1345}
1346
dd68ada2
JK
1347int sort_dimension__add(const char *tok)
1348{
1349 unsigned int i;
1350
fc5871ed
NK
1351 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1352 struct sort_dimension *sd = &common_sort_dimensions[i];
dd68ada2 1353
dd68ada2
JK
1354 if (strncasecmp(tok, sd->name, strlen(tok)))
1355 continue;
fc5871ed 1356
dd68ada2
JK
1357 if (sd->entry == &sort_parent) {
1358 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1359 if (ret) {
1360 char err[BUFSIZ];
1361
1362 regerror(ret, &parent_regex, err, sizeof(err));
2aefa4f7
ACM
1363 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1364 return -EINVAL;
dd68ada2
JK
1365 }
1366 sort__has_parent = 1;
930477bd 1367 } else if (sd->entry == &sort_sym) {
1af55640 1368 sort__has_sym = 1;
68f6d022
NK
1369 } else if (sd->entry == &sort_dso) {
1370 sort__has_dso = 1;
dd68ada2
JK
1371 }
1372
cfaa154b 1373 return __sort_dimension__add(sd);
dd68ada2 1374 }
fc5871ed 1375
a2ce067e
NK
1376 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1377 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1378
1379 if (strncasecmp(tok, hd->name, strlen(tok)))
1380 continue;
1381
1382 return __hpp_dimension__add(hd);
1383 }
1384
fc5871ed
NK
1385 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1386 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1387
1388 if (strncasecmp(tok, sd->name, strlen(tok)))
1389 continue;
1390
55369fc1 1391 if (sort__mode != SORT_MODE__BRANCH)
fc5871ed
NK
1392 return -EINVAL;
1393
1394 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1395 sort__has_sym = 1;
1396
cfaa154b 1397 __sort_dimension__add(sd);
fc5871ed
NK
1398 return 0;
1399 }
1400
afab87b9
NK
1401 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1402 struct sort_dimension *sd = &memory_sort_dimensions[i];
1403
1404 if (strncasecmp(tok, sd->name, strlen(tok)))
1405 continue;
1406
1407 if (sort__mode != SORT_MODE__MEMORY)
1408 return -EINVAL;
1409
1410 if (sd->entry == &sort_mem_daddr_sym)
1411 sort__has_sym = 1;
1412
cfaa154b 1413 __sort_dimension__add(sd);
afab87b9
NK
1414 return 0;
1415 }
1416
dd68ada2
JK
1417 return -ESRCH;
1418}
c8829c7a 1419
512ae1bd
NK
1420static const char *get_default_sort_order(void)
1421{
1422 const char *default_sort_orders[] = {
1423 default_sort_order,
1424 default_branch_sort_order,
1425 default_mem_sort_order,
1426 default_top_sort_order,
1427 default_diff_sort_order,
1428 };
1429
1430 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1431
1432 return default_sort_orders[sort__mode];
1433}
1434
a7d945bc 1435static int __setup_sorting(void)
c8829c7a 1436{
512ae1bd
NK
1437 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order;
55309985 1439 int ret = 0;
c8829c7a 1440
a7d945bc
NK
1441 if (sort_keys == NULL) {
1442 if (field_order) {
1443 /*
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1446 */
1447 return 0;
1448 }
1449
512ae1bd 1450 sort_keys = get_default_sort_order();
a7d945bc 1451 }
512ae1bd
NK
1452
1453 str = strdup(sort_keys);
5936f54d
NK
1454 if (str == NULL) {
1455 error("Not enough memory to setup sort keys");
1456 return -ENOMEM;
1457 }
1458
c8829c7a
ACM
1459 for (tok = strtok_r(str, ", ", &tmp);
1460 tok; tok = strtok_r(NULL, ", ", &tmp)) {
55309985 1461 ret = sort_dimension__add(tok);
fc5871ed
NK
1462 if (ret == -EINVAL) {
1463 error("Invalid --sort key: `%s'", tok);
55309985 1464 break;
fc5871ed 1465 } else if (ret == -ESRCH) {
c8829c7a 1466 error("Unknown --sort key: `%s'", tok);
55309985 1467 break;
c8829c7a
ACM
1468 }
1469 }
1470
1471 free(str);
55309985 1472 return ret;
c8829c7a 1473}
c351c281 1474
f2998422 1475void perf_hpp__set_elide(int idx, bool elide)
e67d49a7 1476{
f2998422
JO
1477 struct perf_hpp_fmt *fmt;
1478 struct hpp_sort_entry *hse;
e67d49a7 1479
f2998422
JO
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1483
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
e67d49a7 1489 }
e67d49a7
NK
1490}
1491
f2998422 1492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
c351c281
ACM
1493{
1494 if (list && strlist__nr_entries(list) == 1) {
1495 if (fp != NULL)
1496 fprintf(fp, "# %s: %s\n", list_name,
1497 strlist__entry(list, 0)->s);
f2998422
JO
1498 return true;
1499 }
1500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
c351c281 1514 }
f2998422
JO
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
c351c281 1533}
08e71542
NK
1534
1535void sort__setup_elide(FILE *output)
1536{
cfaa154b
NK
1537 struct perf_hpp_fmt *fmt;
1538 struct hpp_sort_entry *hse;
7524f63b 1539
f2998422
JO
1540 perf_hpp__for_each_format(fmt) {
1541 if (!perf_hpp__is_sort_entry(fmt))
1542 continue;
1543
1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
08e71542
NK
1546 }
1547
7524f63b
NK
1548 /*
1549 * It makes no sense to elide all of sort entries.
1550 * Just revert them to show up again.
1551 */
cfaa154b
NK
1552 perf_hpp__for_each_format(fmt) {
1553 if (!perf_hpp__is_sort_entry(fmt))
1554 continue;
1555
f2998422 1556 if (!fmt->elide)
7524f63b
NK
1557 return;
1558 }
1559
cfaa154b
NK
1560 perf_hpp__for_each_format(fmt) {
1561 if (!perf_hpp__is_sort_entry(fmt))
1562 continue;
1563
f2998422 1564 fmt->elide = false;
cfaa154b 1565 }
08e71542 1566}
a7d945bc
NK
1567
1568static int output_field_add(char *tok)
1569{
1570 unsigned int i;
1571
1572 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1573 struct sort_dimension *sd = &common_sort_dimensions[i];
1574
1575 if (strncasecmp(tok, sd->name, strlen(tok)))
1576 continue;
1577
1578 return __sort_dimension__add_output(sd);
1579 }
1580
1581 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1582 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1583
1584 if (strncasecmp(tok, hd->name, strlen(tok)))
1585 continue;
1586
1587 return __hpp_dimension__add_output(hd);
1588 }
1589
1590 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1591 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1592
1593 if (strncasecmp(tok, sd->name, strlen(tok)))
1594 continue;
1595
1596 return __sort_dimension__add_output(sd);
1597 }
1598
1599 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1600 struct sort_dimension *sd = &memory_sort_dimensions[i];
1601
1602 if (strncasecmp(tok, sd->name, strlen(tok)))
1603 continue;
1604
1605 return __sort_dimension__add_output(sd);
1606 }
1607
1608 return -ESRCH;
1609}
1610
1611static void reset_dimensions(void)
1612{
1613 unsigned int i;
1614
1615 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1616 common_sort_dimensions[i].taken = 0;
1617
1618 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1619 hpp_sort_dimensions[i].taken = 0;
1620
1621 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1622 bstack_sort_dimensions[i].taken = 0;
1623
1624 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1625 memory_sort_dimensions[i].taken = 0;
1626}
1627
1628static int __setup_output_field(void)
1629{
1630 char *tmp, *tok, *str;
1631 int ret = 0;
1632
1633 if (field_order == NULL)
1634 return 0;
1635
1636 reset_dimensions();
1637
1638 str = strdup(field_order);
1639 if (str == NULL) {
1640 error("Not enough memory to setup output fields");
1641 return -ENOMEM;
1642 }
1643
1644 for (tok = strtok_r(str, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok);
1647 if (ret == -EINVAL) {
1648 error("Invalid --fields key: `%s'", tok);
1649 break;
1650 } else if (ret == -ESRCH) {
1651 error("Unknown --fields key: `%s'", tok);
1652 break;
1653 }
1654 }
1655
1656 free(str);
1657 return ret;
1658}
1659
1660int setup_sorting(void)
1661{
1662 int err;
1663
1664 err = __setup_sorting();
1665 if (err < 0)
1666 return err;
1667
1668 if (parent_pattern != default_parent_pattern) {
1669 err = sort_dimension__add("parent");
1670 if (err < 0)
1671 return err;
1672 }
1673
1674 reset_dimensions();
1675
1676 /*
1677 * perf diff doesn't use default hpp output fields.
1678 */
1679 if (sort__mode != SORT_MODE__DIFF)
1680 perf_hpp__init();
1681
1682 err = __setup_output_field();
1683 if (err < 0)
1684 return err;
1685
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1690
1691 return 0;
1692}
1c89fe9b
NK
1693
1694void reset_output_field(void)
1695{
1696 sort__need_collapse = 0;
1697 sort__has_parent = 0;
1698 sort__has_sym = 0;
1699 sort__has_dso = 0;
1700
d69b2962
NK
1701 field_order = NULL;
1702 sort_order = NULL;
1703
1c89fe9b
NK
1704 reset_dimensions();
1705 perf_hpp__reset_output_field();
1706}