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