blob: b4ecc0e4c908da0fe698849198b50963e6ef558a [file] [log] [blame]
John Kacurdd68ada2009-09-24 18:02:49 +02001#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03002#include "hist.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09003#include "symbol.h"
John Kacurdd68ada2009-09-24 18:02:49 +02004
5regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03006const char default_parent_pattern[] = "^sys_|^do_page_fault";
7const char *parent_pattern = default_parent_pattern;
8const char default_sort_order[] = "comm,dso,symbol";
9const char *sort_order = default_sort_order;
Greg Priceb21484f2012-12-06 21:48:05 -080010regex_t ignore_callees_regex;
11int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020012int sort__need_collapse = 0;
13int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090014int sort__has_sym = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090015enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020016
17enum sort_type sort__first_dimension;
John Kacurdd68ada2009-09-24 18:02:49 +020018
John Kacurdd68ada2009-09-24 18:02:49 +020019LIST_HEAD(hist_entry__sort_list);
20
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030021static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020022{
23 int n;
24 va_list ap;
25
26 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030027 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020028 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030029 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020030
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030031 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020032 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030033 if (sep == NULL)
34 break;
35 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020036 }
John Kacurdd68ada2009-09-24 18:02:49 +020037 }
38 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110039
40 if (n >= (int)size)
41 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020042 return n;
43}
44
Frederic Weisbecker872a8782011-06-29 03:14:52 +020045static int64_t cmp_null(void *l, void *r)
46{
47 if (!l && !r)
48 return 0;
49 else if (!l)
50 return -1;
51 else
52 return 1;
53}
54
55/* --sort pid */
56
57static int64_t
58sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
59{
Adrian Hunter38051232013-07-04 16:20:31 +030060 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020061}
62
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030063static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
64 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020065{
Namhyung Kimfb29a332012-12-27 18:11:40 +090066 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Adrian Hunter38051232013-07-04 16:20:31 +030067 self->thread->comm ?: "", self->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020068}
69
Frederic Weisbecker872a8782011-06-29 03:14:52 +020070struct sort_entry sort_thread = {
71 .se_header = "Command: Pid",
72 .se_cmp = sort__thread_cmp,
73 .se_snprintf = hist_entry__thread_snprintf,
74 .se_width_idx = HISTC_THREAD,
75};
76
77/* --sort comm */
78
79static int64_t
80sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
81{
Adrian Hunter38051232013-07-04 16:20:31 +030082 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020083}
84
85static int64_t
86sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
87{
88 char *comm_l = left->thread->comm;
89 char *comm_r = right->thread->comm;
90
91 if (!comm_l || !comm_r)
92 return cmp_null(comm_l, comm_r);
93
94 return strcmp(comm_l, comm_r);
95}
96
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030097static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
98 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020099{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300100 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
John Kacurdd68ada2009-09-24 18:02:49 +0200101}
102
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900103struct sort_entry sort_comm = {
104 .se_header = "Command",
105 .se_cmp = sort__comm_cmp,
106 .se_collapse = sort__comm_collapse,
107 .se_snprintf = hist_entry__comm_snprintf,
108 .se_width_idx = HISTC_COMM,
109};
110
111/* --sort dso */
112
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100113static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200114{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100115 struct dso *dso_l = map_l ? map_l->dso : NULL;
116 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300117 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200118
119 if (!dso_l || !dso_r)
120 return cmp_null(dso_l, dso_r);
121
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300122 if (verbose) {
123 dso_name_l = dso_l->long_name;
124 dso_name_r = dso_r->long_name;
125 } else {
126 dso_name_l = dso_l->short_name;
127 dso_name_r = dso_r->short_name;
128 }
129
130 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200131}
132
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100133static int64_t
134sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200135{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100136 return _sort__dso_cmp(left->ms.map, right->ms.map);
137}
138
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100139static int _hist_entry__dso_snprintf(struct map *map, char *bf,
140 size_t size, unsigned int width)
141{
142 if (map && map->dso) {
143 const char *dso_name = !verbose ? map->dso->short_name :
144 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300145 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300146 }
John Kacurdd68ada2009-09-24 18:02:49 +0200147
Ian Munsie1437a302010-12-06 13:37:04 +1100148 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200149}
150
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100151static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
152 size_t size, unsigned int width)
153{
154 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
155}
156
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900157struct sort_entry sort_dso = {
158 .se_header = "Shared Object",
159 .se_cmp = sort__dso_cmp,
160 .se_snprintf = hist_entry__dso_snprintf,
161 .se_width_idx = HISTC_DSO,
162};
163
164/* --sort symbol */
165
Namhyung Kim51f27d12013-02-06 14:57:15 +0900166static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900167{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900168 u64 ip_l, ip_r;
169
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900170 if (!sym_l || !sym_r)
171 return cmp_null(sym_l, sym_r);
172
173 if (sym_l == sym_r)
174 return 0;
175
176 ip_l = sym_l->start;
177 ip_r = sym_r->start;
178
179 return (int64_t)(ip_r - ip_l);
180}
181
182static int64_t
183sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
184{
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900185 if (!left->ms.sym && !right->ms.sym)
186 return right->level - left->level;
187
Namhyung Kim51f27d12013-02-06 14:57:15 +0900188 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900189}
190
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100191static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
192 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900193 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100194{
195 size_t ret = 0;
196
197 if (verbose) {
198 char o = map ? dso__symtab_origin(map->dso) : '!';
199 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900200 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100201 }
202
203 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100204 if (sym && map) {
205 if (map->type == MAP__VARIABLE) {
206 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
207 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100208 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100209 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
210 width - ret, "");
211 } else {
212 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
213 width - ret,
214 sym->name);
215 }
216 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100217 size_t len = BITS_PER_LONG / 4;
218 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
219 len, ip);
220 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
221 width - ret, "");
222 }
223
224 return ret;
225}
226
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100227static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900228 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229{
230 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
231 self->level, bf, size, width);
232}
John Kacurdd68ada2009-09-24 18:02:49 +0200233
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200234struct sort_entry sort_sym = {
235 .se_header = "Symbol",
236 .se_cmp = sort__sym_cmp,
237 .se_snprintf = hist_entry__sym_snprintf,
238 .se_width_idx = HISTC_SYMBOL,
239};
John Kacurdd68ada2009-09-24 18:02:49 +0200240
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300241/* --sort srcline */
242
243static int64_t
244sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
245{
246 return (int64_t)(right->ip - left->ip);
247}
248
249static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300250 size_t size,
251 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300252{
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100253 FILE *fp = NULL;
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300254 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
255 size_t line_len;
256
257 if (path != NULL)
258 goto out_path;
259
Namhyung Kimffe10c62012-10-15 12:39:42 +0900260 if (!self->ms.map)
261 goto out_ip;
262
Namhyung Kim88481b62012-10-15 12:39:43 +0900263 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
264 goto out_ip;
265
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300266 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
267 self->ms.map->dso->long_name, self->ip);
268 fp = popen(cmd, "r");
269 if (!fp)
270 goto out_ip;
271
272 if (getline(&path, &line_len, fp) < 0 || !line_len)
273 goto out_ip;
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300274 self->srcline = strdup(path);
275 if (self->srcline == NULL)
276 goto out_ip;
277
278 nl = strchr(self->srcline, '\n');
279 if (nl != NULL)
280 *nl = '\0';
281 path = self->srcline;
282out_path:
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100283 if (fp)
284 pclose(fp);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300285 return repsep_snprintf(bf, size, "%s", path);
286out_ip:
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100287 if (fp)
288 pclose(fp);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300289 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
290}
291
292struct sort_entry sort_srcline = {
293 .se_header = "Source:Line",
294 .se_cmp = sort__srcline_cmp,
295 .se_snprintf = hist_entry__srcline_snprintf,
296 .se_width_idx = HISTC_SRCLINE,
297};
298
John Kacurdd68ada2009-09-24 18:02:49 +0200299/* --sort parent */
300
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200301static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200302sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
303{
304 struct symbol *sym_l = left->parent;
305 struct symbol *sym_r = right->parent;
306
307 if (!sym_l || !sym_r)
308 return cmp_null(sym_l, sym_r);
309
310 return strcmp(sym_l->name, sym_r->name);
311}
312
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300313static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
314 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200315{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300316 return repsep_snprintf(bf, size, "%-*s", width,
John Kacurdd68ada2009-09-24 18:02:49 +0200317 self->parent ? self->parent->name : "[other]");
318}
319
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200320struct sort_entry sort_parent = {
321 .se_header = "Parent symbol",
322 .se_cmp = sort__parent_cmp,
323 .se_snprintf = hist_entry__parent_snprintf,
324 .se_width_idx = HISTC_PARENT,
325};
326
Arun Sharmaf60f3592010-06-04 11:27:10 -0300327/* --sort cpu */
328
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200329static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300330sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
331{
332 return right->cpu - left->cpu;
333}
334
335static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
336 size_t size, unsigned int width)
337{
Namhyung Kimdccf1802012-12-27 18:11:41 +0900338 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300339}
340
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200341struct sort_entry sort_cpu = {
342 .se_header = "CPU",
343 .se_cmp = sort__cpu_cmp,
344 .se_snprintf = hist_entry__cpu_snprintf,
345 .se_width_idx = HISTC_CPU,
346};
347
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900348/* sort keys for branch stacks */
349
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100350static int64_t
351sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
352{
353 return _sort__dso_cmp(left->branch_info->from.map,
354 right->branch_info->from.map);
355}
356
357static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
358 size_t size, unsigned int width)
359{
360 return _hist_entry__dso_snprintf(self->branch_info->from.map,
361 bf, size, width);
362}
363
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100364static int64_t
365sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
366{
367 return _sort__dso_cmp(left->branch_info->to.map,
368 right->branch_info->to.map);
369}
370
371static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
372 size_t size, unsigned int width)
373{
374 return _hist_entry__dso_snprintf(self->branch_info->to.map,
375 bf, size, width);
376}
377
378static int64_t
379sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
380{
381 struct addr_map_symbol *from_l = &left->branch_info->from;
382 struct addr_map_symbol *from_r = &right->branch_info->from;
383
384 if (!from_l->sym && !from_r->sym)
385 return right->level - left->level;
386
Namhyung Kim51f27d12013-02-06 14:57:15 +0900387 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100388}
389
390static int64_t
391sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
392{
393 struct addr_map_symbol *to_l = &left->branch_info->to;
394 struct addr_map_symbol *to_r = &right->branch_info->to;
395
396 if (!to_l->sym && !to_r->sym)
397 return right->level - left->level;
398
Namhyung Kim51f27d12013-02-06 14:57:15 +0900399 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100400}
401
402static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900403 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100404{
405 struct addr_map_symbol *from = &self->branch_info->from;
406 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
407 self->level, bf, size, width);
408
409}
410
411static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900412 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100413{
414 struct addr_map_symbol *to = &self->branch_info->to;
415 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
416 self->level, bf, size, width);
417
418}
419
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900420struct sort_entry sort_dso_from = {
421 .se_header = "Source Shared Object",
422 .se_cmp = sort__dso_from_cmp,
423 .se_snprintf = hist_entry__dso_from_snprintf,
424 .se_width_idx = HISTC_DSO_FROM,
425};
426
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427struct sort_entry sort_dso_to = {
428 .se_header = "Target Shared Object",
429 .se_cmp = sort__dso_to_cmp,
430 .se_snprintf = hist_entry__dso_to_snprintf,
431 .se_width_idx = HISTC_DSO_TO,
432};
433
434struct sort_entry sort_sym_from = {
435 .se_header = "Source Symbol",
436 .se_cmp = sort__sym_from_cmp,
437 .se_snprintf = hist_entry__sym_from_snprintf,
438 .se_width_idx = HISTC_SYMBOL_FROM,
439};
440
441struct sort_entry sort_sym_to = {
442 .se_header = "Target Symbol",
443 .se_cmp = sort__sym_to_cmp,
444 .se_snprintf = hist_entry__sym_to_snprintf,
445 .se_width_idx = HISTC_SYMBOL_TO,
446};
447
448static int64_t
449sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
450{
451 const unsigned char mp = left->branch_info->flags.mispred !=
452 right->branch_info->flags.mispred;
453 const unsigned char p = left->branch_info->flags.predicted !=
454 right->branch_info->flags.predicted;
455
456 return mp || p;
457}
458
459static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
460 size_t size, unsigned int width){
461 static const char *out = "N/A";
462
463 if (self->branch_info->flags.predicted)
464 out = "N";
465 else if (self->branch_info->flags.mispred)
466 out = "Y";
467
468 return repsep_snprintf(bf, size, "%-*s", width, out);
469}
470
Stephane Eranian98a3b322013-01-24 16:10:35 +0100471/* --sort daddr_sym */
472static int64_t
473sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 uint64_t l = 0, r = 0;
476
477 if (left->mem_info)
478 l = left->mem_info->daddr.addr;
479 if (right->mem_info)
480 r = right->mem_info->daddr.addr;
481
482 return (int64_t)(r - l);
483}
484
485static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
486 size_t size, unsigned int width)
487{
488 uint64_t addr = 0;
489 struct map *map = NULL;
490 struct symbol *sym = NULL;
491
492 if (self->mem_info) {
493 addr = self->mem_info->daddr.addr;
494 map = self->mem_info->daddr.map;
495 sym = self->mem_info->daddr.sym;
496 }
497 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
498 width);
499}
500
501static int64_t
502sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
503{
504 struct map *map_l = NULL;
505 struct map *map_r = NULL;
506
507 if (left->mem_info)
508 map_l = left->mem_info->daddr.map;
509 if (right->mem_info)
510 map_r = right->mem_info->daddr.map;
511
512 return _sort__dso_cmp(map_l, map_r);
513}
514
515static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
516 size_t size, unsigned int width)
517{
518 struct map *map = NULL;
519
520 if (self->mem_info)
521 map = self->mem_info->daddr.map;
522
523 return _hist_entry__dso_snprintf(map, bf, size, width);
524}
525
526static int64_t
527sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
528{
529 union perf_mem_data_src data_src_l;
530 union perf_mem_data_src data_src_r;
531
532 if (left->mem_info)
533 data_src_l = left->mem_info->data_src;
534 else
535 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
536
537 if (right->mem_info)
538 data_src_r = right->mem_info->data_src;
539 else
540 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
541
542 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
543}
544
545static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
546 size_t size, unsigned int width)
547{
548 const char *out;
549 u64 mask = PERF_MEM_LOCK_NA;
550
551 if (self->mem_info)
552 mask = self->mem_info->data_src.mem_lock;
553
554 if (mask & PERF_MEM_LOCK_NA)
555 out = "N/A";
556 else if (mask & PERF_MEM_LOCK_LOCKED)
557 out = "Yes";
558 else
559 out = "No";
560
561 return repsep_snprintf(bf, size, "%-*s", width, out);
562}
563
564static int64_t
565sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
566{
567 union perf_mem_data_src data_src_l;
568 union perf_mem_data_src data_src_r;
569
570 if (left->mem_info)
571 data_src_l = left->mem_info->data_src;
572 else
573 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
574
575 if (right->mem_info)
576 data_src_r = right->mem_info->data_src;
577 else
578 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
579
580 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
581}
582
583static const char * const tlb_access[] = {
584 "N/A",
585 "HIT",
586 "MISS",
587 "L1",
588 "L2",
589 "Walker",
590 "Fault",
591};
592#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
593
594static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
595 size_t size, unsigned int width)
596{
597 char out[64];
598 size_t sz = sizeof(out) - 1; /* -1 for null termination */
599 size_t l = 0, i;
600 u64 m = PERF_MEM_TLB_NA;
601 u64 hit, miss;
602
603 out[0] = '\0';
604
605 if (self->mem_info)
606 m = self->mem_info->data_src.mem_dtlb;
607
608 hit = m & PERF_MEM_TLB_HIT;
609 miss = m & PERF_MEM_TLB_MISS;
610
611 /* already taken care of */
612 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
613
614 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
615 if (!(m & 0x1))
616 continue;
617 if (l) {
618 strcat(out, " or ");
619 l += 4;
620 }
621 strncat(out, tlb_access[i], sz - l);
622 l += strlen(tlb_access[i]);
623 }
624 if (*out == '\0')
625 strcpy(out, "N/A");
626 if (hit)
627 strncat(out, " hit", sz - l);
628 if (miss)
629 strncat(out, " miss", sz - l);
630
631 return repsep_snprintf(bf, size, "%-*s", width, out);
632}
633
634static int64_t
635sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
636{
637 union perf_mem_data_src data_src_l;
638 union perf_mem_data_src data_src_r;
639
640 if (left->mem_info)
641 data_src_l = left->mem_info->data_src;
642 else
643 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
644
645 if (right->mem_info)
646 data_src_r = right->mem_info->data_src;
647 else
648 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
649
650 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
651}
652
653static const char * const mem_lvl[] = {
654 "N/A",
655 "HIT",
656 "MISS",
657 "L1",
658 "LFB",
659 "L2",
660 "L3",
661 "Local RAM",
662 "Remote RAM (1 hop)",
663 "Remote RAM (2 hops)",
664 "Remote Cache (1 hop)",
665 "Remote Cache (2 hops)",
666 "I/O",
667 "Uncached",
668};
669#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
670
671static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
672 size_t size, unsigned int width)
673{
674 char out[64];
675 size_t sz = sizeof(out) - 1; /* -1 for null termination */
676 size_t i, l = 0;
677 u64 m = PERF_MEM_LVL_NA;
678 u64 hit, miss;
679
680 if (self->mem_info)
681 m = self->mem_info->data_src.mem_lvl;
682
683 out[0] = '\0';
684
685 hit = m & PERF_MEM_LVL_HIT;
686 miss = m & PERF_MEM_LVL_MISS;
687
688 /* already taken care of */
689 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
690
691 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
692 if (!(m & 0x1))
693 continue;
694 if (l) {
695 strcat(out, " or ");
696 l += 4;
697 }
698 strncat(out, mem_lvl[i], sz - l);
699 l += strlen(mem_lvl[i]);
700 }
701 if (*out == '\0')
702 strcpy(out, "N/A");
703 if (hit)
704 strncat(out, " hit", sz - l);
705 if (miss)
706 strncat(out, " miss", sz - l);
707
708 return repsep_snprintf(bf, size, "%-*s", width, out);
709}
710
711static int64_t
712sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
713{
714 union perf_mem_data_src data_src_l;
715 union perf_mem_data_src data_src_r;
716
717 if (left->mem_info)
718 data_src_l = left->mem_info->data_src;
719 else
720 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
721
722 if (right->mem_info)
723 data_src_r = right->mem_info->data_src;
724 else
725 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
726
727 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
728}
729
730static const char * const snoop_access[] = {
731 "N/A",
732 "None",
733 "Miss",
734 "Hit",
735 "HitM",
736};
737#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
738
739static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
740 size_t size, unsigned int width)
741{
742 char out[64];
743 size_t sz = sizeof(out) - 1; /* -1 for null termination */
744 size_t i, l = 0;
745 u64 m = PERF_MEM_SNOOP_NA;
746
747 out[0] = '\0';
748
749 if (self->mem_info)
750 m = self->mem_info->data_src.mem_snoop;
751
752 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
753 if (!(m & 0x1))
754 continue;
755 if (l) {
756 strcat(out, " or ");
757 l += 4;
758 }
759 strncat(out, snoop_access[i], sz - l);
760 l += strlen(snoop_access[i]);
761 }
762
763 if (*out == '\0')
764 strcpy(out, "N/A");
765
766 return repsep_snprintf(bf, size, "%-*s", width, out);
767}
768
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100769struct sort_entry sort_mispredict = {
770 .se_header = "Branch Mispredicted",
771 .se_cmp = sort__mispredict_cmp,
772 .se_snprintf = hist_entry__mispredict_snprintf,
773 .se_width_idx = HISTC_MISPREDICT,
774};
775
Andi Kleen05484292013-01-24 16:10:29 +0100776static u64 he_weight(struct hist_entry *he)
777{
778 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
779}
780
781static int64_t
782sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
783{
784 return he_weight(left) - he_weight(right);
785}
786
787static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
788 size_t size, unsigned int width)
789{
790 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
791}
792
793struct sort_entry sort_local_weight = {
794 .se_header = "Local Weight",
795 .se_cmp = sort__local_weight_cmp,
796 .se_snprintf = hist_entry__local_weight_snprintf,
797 .se_width_idx = HISTC_LOCAL_WEIGHT,
798};
799
800static int64_t
801sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
802{
803 return left->stat.weight - right->stat.weight;
804}
805
806static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
807 size_t size, unsigned int width)
808{
809 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
810}
811
812struct sort_entry sort_global_weight = {
813 .se_header = "Weight",
814 .se_cmp = sort__global_weight_cmp,
815 .se_snprintf = hist_entry__global_weight_snprintf,
816 .se_width_idx = HISTC_GLOBAL_WEIGHT,
817};
818
Stephane Eranian98a3b322013-01-24 16:10:35 +0100819struct sort_entry sort_mem_daddr_sym = {
820 .se_header = "Data Symbol",
821 .se_cmp = sort__daddr_cmp,
822 .se_snprintf = hist_entry__daddr_snprintf,
823 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
824};
825
826struct sort_entry sort_mem_daddr_dso = {
827 .se_header = "Data Object",
828 .se_cmp = sort__dso_daddr_cmp,
829 .se_snprintf = hist_entry__dso_daddr_snprintf,
830 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
831};
832
833struct sort_entry sort_mem_locked = {
834 .se_header = "Locked",
835 .se_cmp = sort__locked_cmp,
836 .se_snprintf = hist_entry__locked_snprintf,
837 .se_width_idx = HISTC_MEM_LOCKED,
838};
839
840struct sort_entry sort_mem_tlb = {
841 .se_header = "TLB access",
842 .se_cmp = sort__tlb_cmp,
843 .se_snprintf = hist_entry__tlb_snprintf,
844 .se_width_idx = HISTC_MEM_TLB,
845};
846
847struct sort_entry sort_mem_lvl = {
848 .se_header = "Memory access",
849 .se_cmp = sort__lvl_cmp,
850 .se_snprintf = hist_entry__lvl_snprintf,
851 .se_width_idx = HISTC_MEM_LVL,
852};
853
854struct sort_entry sort_mem_snoop = {
855 .se_header = "Snoop",
856 .se_cmp = sort__snoop_cmp,
857 .se_snprintf = hist_entry__snoop_snprintf,
858 .se_width_idx = HISTC_MEM_SNOOP,
859};
860
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700861static int64_t
862sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
863{
864 return left->branch_info->flags.abort !=
865 right->branch_info->flags.abort;
866}
867
868static int hist_entry__abort_snprintf(struct hist_entry *self, char *bf,
869 size_t size, unsigned int width)
870{
871 static const char *out = ".";
872
873 if (self->branch_info->flags.abort)
874 out = "A";
875 return repsep_snprintf(bf, size, "%-*s", width, out);
876}
877
878struct sort_entry sort_abort = {
879 .se_header = "Transaction abort",
880 .se_cmp = sort__abort_cmp,
881 .se_snprintf = hist_entry__abort_snprintf,
882 .se_width_idx = HISTC_ABORT,
883};
884
885static int64_t
886sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
887{
888 return left->branch_info->flags.in_tx !=
889 right->branch_info->flags.in_tx;
890}
891
892static int hist_entry__in_tx_snprintf(struct hist_entry *self, char *bf,
893 size_t size, unsigned int width)
894{
895 static const char *out = ".";
896
897 if (self->branch_info->flags.in_tx)
898 out = "T";
899
900 return repsep_snprintf(bf, size, "%-*s", width, out);
901}
902
903struct sort_entry sort_in_tx = {
904 .se_header = "Branch in transaction",
905 .se_cmp = sort__in_tx_cmp,
906 .se_snprintf = hist_entry__in_tx_snprintf,
907 .se_width_idx = HISTC_IN_TX,
908};
909
Andi Kleen475eeab2013-09-20 07:40:43 -0700910static int64_t
911sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
912{
913 return left->transaction - right->transaction;
914}
915
916static inline char *add_str(char *p, const char *str)
917{
918 strcpy(p, str);
919 return p + strlen(str);
920}
921
922static struct txbit {
923 unsigned flag;
924 const char *name;
925 int skip_for_len;
926} txbits[] = {
927 { PERF_TXN_ELISION, "EL ", 0 },
928 { PERF_TXN_TRANSACTION, "TX ", 1 },
929 { PERF_TXN_SYNC, "SYNC ", 1 },
930 { PERF_TXN_ASYNC, "ASYNC ", 0 },
931 { PERF_TXN_RETRY, "RETRY ", 0 },
932 { PERF_TXN_CONFLICT, "CON ", 0 },
933 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
934 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
935 { 0, NULL, 0 }
936};
937
938int hist_entry__transaction_len(void)
939{
940 int i;
941 int len = 0;
942
943 for (i = 0; txbits[i].name; i++) {
944 if (!txbits[i].skip_for_len)
945 len += strlen(txbits[i].name);
946 }
947 len += 4; /* :XX<space> */
948 return len;
949}
950
951static int hist_entry__transaction_snprintf(struct hist_entry *self, char *bf,
952 size_t size, unsigned int width)
953{
954 u64 t = self->transaction;
955 char buf[128];
956 char *p = buf;
957 int i;
958
959 buf[0] = 0;
960 for (i = 0; txbits[i].name; i++)
961 if (txbits[i].flag & t)
962 p = add_str(p, txbits[i].name);
963 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
964 p = add_str(p, "NEITHER ");
965 if (t & PERF_TXN_ABORT_MASK) {
966 sprintf(p, ":%" PRIx64,
967 (t & PERF_TXN_ABORT_MASK) >>
968 PERF_TXN_ABORT_SHIFT);
969 p += strlen(p);
970 }
971
972 return repsep_snprintf(bf, size, "%-*s", width, buf);
973}
974
975struct sort_entry sort_transaction = {
976 .se_header = "Transaction ",
977 .se_cmp = sort__transaction_cmp,
978 .se_snprintf = hist_entry__transaction_snprintf,
979 .se_width_idx = HISTC_TRANSACTION,
980};
981
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200982struct sort_dimension {
983 const char *name;
984 struct sort_entry *entry;
985 int taken;
986};
987
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100988#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
989
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900990static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100991 DIM(SORT_PID, "pid", sort_thread),
992 DIM(SORT_COMM, "comm", sort_comm),
993 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100994 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100995 DIM(SORT_PARENT, "parent", sort_parent),
996 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300997 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -0700998 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
999 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001000 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001001};
1002
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001003#undef DIM
1004
1005#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1006
1007static struct sort_dimension bstack_sort_dimensions[] = {
1008 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1009 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1010 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1011 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1012 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001013 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1014 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001015};
1016
1017#undef DIM
1018
Namhyung Kimafab87b2013-04-03 21:26:11 +09001019#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1020
1021static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001022 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1023 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1024 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1025 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1026 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1027 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1028};
1029
1030#undef DIM
1031
Namhyung Kim2f532d092013-04-03 21:26:10 +09001032static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1033{
1034 if (sd->taken)
1035 return;
1036
1037 if (sd->entry->se_collapse)
1038 sort__need_collapse = 1;
1039
1040 if (list_empty(&hist_entry__sort_list))
1041 sort__first_dimension = idx;
1042
1043 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1044 sd->taken = 1;
1045}
1046
John Kacurdd68ada2009-09-24 18:02:49 +02001047int sort_dimension__add(const char *tok)
1048{
1049 unsigned int i;
1050
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001051 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1052 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001053
John Kacurdd68ada2009-09-24 18:02:49 +02001054 if (strncasecmp(tok, sd->name, strlen(tok)))
1055 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001056
John Kacurdd68ada2009-09-24 18:02:49 +02001057 if (sd->entry == &sort_parent) {
1058 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1059 if (ret) {
1060 char err[BUFSIZ];
1061
1062 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001063 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1064 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001065 }
1066 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001067 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001068 sort__has_sym = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001069 }
1070
Namhyung Kim2f532d092013-04-03 21:26:10 +09001071 __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001072 return 0;
1073 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001074
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1076 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1077
1078 if (strncasecmp(tok, sd->name, strlen(tok)))
1079 continue;
1080
Namhyung Kim55369fc2013-04-01 20:35:20 +09001081 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001082 return -EINVAL;
1083
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1;
1086
Namhyung Kim2f532d092013-04-03 21:26:10 +09001087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001088 return 0;
1089 }
1090
Namhyung Kimafab87b2013-04-03 21:26:11 +09001091 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1092 struct sort_dimension *sd = &memory_sort_dimensions[i];
1093
1094 if (strncasecmp(tok, sd->name, strlen(tok)))
1095 continue;
1096
1097 if (sort__mode != SORT_MODE__MEMORY)
1098 return -EINVAL;
1099
1100 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1;
1102
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1104 return 0;
1105 }
1106
John Kacurdd68ada2009-09-24 18:02:49 +02001107 return -ESRCH;
1108}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001109
Namhyung Kim55309982013-02-06 14:57:16 +09001110int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001111{
1112 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +09001113 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001114
Namhyung Kim5936f542013-02-06 14:57:17 +09001115 if (str == NULL) {
1116 error("Not enough memory to setup sort keys");
1117 return -ENOMEM;
1118 }
1119
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001120 for (tok = strtok_r(str, ", ", &tmp);
1121 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001122 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001123 if (ret == -EINVAL) {
1124 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001125 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001126 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001127 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001128 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001129 }
1130 }
1131
1132 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001133 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001134}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001135
Namhyung Kim08e71542013-04-03 21:26:19 +09001136static void sort_entry__setup_elide(struct sort_entry *self,
1137 struct strlist *list,
1138 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001139{
1140 if (list && strlist__nr_entries(list) == 1) {
1141 if (fp != NULL)
1142 fprintf(fp, "# %s: %s\n", list_name,
1143 strlist__entry(list, 0)->s);
1144 self->elide = true;
1145 }
1146}
Namhyung Kim08e71542013-04-03 21:26:19 +09001147
1148void sort__setup_elide(FILE *output)
1149{
1150 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1151 "dso", output);
1152 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1153 "comm", output);
1154 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1155 "symbol", output);
1156
1157 if (sort__mode == SORT_MODE__BRANCH) {
1158 sort_entry__setup_elide(&sort_dso_from,
1159 symbol_conf.dso_from_list,
1160 "dso_from", output);
1161 sort_entry__setup_elide(&sort_dso_to,
1162 symbol_conf.dso_to_list,
1163 "dso_to", output);
1164 sort_entry__setup_elide(&sort_sym_from,
1165 symbol_conf.sym_from_list,
1166 "sym_from", output);
1167 sort_entry__setup_elide(&sort_sym_to,
1168 symbol_conf.sym_to_list,
1169 "sym_to", output);
1170 } else if (sort__mode == SORT_MODE__MEMORY) {
1171 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1172 "symbol_daddr", output);
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "dso_daddr", output);
1175 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1176 "mem", output);
1177 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1178 "local_weight", output);
1179 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1180 "tlb", output);
1181 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1182 "snoop", output);
1183 }
1184
1185}