blob: 22d28c7e0b0197090e5364b39724247bc82a458e [file] [log] [blame]
Don Zickus9b32ba72014-06-01 15:38:29 +02001#include <sys/mman.h>
John Kacurdd68ada2009-09-24 18:02:49 +02002#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03003#include "hist.h"
Namhyung Kim4dfced32013-09-13 16:28:57 +09004#include "comm.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09005#include "symbol.h"
Namhyung Kim8b536992014-03-03 11:46:55 +09006#include "evsel.h"
Namhyung Kim40184c42015-12-23 02:07:01 +09007#include "evlist.h"
8#include <traceevent/event-parse.h>
John Kacurdd68ada2009-09-24 18:02:49 +02009
10regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -030011const char default_parent_pattern[] = "^sys_|^do_page_fault";
12const char *parent_pattern = default_parent_pattern;
13const char default_sort_order[] = "comm,dso,symbol";
Andi Kleen40997d62015-07-18 08:24:53 -070014const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090015const 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;
Namhyung Kima7d945b2014-03-04 10:46:34 +090019const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080020regex_t ignore_callees_regex;
21int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020022int sort__need_collapse = 0;
23int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090024int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090025int sort__has_dso = 0;
Kan Liang2e7ea3a2015-09-04 10:45:43 -040026int sort__has_socket = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090027enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020028
John Kacurdd68ada2009-09-24 18:02:49 +020029
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030030static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020031{
32 int n;
33 va_list ap;
34
35 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030036 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020037 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030038 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020039
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030040 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020041 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030042 if (sep == NULL)
43 break;
44 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020045 }
John Kacurdd68ada2009-09-24 18:02:49 +020046 }
47 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110048
49 if (n >= (int)size)
50 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020051 return n;
52}
53
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020054static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020055{
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{
Adrian Hunter38051232013-07-04 16:20:31 +030069 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020070}
71
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030072static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030073 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020074{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020075 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090076
77 width = max(7U, width) - 6;
78 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
79 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020080}
81
Frederic Weisbecker872a8782011-06-29 03:14:52 +020082struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090083 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020084 .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{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020094 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020095 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +020096}
97
98static int64_t
99sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
100{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900101 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200102 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200103}
104
Namhyung Kim202e7a62014-03-04 11:01:41 +0900105static 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300111static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300112 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200113{
Namhyung Kim5b591662014-07-31 14:47:38 +0900114 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200115}
116
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900117struct sort_entry sort_comm = {
118 .se_header = "Command",
119 .se_cmp = sort__comm_cmp,
120 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900121 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900122 .se_snprintf = hist_entry__comm_snprintf,
123 .se_width_idx = HISTC_COMM,
124};
125
126/* --sort dso */
127
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100128static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200129{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100130 struct dso *dso_l = map_l ? map_l->dso : NULL;
131 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300132 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200133
134 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900135 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200136
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300137 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);
John Kacurdd68ada2009-09-24 18:02:49 +0200146}
147
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100148static int64_t
149sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200150{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900151 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100152}
153
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100154static 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;
Namhyung Kim5b591662014-07-31 14:47:38 +0900160 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300161 }
John Kacurdd68ada2009-09-24 18:02:49 +0200162
Namhyung Kim5b591662014-07-31 14:47:38 +0900163 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200164}
165
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300166static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100167 size_t size, unsigned int width)
168{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300169 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100170}
171
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900172struct 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 */
180
Namhyung Kim2037be52013-12-18 14:21:09 +0900181static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
182{
183 return (int64_t)(right_ip - left_ip);
184}
185
Namhyung Kim51f27d12013-02-06 14:57:15 +0900186static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187{
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
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700194 if (sym_l->start != sym_r->start)
195 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900196
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700197 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900198}
199
200static int64_t
201sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
202{
Namhyung Kim09600e02013-10-15 11:01:56 +0900203 int64_t ret;
204
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900205 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900206 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900207
Namhyung Kim09600e02013-10-15 11:01:56 +0900208 /*
209 * comparing symbol address alone is not enough since it's a
210 * relative address within a dso.
211 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900212 if (!sort__has_dso) {
213 ret = sort__dso_cmp(left, right);
214 if (ret != 0)
215 return ret;
216 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900217
Namhyung Kim51f27d12013-02-06 14:57:15 +0900218 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900219}
220
Namhyung Kim202e7a62014-03-04 11:01:41 +0900221static 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
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100230static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
231 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900232 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100233{
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 ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900239 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100240 }
241
242 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100243 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",
Namhyung Kim62667742013-01-24 16:10:42 +0100247 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100248 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 {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100256 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
Namhyung Kim5b591662014-07-31 14:47:38 +0900263 if (ret > width)
264 bf[width] = '\0';
265
266 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100267}
268
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300269static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900270 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100271{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300272 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
273 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100274}
John Kacurdd68ada2009-09-24 18:02:49 +0200275
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200276struct sort_entry sort_sym = {
277 .se_header = "Symbol",
278 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900279 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200280 .se_snprintf = hist_entry__sym_snprintf,
281 .se_width_idx = HISTC_SYMBOL,
282};
John Kacurdd68ada2009-09-24 18:02:49 +0200283
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300284/* --sort srcline */
285
286static int64_t
287sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
288{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900289 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,
Andi Kleen85c116a2014-11-12 18:05:27 -0800295 map__rip_2objdump(map, left->ip),
296 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900297 }
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,
Andi Kleen85c116a2014-11-12 18:05:27 -0800305 map__rip_2objdump(map, right->ip),
306 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900307 }
308 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900309 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300310}
311
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300312static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900313 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300314{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300315 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300316}
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
Andi Kleen31191a82015-08-07 15:54:24 -0700325/* --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
Andi Kleen2f84b422015-09-01 11:47:19 -0700334 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
335 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700336 if (!strcmp(sf, SRCLINE_UNKNOWN))
337 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700338 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
John Kacurdd68ada2009-09-24 18:02:49 +0200378/* --sort parent */
379
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200380static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200381sort__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
Namhyung Kim202e7a62014-03-04 11:01:41 +0900389 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200390}
391
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300392static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300393 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200394{
Namhyung Kim5b591662014-07-31 14:47:38 +0900395 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300396 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200397}
398
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200399struct 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
Arun Sharmaf60f3592010-06-04 11:27:10 -0300406/* --sort cpu */
407
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200408static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300409sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
410{
411 return right->cpu - left->cpu;
412}
413
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300414static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
415 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300416{
Namhyung Kim5b591662014-07-31 14:47:38 +0900417 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300418}
419
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200420struct 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
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400427/* --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
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900448/* sort keys for branch stacks */
449
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450static int64_t
451sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
452{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200453 if (!left->branch_info || !right->branch_info)
454 return cmp_null(left->branch_info, right->branch_info);
455
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100456 return _sort__dso_cmp(left->branch_info->from.map,
457 right->branch_info->from.map);
458}
459
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300460static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100461 size_t size, unsigned int width)
462{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200463 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");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100468}
469
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100470static int64_t
471sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
472{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200473 if (!left->branch_info || !right->branch_info)
474 return cmp_null(left->branch_info, right->branch_info);
475
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100476 return _sort__dso_cmp(left->branch_info->to.map,
477 right->branch_info->to.map);
478}
479
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300480static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100481 size_t size, unsigned int width)
482{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200483 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");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100488}
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
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200496 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
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100502 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900503 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100504
Namhyung Kim51f27d12013-02-06 14:57:15 +0900505 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100506}
507
508static int64_t
509sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
510{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200511 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;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100518
519 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900520 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100521
Namhyung Kim51f27d12013-02-06 14:57:15 +0900522 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100523}
524
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300525static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900526 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100527{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200528 if (he->branch_info) {
529 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100530
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200531 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");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100536}
537
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300538static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900539 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100540{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200541 if (he->branch_info) {
542 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100543
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200544 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
545 he->level, bf, size, width);
546 }
547
548 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100549}
550
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900551struct 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
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100558struct 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{
Jiri Olsa428560e2014-10-16 16:07:03 +0200582 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100583
Jiri Olsa428560e2014-10-16 16:07:03 +0200584 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;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100589 return mp || p;
590}
591
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300592static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100593 size_t size, unsigned int width){
594 static const char *out = "N/A";
595
Jiri Olsa428560e2014-10-16 16:07:03 +0200596 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 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100602
Namhyung Kim5b591662014-07-31 14:47:38 +0900603 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100604}
605
Andi Kleen0e332f02015-07-18 08:24:46 -0700606static 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
Stephane Eranian98a3b322013-01-24 16:10:35 +0100629/* --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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300643static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100644 size_t size, unsigned int width)
645{
646 uint64_t addr = 0;
647 struct map *map = NULL;
648 struct symbol *sym = NULL;
649
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300650 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;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100654 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300655 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100656 width);
657}
658
659static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200660sort__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
688static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100689sort__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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300702static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100703 size_t size, unsigned int width)
704{
705 struct map *map = NULL;
706
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300707 if (he->mem_info)
708 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100709
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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300732static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100733 size_t size, unsigned int width)
734{
735 const char *out;
736 u64 mask = PERF_MEM_LOCK_NA;
737
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300738 if (he->mem_info)
739 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100740
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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300781static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100782 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300792 if (he->mem_info)
793 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100794
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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300858static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100859 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300867 if (he->mem_info)
868 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100869
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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300926static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100927 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300936 if (he->mem_info)
937 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100938
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
Don Zickus9b32ba72014-06-01 15:38:29 +0200956static 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
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001054struct 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
Andi Kleen05484292013-01-24 16:10:29 +01001061static 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001072static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001073 size_t size, unsigned int width)
1074{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001075 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001076}
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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001091static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001092 size_t size, unsigned int width)
1093{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001094 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001095}
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
Stephane Eranian98a3b322013-01-24 16:10:35 +01001104struct 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
Don Zickus28e6db22015-10-05 20:06:07 +02001111struct 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
Stephane Eranian98a3b322013-01-24 16:10:35 +01001118struct 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
Don Zickus9b32ba72014-06-01 15:38:29 +02001153struct 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
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001160static int64_t
1161sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1162{
Jiri Olsa49f47442014-10-16 16:07:01 +02001163 if (!left->branch_info || !right->branch_info)
1164 return cmp_null(left->branch_info, right->branch_info);
1165
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001166 return left->branch_info->flags.abort !=
1167 right->branch_info->flags.abort;
1168}
1169
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001170static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001171 size_t size, unsigned int width)
1172{
Jiri Olsa49f47442014-10-16 16:07:01 +02001173 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001174
Jiri Olsa49f47442014-10-16 16:07:01 +02001175 if (he->branch_info) {
1176 if (he->branch_info->flags.abort)
1177 out = "A";
1178 else
1179 out = ".";
1180 }
1181
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001182 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{
Jiri Olsa0199d242014-10-16 16:07:02 +02001195 if (!left->branch_info || !right->branch_info)
1196 return cmp_null(left->branch_info, right->branch_info);
1197
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001198 return left->branch_info->flags.in_tx !=
1199 right->branch_info->flags.in_tx;
1200}
1201
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001202static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001203 size_t size, unsigned int width)
1204{
Jiri Olsa0199d242014-10-16 16:07:02 +02001205 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001206
Jiri Olsa0199d242014-10-16 16:07:02 +02001207 if (he->branch_info) {
1208 if (he->branch_info->flags.in_tx)
1209 out = "T";
1210 else
1211 out = ".";
1212 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001213
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
Andi Kleen475eeab2013-09-20 07:40:43 -07001224static 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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001265static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001266 size_t size, unsigned int width)
1267{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001268 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001269 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
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001296struct sort_dimension {
1297 const char *name;
1298 struct sort_entry *entry;
1299 int taken;
1300};
1301
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001302#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1303
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001304static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001305 DIM(SORT_PID, "pid", sort_thread),
1306 DIM(SORT_COMM, "comm", sort_comm),
1307 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001308 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001309 DIM(SORT_PARENT, "parent", sort_parent),
1310 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001311 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001312 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001313 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001314 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1315 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001316 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001317};
1318
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001319#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),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001329 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1330 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001331 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001332};
1333
1334#undef DIM
1335
Namhyung Kimafab87b2013-04-03 21:26:11 +09001336#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1337
1338static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001339 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001340 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001341 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),
Don Zickus9b32ba72014-06-01 15:38:29 +02001346 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001347};
1348
1349#undef DIM
1350
Namhyung Kima2ce0672014-03-04 09:06:42 +09001351struct 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"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001365 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001366 DIM(PERF_HPP__SAMPLES, "sample"),
1367 DIM(PERF_HPP__PERIOD, "period"),
1368};
1369
1370#undef DIM
1371
Namhyung Kim8b536992014-03-03 11:46:55 +09001372struct hpp_sort_entry {
1373 struct perf_hpp_fmt hpp;
1374 struct sort_entry *se;
1375};
1376
Namhyung Kima7d945b2014-03-04 10:46:34 +09001377bool 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
Namhyung Kime0d66c72014-07-31 14:47:37 +09001391void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001392{
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);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001399 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001400}
1401
Namhyung Kim8b536992014-03-03 11:46:55 +09001402static 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;
Namhyung Kim5b591662014-07-31 14:47:38 +09001406 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001407
1408 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001409
Namhyung Kim5b591662014-07-31 14:47:38 +09001410 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001411 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001412
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001413 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001414}
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;
Namhyung Kim5b591662014-07-31 14:47:38 +09001421 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001422
1423 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1424
Namhyung Kim5b591662014-07-31 14:47:38 +09001425 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001426 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001427
1428 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001429}
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;
Namhyung Kim5b591662014-07-31 14:47:38 +09001435 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001436
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001438
1439 if (!len)
1440 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001441
1442 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1443}
1444
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001445static 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
Namhyung Kima7d945b2014-03-04 10:46:34 +09001476static struct hpp_sort_entry *
1477__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001478{
1479 struct hpp_sort_entry *hse;
1480
1481 hse = malloc(sizeof(*hse));
1482 if (hse == NULL) {
1483 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001484 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001485 }
1486
1487 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001488 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001489 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
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001494 hse->hpp.cmp = __sort__hpp_cmp;
1495 hse->hpp.collapse = __sort__hpp_collapse;
1496 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001497
1498 INIT_LIST_HEAD(&hse->hpp.list);
1499 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001500 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001501 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001502 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001503
Namhyung Kima7d945b2014-03-04 10:46:34 +09001504 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
Namhyung Kim8b536992014-03-03 11:46:55 +09001519 perf_hpp__register_sort_field(&hse->hpp);
1520 return 0;
1521}
1522
Namhyung Kima7d945b2014-03-04 10:46:34 +09001523static 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
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001534struct 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
Namhyung Kim60517d22015-12-23 02:07:03 +09001563static char *get_trace_output(struct hist_entry *he)
1564{
1565 struct trace_seq seq;
1566 struct perf_evsel *evsel;
1567 struct pevent_record rec = {
1568 .data = he->raw_data,
1569 .size = he->raw_size,
1570 };
1571
1572 evsel = hists_to_evsel(he->hists);
1573
1574 trace_seq_init(&seq);
1575 pevent_event_info(&seq, evsel->tp_format, &rec);
1576 return seq.buffer;
1577}
1578
1579static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1580 struct hist_entry *he)
1581{
1582 char *str, *pos;
1583 struct format_field *field = hde->field;
1584 size_t namelen;
1585 bool last = false;
1586
1587 /* parse pretty print result and update max length */
1588 if (!he->trace_output)
1589 he->trace_output = get_trace_output(he);
1590
1591 namelen = strlen(field->name);
1592 str = he->trace_output;
1593
1594 while (str) {
1595 pos = strchr(str, ' ');
1596 if (pos == NULL) {
1597 last = true;
1598 pos = str + strlen(str);
1599 }
1600
1601 if (!strncmp(str, field->name, namelen)) {
1602 size_t len;
1603
1604 str += namelen + 1;
1605 len = pos - str;
1606
1607 if (len > hde->dynamic_len)
1608 hde->dynamic_len = len;
1609 break;
1610 }
1611
1612 if (last)
1613 str = NULL;
1614 else
1615 str = pos + 1;
1616 }
1617}
1618
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001619static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1620 struct perf_evsel *evsel __maybe_unused)
1621{
1622 struct hpp_dynamic_entry *hde;
1623 size_t len = fmt->user_len;
1624
1625 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1626
1627 if (!len)
1628 len = hde_width(hde);
1629
1630 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1631}
1632
1633static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1634 struct perf_hpp *hpp __maybe_unused,
1635 struct perf_evsel *evsel __maybe_unused)
1636{
1637 struct hpp_dynamic_entry *hde;
1638 size_t len = fmt->user_len;
1639
1640 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1641
1642 if (!len)
1643 len = hde_width(hde);
1644
1645 return len;
1646}
1647
1648static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1649 struct hist_entry *he)
1650{
1651 struct hpp_dynamic_entry *hde;
1652 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001653 char *str, *pos;
1654 struct format_field *field;
1655 size_t namelen;
1656 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001657 int ret;
1658
1659 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1660
1661 if (!len)
1662 len = hde_width(hde);
1663
1664 if (hists_to_evsel(he->hists) != hde->evsel)
1665 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, "N/A");
1666
Namhyung Kim60517d22015-12-23 02:07:03 +09001667 field = hde->field;
1668
1669 namelen = strlen(field->name);
1670 str = he->trace_output;
1671
1672 while (str) {
1673 pos = strchr(str, ' ');
1674 if (pos == NULL) {
1675 last = true;
1676 pos = str + strlen(str);
1677 }
1678
1679 if (!strncmp(str, field->name, namelen)) {
1680 str += namelen + 1;
1681 str = strndup(str, pos - str);
1682
1683 if (str == NULL)
1684 return scnprintf(hpp->buf, hpp->size,
1685 "%*.*s", len, len, "ERROR");
1686 break;
1687 }
1688
1689 if (last)
1690 str = NULL;
1691 else
1692 str = pos + 1;
1693 }
1694
1695 if (str == NULL) {
1696 struct trace_seq seq;
1697 trace_seq_init(&seq);
1698 pevent_print_field(&seq, he->raw_data, hde->field);
1699 str = seq.buffer;
1700 }
1701
1702 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1703 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001704 return ret;
1705}
1706
1707static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1708 struct hist_entry *a, struct hist_entry *b)
1709{
1710 struct hpp_dynamic_entry *hde;
1711 struct format_field *field;
1712 unsigned offset, size;
1713
1714 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1715
1716 if (hists_to_evsel(a->hists) != hde->evsel)
1717 return 0;
1718
1719 field = hde->field;
1720 if (field->flags & FIELD_IS_DYNAMIC) {
1721 unsigned long long dyn;
1722
1723 pevent_read_number_field(field, a->raw_data, &dyn);
1724 offset = dyn & 0xffff;
1725 size = (dyn >> 16) & 0xffff;
1726
1727 /* record max width for output */
1728 if (size > hde->dynamic_len)
1729 hde->dynamic_len = size;
1730 } else {
1731 offset = field->offset;
1732 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001733
1734 update_dynamic_len(hde, a);
1735 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001736 }
1737
1738 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1739}
1740
1741static struct hpp_dynamic_entry *
1742__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1743{
1744 struct hpp_dynamic_entry *hde;
1745
1746 hde = malloc(sizeof(*hde));
1747 if (hde == NULL) {
1748 pr_debug("Memory allocation failed\n");
1749 return NULL;
1750 }
1751
1752 hde->evsel = evsel;
1753 hde->field = field;
1754 hde->dynamic_len = 0;
1755
1756 hde->hpp.name = field->name;
1757 hde->hpp.header = __sort__hde_header;
1758 hde->hpp.width = __sort__hde_width;
1759 hde->hpp.entry = __sort__hde_entry;
1760 hde->hpp.color = NULL;
1761
1762 hde->hpp.cmp = __sort__hde_cmp;
1763 hde->hpp.collapse = __sort__hde_cmp;
1764 hde->hpp.sort = __sort__hde_cmp;
1765
1766 INIT_LIST_HEAD(&hde->hpp.list);
1767 INIT_LIST_HEAD(&hde->hpp.sort_list);
1768 hde->hpp.elide = false;
1769 hde->hpp.len = 0;
1770 hde->hpp.user_len = 0;
1771
1772 return hde;
1773}
1774
1775static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
1776{
1777 char *str, *event_name, *field_name;
1778 struct perf_evsel *evsel, *pos;
1779 struct format_field *field;
1780 struct hpp_dynamic_entry *hde;
1781 int ret = 0;
1782
1783 if (evlist == NULL)
1784 return -ENOENT;
1785
1786 str = strdup(tok);
1787 if (str == NULL)
1788 return -ENOMEM;
1789
1790 event_name = str;
1791 field_name = strchr(str, '.');
1792 if (field_name == NULL) {
1793 ret = -EINVAL;
1794 goto out;
1795 }
1796 *field_name++ = '\0';
1797
1798 evsel = NULL;
1799 evlist__for_each(evlist, pos) {
1800 if (!strcmp(pos->name, event_name)) {
1801 evsel = pos;
1802 break;
1803 }
1804 }
1805
1806 if (evsel == NULL) {
1807 pr_debug("Cannot find event: %s\n", event_name);
1808 ret = -ENOENT;
1809 goto out;
1810 }
1811
1812 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
1813 pr_debug("%s is not a tracepoint event\n", event_name);
1814 ret = -EINVAL;
1815 goto out;
1816 }
1817
1818 field = pevent_find_any_field(evsel->tp_format, field_name);
1819 if (field == NULL) {
1820 pr_debug("Cannot find event field for %s.%s\n",
1821 event_name, field_name);
1822 ret = -ENOENT;
1823 goto out;
1824 }
1825
1826 hde = __alloc_dynamic_entry(evsel, field);
1827 if (hde == NULL) {
1828 ret = -ENOMEM;
1829 goto out;
1830 }
1831
1832 perf_hpp__register_sort_field(&hde->hpp);
1833
1834out:
1835 free(str);
1836 return ret;
1837}
1838
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001839static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001840{
1841 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001842 return 0;
1843
Namhyung Kima7d945b2014-03-04 10:46:34 +09001844 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001845 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001846
1847 if (sd->entry->se_collapse)
1848 sort__need_collapse = 1;
1849
Namhyung Kim2f532d092013-04-03 21:26:10 +09001850 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001851
1852 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001853}
1854
Namhyung Kima2ce0672014-03-04 09:06:42 +09001855static int __hpp_dimension__add(struct hpp_dimension *hd)
1856{
1857 if (!hd->taken) {
1858 hd->taken = 1;
1859
1860 perf_hpp__register_sort_field(hd->fmt);
1861 }
1862 return 0;
1863}
1864
Namhyung Kima7d945b2014-03-04 10:46:34 +09001865static int __sort_dimension__add_output(struct sort_dimension *sd)
1866{
1867 if (sd->taken)
1868 return 0;
1869
1870 if (__sort_dimension__add_hpp_output(sd) < 0)
1871 return -1;
1872
1873 sd->taken = 1;
1874 return 0;
1875}
1876
1877static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1878{
1879 if (!hd->taken) {
1880 hd->taken = 1;
1881
1882 perf_hpp__column_register(hd->fmt);
1883 }
1884 return 0;
1885}
1886
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02001887int hpp_dimension__add_output(unsigned col)
1888{
1889 BUG_ON(col >= PERF_HPP__MAX_INDEX);
1890 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
1891}
1892
Namhyung Kim40184c42015-12-23 02:07:01 +09001893static int sort_dimension__add(const char *tok,
1894 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02001895{
1896 unsigned int i;
1897
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001898 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1899 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001900
John Kacurdd68ada2009-09-24 18:02:49 +02001901 if (strncasecmp(tok, sd->name, strlen(tok)))
1902 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001903
John Kacurdd68ada2009-09-24 18:02:49 +02001904 if (sd->entry == &sort_parent) {
1905 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1906 if (ret) {
1907 char err[BUFSIZ];
1908
1909 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001910 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1911 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001912 }
1913 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001914 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001915 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00001916 /*
1917 * perf diff displays the performance difference amongst
1918 * two or more perf.data files. Those files could come
1919 * from different binaries. So we should not compare
1920 * their ips, but the name of symbol.
1921 */
1922 if (sort__mode == SORT_MODE__DIFF)
1923 sd->entry->se_collapse = sort__sym_sort;
1924
Namhyung Kim68f6d022013-12-18 14:21:10 +09001925 } else if (sd->entry == &sort_dso) {
1926 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001927 } else if (sd->entry == &sort_socket) {
1928 sort__has_socket = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001929 }
1930
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001931 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001932 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001933
Namhyung Kima2ce0672014-03-04 09:06:42 +09001934 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1935 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1936
1937 if (strncasecmp(tok, hd->name, strlen(tok)))
1938 continue;
1939
1940 return __hpp_dimension__add(hd);
1941 }
1942
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001943 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1944 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1945
1946 if (strncasecmp(tok, sd->name, strlen(tok)))
1947 continue;
1948
Namhyung Kim55369fc2013-04-01 20:35:20 +09001949 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001950 return -EINVAL;
1951
1952 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1953 sort__has_sym = 1;
1954
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001955 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001956 return 0;
1957 }
1958
Namhyung Kimafab87b2013-04-03 21:26:11 +09001959 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1960 struct sort_dimension *sd = &memory_sort_dimensions[i];
1961
1962 if (strncasecmp(tok, sd->name, strlen(tok)))
1963 continue;
1964
1965 if (sort__mode != SORT_MODE__MEMORY)
1966 return -EINVAL;
1967
1968 if (sd->entry == &sort_mem_daddr_sym)
1969 sort__has_sym = 1;
1970
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001971 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001972 return 0;
1973 }
1974
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001975 if (!add_dynamic_entry(evlist, tok))
1976 return 0;
1977
John Kacurdd68ada2009-09-24 18:02:49 +02001978 return -ESRCH;
1979}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001980
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001981static const char *get_default_sort_order(void)
1982{
1983 const char *default_sort_orders[] = {
1984 default_sort_order,
1985 default_branch_sort_order,
1986 default_mem_sort_order,
1987 default_top_sort_order,
1988 default_diff_sort_order,
1989 };
1990
1991 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1992
1993 return default_sort_orders[sort__mode];
1994}
1995
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001996static int setup_sort_order(void)
1997{
1998 char *new_sort_order;
1999
2000 /*
2001 * Append '+'-prefixed sort order to the default sort
2002 * order string.
2003 */
2004 if (!sort_order || is_strict_order(sort_order))
2005 return 0;
2006
2007 if (sort_order[1] == '\0') {
2008 error("Invalid --sort key: `+'");
2009 return -EINVAL;
2010 }
2011
2012 /*
2013 * We allocate new sort_order string, but we never free it,
2014 * because it's checked over the rest of the code.
2015 */
2016 if (asprintf(&new_sort_order, "%s,%s",
2017 get_default_sort_order(), sort_order + 1) < 0) {
2018 error("Not enough memory to set up --sort");
2019 return -ENOMEM;
2020 }
2021
2022 sort_order = new_sort_order;
2023 return 0;
2024}
2025
Namhyung Kim40184c42015-12-23 02:07:01 +09002026static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002027{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002028 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002029 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002030 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002031
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002032 ret = setup_sort_order();
2033 if (ret)
2034 return ret;
2035
2036 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002037 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002038 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002039 /*
2040 * If user specified field order but no sort order,
2041 * we'll honor it and not add default sort orders.
2042 */
2043 return 0;
2044 }
2045
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002046 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09002047 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002048
2049 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002050 if (str == NULL) {
2051 error("Not enough memory to setup sort keys");
2052 return -ENOMEM;
2053 }
2054
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002055 for (tok = strtok_r(str, ", ", &tmp);
2056 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002057 ret = sort_dimension__add(tok, evlist);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002058 if (ret == -EINVAL) {
2059 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09002060 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002061 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002062 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09002063 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002064 }
2065 }
2066
2067 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002068 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002069}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002070
Jiri Olsaf2998422014-05-23 17:15:47 +02002071void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002072{
Jiri Olsaf2998422014-05-23 17:15:47 +02002073 struct perf_hpp_fmt *fmt;
2074 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002075
Jiri Olsaf2998422014-05-23 17:15:47 +02002076 perf_hpp__for_each_format(fmt) {
2077 if (!perf_hpp__is_sort_entry(fmt))
2078 continue;
2079
2080 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2081 if (hse->se->se_width_idx == idx) {
2082 fmt->elide = elide;
2083 break;
2084 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002085 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002086}
2087
Jiri Olsaf2998422014-05-23 17:15:47 +02002088static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002089{
2090 if (list && strlist__nr_entries(list) == 1) {
2091 if (fp != NULL)
2092 fprintf(fp, "# %s: %s\n", list_name,
2093 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002094 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002095 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002096 return false;
2097}
2098
2099static bool get_elide(int idx, FILE *output)
2100{
2101 switch (idx) {
2102 case HISTC_SYMBOL:
2103 return __get_elide(symbol_conf.sym_list, "symbol", output);
2104 case HISTC_DSO:
2105 return __get_elide(symbol_conf.dso_list, "dso", output);
2106 case HISTC_COMM:
2107 return __get_elide(symbol_conf.comm_list, "comm", output);
2108 default:
2109 break;
2110 }
2111
2112 if (sort__mode != SORT_MODE__BRANCH)
2113 return false;
2114
2115 switch (idx) {
2116 case HISTC_SYMBOL_FROM:
2117 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2118 case HISTC_SYMBOL_TO:
2119 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2120 case HISTC_DSO_FROM:
2121 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2122 case HISTC_DSO_TO:
2123 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2124 default:
2125 break;
2126 }
2127
2128 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002129}
Namhyung Kim08e71542013-04-03 21:26:19 +09002130
2131void sort__setup_elide(FILE *output)
2132{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002133 struct perf_hpp_fmt *fmt;
2134 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002135
Jiri Olsaf2998422014-05-23 17:15:47 +02002136 perf_hpp__for_each_format(fmt) {
2137 if (!perf_hpp__is_sort_entry(fmt))
2138 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002139
Jiri Olsaf2998422014-05-23 17:15:47 +02002140 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2141 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002142 }
2143
Namhyung Kim7524f632013-11-08 17:53:42 +09002144 /*
2145 * It makes no sense to elide all of sort entries.
2146 * Just revert them to show up again.
2147 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002148 perf_hpp__for_each_format(fmt) {
2149 if (!perf_hpp__is_sort_entry(fmt))
2150 continue;
2151
Jiri Olsaf2998422014-05-23 17:15:47 +02002152 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002153 return;
2154 }
2155
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002156 perf_hpp__for_each_format(fmt) {
2157 if (!perf_hpp__is_sort_entry(fmt))
2158 continue;
2159
Jiri Olsaf2998422014-05-23 17:15:47 +02002160 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002161 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002162}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002163
2164static int output_field_add(char *tok)
2165{
2166 unsigned int i;
2167
2168 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2169 struct sort_dimension *sd = &common_sort_dimensions[i];
2170
2171 if (strncasecmp(tok, sd->name, strlen(tok)))
2172 continue;
2173
2174 return __sort_dimension__add_output(sd);
2175 }
2176
2177 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2178 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2179
2180 if (strncasecmp(tok, hd->name, strlen(tok)))
2181 continue;
2182
2183 return __hpp_dimension__add_output(hd);
2184 }
2185
2186 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2187 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2188
2189 if (strncasecmp(tok, sd->name, strlen(tok)))
2190 continue;
2191
2192 return __sort_dimension__add_output(sd);
2193 }
2194
2195 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2196 struct sort_dimension *sd = &memory_sort_dimensions[i];
2197
2198 if (strncasecmp(tok, sd->name, strlen(tok)))
2199 continue;
2200
2201 return __sort_dimension__add_output(sd);
2202 }
2203
2204 return -ESRCH;
2205}
2206
2207static void reset_dimensions(void)
2208{
2209 unsigned int i;
2210
2211 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2212 common_sort_dimensions[i].taken = 0;
2213
2214 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2215 hpp_sort_dimensions[i].taken = 0;
2216
2217 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2218 bstack_sort_dimensions[i].taken = 0;
2219
2220 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2221 memory_sort_dimensions[i].taken = 0;
2222}
2223
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002224bool is_strict_order(const char *order)
2225{
2226 return order && (*order != '+');
2227}
2228
Namhyung Kima7d945b2014-03-04 10:46:34 +09002229static int __setup_output_field(void)
2230{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002231 char *tmp, *tok, *str, *strp;
2232 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002233
2234 if (field_order == NULL)
2235 return 0;
2236
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002237 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002238 if (str == NULL) {
2239 error("Not enough memory to setup output fields");
2240 return -ENOMEM;
2241 }
2242
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002243 if (!is_strict_order(field_order))
2244 strp++;
2245
2246 if (!strlen(strp)) {
2247 error("Invalid --fields key: `+'");
2248 goto out;
2249 }
2250
2251 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002252 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2253 ret = output_field_add(tok);
2254 if (ret == -EINVAL) {
2255 error("Invalid --fields key: `%s'", tok);
2256 break;
2257 } else if (ret == -ESRCH) {
2258 error("Unknown --fields key: `%s'", tok);
2259 break;
2260 }
2261 }
2262
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002263out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002264 free(str);
2265 return ret;
2266}
2267
Namhyung Kim40184c42015-12-23 02:07:01 +09002268int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002269{
2270 int err;
2271
Namhyung Kim40184c42015-12-23 02:07:01 +09002272 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002273 if (err < 0)
2274 return err;
2275
2276 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002277 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002278 if (err < 0)
2279 return err;
2280 }
2281
2282 reset_dimensions();
2283
2284 /*
2285 * perf diff doesn't use default hpp output fields.
2286 */
2287 if (sort__mode != SORT_MODE__DIFF)
2288 perf_hpp__init();
2289
2290 err = __setup_output_field();
2291 if (err < 0)
2292 return err;
2293
2294 /* copy sort keys to output fields */
2295 perf_hpp__setup_output_field();
2296 /* and then copy output fields to sort keys */
2297 perf_hpp__append_sort_keys();
2298
2299 return 0;
2300}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002301
2302void reset_output_field(void)
2303{
2304 sort__need_collapse = 0;
2305 sort__has_parent = 0;
2306 sort__has_sym = 0;
2307 sort__has_dso = 0;
2308
Namhyung Kimd69b2962014-05-23 10:59:01 +09002309 field_order = NULL;
2310 sort_order = NULL;
2311
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002312 reset_dimensions();
2313 perf_hpp__reset_output_field();
2314}