blob: bf91d0e5c16e20fda56880629967038a41a29aea [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 Weisbeckerb9c51432013-09-11 14:46:56 +020045static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020046{
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 Meloc824c432013-10-22 19:01:31 -030063static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030064 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020065{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020066 const char *comm = thread__comm_str(he->thread);
Namhyung Kimfb29a332012-12-27 18:11:40 +090067 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020068 comm ?: "", he->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020069}
70
Frederic Weisbecker872a8782011-06-29 03:14:52 +020071struct sort_entry sort_thread = {
72 .se_header = "Command: Pid",
73 .se_cmp = sort__thread_cmp,
74 .se_snprintf = hist_entry__thread_snprintf,
75 .se_width_idx = HISTC_THREAD,
76};
77
78/* --sort comm */
79
80static int64_t
81sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
82{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020083 /* Compare the addr that should be unique among comm */
84 return thread__comm_str(right->thread) - thread__comm_str(left->thread);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020085}
86
87static int64_t
88sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
89{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020090 const char *comm_l = thread__comm_str(left->thread);
91 const char *comm_r = thread__comm_str(right->thread);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020092
93 if (!comm_l || !comm_r)
94 return cmp_null(comm_l, comm_r);
95
96 return strcmp(comm_l, comm_r);
97}
98
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030099static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300100 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200101{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +0200102 return repsep_snprintf(bf, size, "%*s", width, thread__comm_str(he->thread));
John Kacurdd68ada2009-09-24 18:02:49 +0200103}
104
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900105struct sort_entry sort_comm = {
106 .se_header = "Command",
107 .se_cmp = sort__comm_cmp,
108 .se_collapse = sort__comm_collapse,
109 .se_snprintf = hist_entry__comm_snprintf,
110 .se_width_idx = HISTC_COMM,
111};
112
113/* --sort dso */
114
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100115static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200116{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100117 struct dso *dso_l = map_l ? map_l->dso : NULL;
118 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300119 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200120
121 if (!dso_l || !dso_r)
122 return cmp_null(dso_l, dso_r);
123
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300124 if (verbose) {
125 dso_name_l = dso_l->long_name;
126 dso_name_r = dso_r->long_name;
127 } else {
128 dso_name_l = dso_l->short_name;
129 dso_name_r = dso_r->short_name;
130 }
131
132 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200133}
134
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100135static int64_t
136sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200137{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100138 return _sort__dso_cmp(left->ms.map, right->ms.map);
139}
140
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100141static int _hist_entry__dso_snprintf(struct map *map, char *bf,
142 size_t size, unsigned int width)
143{
144 if (map && map->dso) {
145 const char *dso_name = !verbose ? map->dso->short_name :
146 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300147 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300148 }
John Kacurdd68ada2009-09-24 18:02:49 +0200149
Ian Munsie1437a302010-12-06 13:37:04 +1100150 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200151}
152
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300153static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100154 size_t size, unsigned int width)
155{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300156 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100157}
158
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900159struct sort_entry sort_dso = {
160 .se_header = "Shared Object",
161 .se_cmp = sort__dso_cmp,
162 .se_snprintf = hist_entry__dso_snprintf,
163 .se_width_idx = HISTC_DSO,
164};
165
166/* --sort symbol */
167
Namhyung Kim51f27d12013-02-06 14:57:15 +0900168static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900169{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900170 u64 ip_l, ip_r;
171
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900172 if (!sym_l || !sym_r)
173 return cmp_null(sym_l, sym_r);
174
175 if (sym_l == sym_r)
176 return 0;
177
178 ip_l = sym_l->start;
179 ip_r = sym_r->start;
180
181 return (int64_t)(ip_r - ip_l);
182}
183
184static int64_t
185sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
186{
Namhyung Kim09600e02013-10-15 11:01:56 +0900187 int64_t ret;
188
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900189 if (!left->ms.sym && !right->ms.sym)
190 return right->level - left->level;
191
Namhyung Kim09600e02013-10-15 11:01:56 +0900192 /*
193 * comparing symbol address alone is not enough since it's a
194 * relative address within a dso.
195 */
196 ret = sort__dso_cmp(left, right);
197 if (ret != 0)
198 return ret;
199
Namhyung Kim51f27d12013-02-06 14:57:15 +0900200 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900201}
202
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100203static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
204 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900205 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100206{
207 size_t ret = 0;
208
209 if (verbose) {
210 char o = map ? dso__symtab_origin(map->dso) : '!';
211 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900212 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100213 }
214
215 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100216 if (sym && map) {
217 if (map->type == MAP__VARIABLE) {
218 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
219 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100220 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100221 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
222 width - ret, "");
223 } else {
224 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
225 width - ret,
226 sym->name);
227 }
228 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229 size_t len = BITS_PER_LONG / 4;
230 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
231 len, ip);
232 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
233 width - ret, "");
234 }
235
236 return ret;
237}
238
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300239static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900240 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100241{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300242 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
243 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100244}
John Kacurdd68ada2009-09-24 18:02:49 +0200245
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200246struct sort_entry sort_sym = {
247 .se_header = "Symbol",
248 .se_cmp = sort__sym_cmp,
249 .se_snprintf = hist_entry__sym_snprintf,
250 .se_width_idx = HISTC_SYMBOL,
251};
John Kacurdd68ada2009-09-24 18:02:49 +0200252
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300253/* --sort srcline */
254
255static int64_t
256sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
257{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900258 if (!left->srcline) {
259 if (!left->ms.map)
260 left->srcline = SRCLINE_UNKNOWN;
261 else {
262 struct map *map = left->ms.map;
263 left->srcline = get_srcline(map->dso,
264 map__rip_2objdump(map, left->ip));
265 }
266 }
267 if (!right->srcline) {
268 if (!right->ms.map)
269 right->srcline = SRCLINE_UNKNOWN;
270 else {
271 struct map *map = right->ms.map;
272 right->srcline = get_srcline(map->dso,
273 map__rip_2objdump(map, right->ip));
274 }
275 }
276 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300277}
278
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300279static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300280 size_t size,
281 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300282{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300283 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300284}
285
286struct sort_entry sort_srcline = {
287 .se_header = "Source:Line",
288 .se_cmp = sort__srcline_cmp,
289 .se_snprintf = hist_entry__srcline_snprintf,
290 .se_width_idx = HISTC_SRCLINE,
291};
292
John Kacurdd68ada2009-09-24 18:02:49 +0200293/* --sort parent */
294
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200295static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200296sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
297{
298 struct symbol *sym_l = left->parent;
299 struct symbol *sym_r = right->parent;
300
301 if (!sym_l || !sym_r)
302 return cmp_null(sym_l, sym_r);
303
304 return strcmp(sym_l->name, sym_r->name);
305}
306
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300307static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300308 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200309{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300310 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300311 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200312}
313
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200314struct sort_entry sort_parent = {
315 .se_header = "Parent symbol",
316 .se_cmp = sort__parent_cmp,
317 .se_snprintf = hist_entry__parent_snprintf,
318 .se_width_idx = HISTC_PARENT,
319};
320
Arun Sharmaf60f3592010-06-04 11:27:10 -0300321/* --sort cpu */
322
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200323static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300324sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
325{
326 return right->cpu - left->cpu;
327}
328
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300329static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
330 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300331{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300332 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300333}
334
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200335struct sort_entry sort_cpu = {
336 .se_header = "CPU",
337 .se_cmp = sort__cpu_cmp,
338 .se_snprintf = hist_entry__cpu_snprintf,
339 .se_width_idx = HISTC_CPU,
340};
341
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900342/* sort keys for branch stacks */
343
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100344static int64_t
345sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
346{
347 return _sort__dso_cmp(left->branch_info->from.map,
348 right->branch_info->from.map);
349}
350
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300351static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100352 size_t size, unsigned int width)
353{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300354 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100355 bf, size, width);
356}
357
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100358static int64_t
359sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
360{
361 return _sort__dso_cmp(left->branch_info->to.map,
362 right->branch_info->to.map);
363}
364
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300365static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100366 size_t size, unsigned int width)
367{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300368 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100369 bf, size, width);
370}
371
372static int64_t
373sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
374{
375 struct addr_map_symbol *from_l = &left->branch_info->from;
376 struct addr_map_symbol *from_r = &right->branch_info->from;
377
378 if (!from_l->sym && !from_r->sym)
379 return right->level - left->level;
380
Namhyung Kim51f27d12013-02-06 14:57:15 +0900381 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100382}
383
384static int64_t
385sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
386{
387 struct addr_map_symbol *to_l = &left->branch_info->to;
388 struct addr_map_symbol *to_r = &right->branch_info->to;
389
390 if (!to_l->sym && !to_r->sym)
391 return right->level - left->level;
392
Namhyung Kim51f27d12013-02-06 14:57:15 +0900393 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100394}
395
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300396static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900397 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100398{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300399 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100400 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300401 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100402
403}
404
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300405static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900406 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300408 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300410 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411
412}
413
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900414struct sort_entry sort_dso_from = {
415 .se_header = "Source Shared Object",
416 .se_cmp = sort__dso_from_cmp,
417 .se_snprintf = hist_entry__dso_from_snprintf,
418 .se_width_idx = HISTC_DSO_FROM,
419};
420
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421struct sort_entry sort_dso_to = {
422 .se_header = "Target Shared Object",
423 .se_cmp = sort__dso_to_cmp,
424 .se_snprintf = hist_entry__dso_to_snprintf,
425 .se_width_idx = HISTC_DSO_TO,
426};
427
428struct sort_entry sort_sym_from = {
429 .se_header = "Source Symbol",
430 .se_cmp = sort__sym_from_cmp,
431 .se_snprintf = hist_entry__sym_from_snprintf,
432 .se_width_idx = HISTC_SYMBOL_FROM,
433};
434
435struct sort_entry sort_sym_to = {
436 .se_header = "Target Symbol",
437 .se_cmp = sort__sym_to_cmp,
438 .se_snprintf = hist_entry__sym_to_snprintf,
439 .se_width_idx = HISTC_SYMBOL_TO,
440};
441
442static int64_t
443sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
444{
445 const unsigned char mp = left->branch_info->flags.mispred !=
446 right->branch_info->flags.mispred;
447 const unsigned char p = left->branch_info->flags.predicted !=
448 right->branch_info->flags.predicted;
449
450 return mp || p;
451}
452
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300453static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100454 size_t size, unsigned int width){
455 static const char *out = "N/A";
456
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300457 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100458 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300459 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100460 out = "Y";
461
462 return repsep_snprintf(bf, size, "%-*s", width, out);
463}
464
Stephane Eranian98a3b322013-01-24 16:10:35 +0100465/* --sort daddr_sym */
466static int64_t
467sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
468{
469 uint64_t l = 0, r = 0;
470
471 if (left->mem_info)
472 l = left->mem_info->daddr.addr;
473 if (right->mem_info)
474 r = right->mem_info->daddr.addr;
475
476 return (int64_t)(r - l);
477}
478
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300479static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100480 size_t size, unsigned int width)
481{
482 uint64_t addr = 0;
483 struct map *map = NULL;
484 struct symbol *sym = NULL;
485
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300486 if (he->mem_info) {
487 addr = he->mem_info->daddr.addr;
488 map = he->mem_info->daddr.map;
489 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100490 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300491 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100492 width);
493}
494
495static int64_t
496sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
497{
498 struct map *map_l = NULL;
499 struct map *map_r = NULL;
500
501 if (left->mem_info)
502 map_l = left->mem_info->daddr.map;
503 if (right->mem_info)
504 map_r = right->mem_info->daddr.map;
505
506 return _sort__dso_cmp(map_l, map_r);
507}
508
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300509static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100510 size_t size, unsigned int width)
511{
512 struct map *map = NULL;
513
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300514 if (he->mem_info)
515 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100516
517 return _hist_entry__dso_snprintf(map, bf, size, width);
518}
519
520static int64_t
521sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
522{
523 union perf_mem_data_src data_src_l;
524 union perf_mem_data_src data_src_r;
525
526 if (left->mem_info)
527 data_src_l = left->mem_info->data_src;
528 else
529 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
530
531 if (right->mem_info)
532 data_src_r = right->mem_info->data_src;
533 else
534 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
535
536 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
537}
538
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300539static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100540 size_t size, unsigned int width)
541{
542 const char *out;
543 u64 mask = PERF_MEM_LOCK_NA;
544
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300545 if (he->mem_info)
546 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100547
548 if (mask & PERF_MEM_LOCK_NA)
549 out = "N/A";
550 else if (mask & PERF_MEM_LOCK_LOCKED)
551 out = "Yes";
552 else
553 out = "No";
554
555 return repsep_snprintf(bf, size, "%-*s", width, out);
556}
557
558static int64_t
559sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
560{
561 union perf_mem_data_src data_src_l;
562 union perf_mem_data_src data_src_r;
563
564 if (left->mem_info)
565 data_src_l = left->mem_info->data_src;
566 else
567 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
568
569 if (right->mem_info)
570 data_src_r = right->mem_info->data_src;
571 else
572 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
573
574 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
575}
576
577static const char * const tlb_access[] = {
578 "N/A",
579 "HIT",
580 "MISS",
581 "L1",
582 "L2",
583 "Walker",
584 "Fault",
585};
586#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
587
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300588static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100589 size_t size, unsigned int width)
590{
591 char out[64];
592 size_t sz = sizeof(out) - 1; /* -1 for null termination */
593 size_t l = 0, i;
594 u64 m = PERF_MEM_TLB_NA;
595 u64 hit, miss;
596
597 out[0] = '\0';
598
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300599 if (he->mem_info)
600 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100601
602 hit = m & PERF_MEM_TLB_HIT;
603 miss = m & PERF_MEM_TLB_MISS;
604
605 /* already taken care of */
606 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
607
608 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
609 if (!(m & 0x1))
610 continue;
611 if (l) {
612 strcat(out, " or ");
613 l += 4;
614 }
615 strncat(out, tlb_access[i], sz - l);
616 l += strlen(tlb_access[i]);
617 }
618 if (*out == '\0')
619 strcpy(out, "N/A");
620 if (hit)
621 strncat(out, " hit", sz - l);
622 if (miss)
623 strncat(out, " miss", sz - l);
624
625 return repsep_snprintf(bf, size, "%-*s", width, out);
626}
627
628static int64_t
629sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
630{
631 union perf_mem_data_src data_src_l;
632 union perf_mem_data_src data_src_r;
633
634 if (left->mem_info)
635 data_src_l = left->mem_info->data_src;
636 else
637 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
638
639 if (right->mem_info)
640 data_src_r = right->mem_info->data_src;
641 else
642 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
643
644 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
645}
646
647static const char * const mem_lvl[] = {
648 "N/A",
649 "HIT",
650 "MISS",
651 "L1",
652 "LFB",
653 "L2",
654 "L3",
655 "Local RAM",
656 "Remote RAM (1 hop)",
657 "Remote RAM (2 hops)",
658 "Remote Cache (1 hop)",
659 "Remote Cache (2 hops)",
660 "I/O",
661 "Uncached",
662};
663#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
664
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300665static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100666 size_t size, unsigned int width)
667{
668 char out[64];
669 size_t sz = sizeof(out) - 1; /* -1 for null termination */
670 size_t i, l = 0;
671 u64 m = PERF_MEM_LVL_NA;
672 u64 hit, miss;
673
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300674 if (he->mem_info)
675 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100676
677 out[0] = '\0';
678
679 hit = m & PERF_MEM_LVL_HIT;
680 miss = m & PERF_MEM_LVL_MISS;
681
682 /* already taken care of */
683 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
684
685 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
686 if (!(m & 0x1))
687 continue;
688 if (l) {
689 strcat(out, " or ");
690 l += 4;
691 }
692 strncat(out, mem_lvl[i], sz - l);
693 l += strlen(mem_lvl[i]);
694 }
695 if (*out == '\0')
696 strcpy(out, "N/A");
697 if (hit)
698 strncat(out, " hit", sz - l);
699 if (miss)
700 strncat(out, " miss", sz - l);
701
702 return repsep_snprintf(bf, size, "%-*s", width, out);
703}
704
705static int64_t
706sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
707{
708 union perf_mem_data_src data_src_l;
709 union perf_mem_data_src data_src_r;
710
711 if (left->mem_info)
712 data_src_l = left->mem_info->data_src;
713 else
714 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
715
716 if (right->mem_info)
717 data_src_r = right->mem_info->data_src;
718 else
719 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
720
721 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
722}
723
724static const char * const snoop_access[] = {
725 "N/A",
726 "None",
727 "Miss",
728 "Hit",
729 "HitM",
730};
731#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
732
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300733static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100734 size_t size, unsigned int width)
735{
736 char out[64];
737 size_t sz = sizeof(out) - 1; /* -1 for null termination */
738 size_t i, l = 0;
739 u64 m = PERF_MEM_SNOOP_NA;
740
741 out[0] = '\0';
742
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300743 if (he->mem_info)
744 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100745
746 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
747 if (!(m & 0x1))
748 continue;
749 if (l) {
750 strcat(out, " or ");
751 l += 4;
752 }
753 strncat(out, snoop_access[i], sz - l);
754 l += strlen(snoop_access[i]);
755 }
756
757 if (*out == '\0')
758 strcpy(out, "N/A");
759
760 return repsep_snprintf(bf, size, "%-*s", width, out);
761}
762
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100763struct sort_entry sort_mispredict = {
764 .se_header = "Branch Mispredicted",
765 .se_cmp = sort__mispredict_cmp,
766 .se_snprintf = hist_entry__mispredict_snprintf,
767 .se_width_idx = HISTC_MISPREDICT,
768};
769
Andi Kleen05484292013-01-24 16:10:29 +0100770static u64 he_weight(struct hist_entry *he)
771{
772 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
773}
774
775static int64_t
776sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
777{
778 return he_weight(left) - he_weight(right);
779}
780
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300781static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100782 size_t size, unsigned int width)
783{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300784 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100785}
786
787struct sort_entry sort_local_weight = {
788 .se_header = "Local Weight",
789 .se_cmp = sort__local_weight_cmp,
790 .se_snprintf = hist_entry__local_weight_snprintf,
791 .se_width_idx = HISTC_LOCAL_WEIGHT,
792};
793
794static int64_t
795sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 return left->stat.weight - right->stat.weight;
798}
799
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300800static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100801 size_t size, unsigned int width)
802{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300803 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100804}
805
806struct sort_entry sort_global_weight = {
807 .se_header = "Weight",
808 .se_cmp = sort__global_weight_cmp,
809 .se_snprintf = hist_entry__global_weight_snprintf,
810 .se_width_idx = HISTC_GLOBAL_WEIGHT,
811};
812
Stephane Eranian98a3b322013-01-24 16:10:35 +0100813struct sort_entry sort_mem_daddr_sym = {
814 .se_header = "Data Symbol",
815 .se_cmp = sort__daddr_cmp,
816 .se_snprintf = hist_entry__daddr_snprintf,
817 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
818};
819
820struct sort_entry sort_mem_daddr_dso = {
821 .se_header = "Data Object",
822 .se_cmp = sort__dso_daddr_cmp,
823 .se_snprintf = hist_entry__dso_daddr_snprintf,
824 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
825};
826
827struct sort_entry sort_mem_locked = {
828 .se_header = "Locked",
829 .se_cmp = sort__locked_cmp,
830 .se_snprintf = hist_entry__locked_snprintf,
831 .se_width_idx = HISTC_MEM_LOCKED,
832};
833
834struct sort_entry sort_mem_tlb = {
835 .se_header = "TLB access",
836 .se_cmp = sort__tlb_cmp,
837 .se_snprintf = hist_entry__tlb_snprintf,
838 .se_width_idx = HISTC_MEM_TLB,
839};
840
841struct sort_entry sort_mem_lvl = {
842 .se_header = "Memory access",
843 .se_cmp = sort__lvl_cmp,
844 .se_snprintf = hist_entry__lvl_snprintf,
845 .se_width_idx = HISTC_MEM_LVL,
846};
847
848struct sort_entry sort_mem_snoop = {
849 .se_header = "Snoop",
850 .se_cmp = sort__snoop_cmp,
851 .se_snprintf = hist_entry__snoop_snprintf,
852 .se_width_idx = HISTC_MEM_SNOOP,
853};
854
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700855static int64_t
856sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
857{
858 return left->branch_info->flags.abort !=
859 right->branch_info->flags.abort;
860}
861
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300862static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700863 size_t size, unsigned int width)
864{
865 static const char *out = ".";
866
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300867 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700868 out = "A";
869 return repsep_snprintf(bf, size, "%-*s", width, out);
870}
871
872struct sort_entry sort_abort = {
873 .se_header = "Transaction abort",
874 .se_cmp = sort__abort_cmp,
875 .se_snprintf = hist_entry__abort_snprintf,
876 .se_width_idx = HISTC_ABORT,
877};
878
879static int64_t
880sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
881{
882 return left->branch_info->flags.in_tx !=
883 right->branch_info->flags.in_tx;
884}
885
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300886static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700887 size_t size, unsigned int width)
888{
889 static const char *out = ".";
890
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300891 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700892 out = "T";
893
894 return repsep_snprintf(bf, size, "%-*s", width, out);
895}
896
897struct sort_entry sort_in_tx = {
898 .se_header = "Branch in transaction",
899 .se_cmp = sort__in_tx_cmp,
900 .se_snprintf = hist_entry__in_tx_snprintf,
901 .se_width_idx = HISTC_IN_TX,
902};
903
Andi Kleen475eeab2013-09-20 07:40:43 -0700904static int64_t
905sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
906{
907 return left->transaction - right->transaction;
908}
909
910static inline char *add_str(char *p, const char *str)
911{
912 strcpy(p, str);
913 return p + strlen(str);
914}
915
916static struct txbit {
917 unsigned flag;
918 const char *name;
919 int skip_for_len;
920} txbits[] = {
921 { PERF_TXN_ELISION, "EL ", 0 },
922 { PERF_TXN_TRANSACTION, "TX ", 1 },
923 { PERF_TXN_SYNC, "SYNC ", 1 },
924 { PERF_TXN_ASYNC, "ASYNC ", 0 },
925 { PERF_TXN_RETRY, "RETRY ", 0 },
926 { PERF_TXN_CONFLICT, "CON ", 0 },
927 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
928 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
929 { 0, NULL, 0 }
930};
931
932int hist_entry__transaction_len(void)
933{
934 int i;
935 int len = 0;
936
937 for (i = 0; txbits[i].name; i++) {
938 if (!txbits[i].skip_for_len)
939 len += strlen(txbits[i].name);
940 }
941 len += 4; /* :XX<space> */
942 return len;
943}
944
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300945static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700946 size_t size, unsigned int width)
947{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300948 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700949 char buf[128];
950 char *p = buf;
951 int i;
952
953 buf[0] = 0;
954 for (i = 0; txbits[i].name; i++)
955 if (txbits[i].flag & t)
956 p = add_str(p, txbits[i].name);
957 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
958 p = add_str(p, "NEITHER ");
959 if (t & PERF_TXN_ABORT_MASK) {
960 sprintf(p, ":%" PRIx64,
961 (t & PERF_TXN_ABORT_MASK) >>
962 PERF_TXN_ABORT_SHIFT);
963 p += strlen(p);
964 }
965
966 return repsep_snprintf(bf, size, "%-*s", width, buf);
967}
968
969struct sort_entry sort_transaction = {
970 .se_header = "Transaction ",
971 .se_cmp = sort__transaction_cmp,
972 .se_snprintf = hist_entry__transaction_snprintf,
973 .se_width_idx = HISTC_TRANSACTION,
974};
975
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200976struct sort_dimension {
977 const char *name;
978 struct sort_entry *entry;
979 int taken;
980};
981
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100982#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
983
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900984static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100985 DIM(SORT_PID, "pid", sort_thread),
986 DIM(SORT_COMM, "comm", sort_comm),
987 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100988 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100989 DIM(SORT_PARENT, "parent", sort_parent),
990 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300991 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -0700992 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
993 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -0700994 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200995};
996
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900997#undef DIM
998
999#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1000
1001static struct sort_dimension bstack_sort_dimensions[] = {
1002 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1003 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1004 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1005 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1006 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001007 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1008 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001009};
1010
1011#undef DIM
1012
Namhyung Kimafab87b2013-04-03 21:26:11 +09001013#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1014
1015static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001016 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1017 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1018 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1019 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1020 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1021 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1022};
1023
1024#undef DIM
1025
Namhyung Kim2f532d092013-04-03 21:26:10 +09001026static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1027{
1028 if (sd->taken)
1029 return;
1030
1031 if (sd->entry->se_collapse)
1032 sort__need_collapse = 1;
1033
1034 if (list_empty(&hist_entry__sort_list))
1035 sort__first_dimension = idx;
1036
1037 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1038 sd->taken = 1;
1039}
1040
John Kacurdd68ada2009-09-24 18:02:49 +02001041int sort_dimension__add(const char *tok)
1042{
1043 unsigned int i;
1044
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001045 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1046 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001047
John Kacurdd68ada2009-09-24 18:02:49 +02001048 if (strncasecmp(tok, sd->name, strlen(tok)))
1049 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001050
John Kacurdd68ada2009-09-24 18:02:49 +02001051 if (sd->entry == &sort_parent) {
1052 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1053 if (ret) {
1054 char err[BUFSIZ];
1055
1056 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001057 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1058 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001059 }
1060 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001061 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001062 sort__has_sym = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001063 }
1064
Namhyung Kim2f532d092013-04-03 21:26:10 +09001065 __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001066 return 0;
1067 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001068
1069 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1070 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1071
1072 if (strncasecmp(tok, sd->name, strlen(tok)))
1073 continue;
1074
Namhyung Kim55369fc2013-04-01 20:35:20 +09001075 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001076 return -EINVAL;
1077
1078 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1079 sort__has_sym = 1;
1080
Namhyung Kim2f532d092013-04-03 21:26:10 +09001081 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001082 return 0;
1083 }
1084
Namhyung Kimafab87b2013-04-03 21:26:11 +09001085 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1086 struct sort_dimension *sd = &memory_sort_dimensions[i];
1087
1088 if (strncasecmp(tok, sd->name, strlen(tok)))
1089 continue;
1090
1091 if (sort__mode != SORT_MODE__MEMORY)
1092 return -EINVAL;
1093
1094 if (sd->entry == &sort_mem_daddr_sym)
1095 sort__has_sym = 1;
1096
1097 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1098 return 0;
1099 }
1100
John Kacurdd68ada2009-09-24 18:02:49 +02001101 return -ESRCH;
1102}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001103
Namhyung Kim55309982013-02-06 14:57:16 +09001104int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001105{
1106 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +09001107 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001108
Namhyung Kim5936f542013-02-06 14:57:17 +09001109 if (str == NULL) {
1110 error("Not enough memory to setup sort keys");
1111 return -ENOMEM;
1112 }
1113
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001114 for (tok = strtok_r(str, ", ", &tmp);
1115 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001116 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001117 if (ret == -EINVAL) {
1118 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001119 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001120 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001121 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001122 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001123 }
1124 }
1125
1126 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001127 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001128}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001129
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001130static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001131 struct strlist *list,
1132 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001133{
1134 if (list && strlist__nr_entries(list) == 1) {
1135 if (fp != NULL)
1136 fprintf(fp, "# %s: %s\n", list_name,
1137 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001138 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001139 }
1140}
Namhyung Kim08e71542013-04-03 21:26:19 +09001141
1142void sort__setup_elide(FILE *output)
1143{
1144 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1145 "dso", output);
1146 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1147 "comm", output);
1148 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1149 "symbol", output);
1150
1151 if (sort__mode == SORT_MODE__BRANCH) {
1152 sort_entry__setup_elide(&sort_dso_from,
1153 symbol_conf.dso_from_list,
1154 "dso_from", output);
1155 sort_entry__setup_elide(&sort_dso_to,
1156 symbol_conf.dso_to_list,
1157 "dso_to", output);
1158 sort_entry__setup_elide(&sort_sym_from,
1159 symbol_conf.sym_from_list,
1160 "sym_from", output);
1161 sort_entry__setup_elide(&sort_sym_to,
1162 symbol_conf.sym_to_list,
1163 "sym_to", output);
1164 } else if (sort__mode == SORT_MODE__MEMORY) {
1165 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1166 "symbol_daddr", output);
1167 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1168 "dso_daddr", output);
1169 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1170 "mem", output);
1171 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1172 "local_weight", output);
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "tlb", output);
1175 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1176 "snoop", output);
1177 }
1178
1179}