blob: 835e8bdd869f9bed27e074ee3e770e8fe7e0444b [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{
Adrian Hunter38051232013-07-04 16:20:31 +030083 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020084}
85
86static int64_t
87sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
88{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020089 const char *comm_l = thread__comm_str(left->thread);
90 const char *comm_r = thread__comm_str(right->thread);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020091
92 if (!comm_l || !comm_r)
93 return cmp_null(comm_l, comm_r);
94
95 return strcmp(comm_l, comm_r);
96}
97
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030098static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030099 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200100{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +0200101 return repsep_snprintf(bf, size, "%*s", width, thread__comm_str(he->thread));
John Kacurdd68ada2009-09-24 18:02:49 +0200102}
103
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900104struct sort_entry sort_comm = {
105 .se_header = "Command",
106 .se_cmp = sort__comm_cmp,
107 .se_collapse = sort__comm_collapse,
108 .se_snprintf = hist_entry__comm_snprintf,
109 .se_width_idx = HISTC_COMM,
110};
111
112/* --sort dso */
113
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100114static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200115{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100116 struct dso *dso_l = map_l ? map_l->dso : NULL;
117 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300118 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200119
120 if (!dso_l || !dso_r)
121 return cmp_null(dso_l, dso_r);
122
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300123 if (verbose) {
124 dso_name_l = dso_l->long_name;
125 dso_name_r = dso_r->long_name;
126 } else {
127 dso_name_l = dso_l->short_name;
128 dso_name_r = dso_r->short_name;
129 }
130
131 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200132}
133
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100134static int64_t
135sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200136{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100137 return _sort__dso_cmp(left->ms.map, right->ms.map);
138}
139
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100140static int _hist_entry__dso_snprintf(struct map *map, char *bf,
141 size_t size, unsigned int width)
142{
143 if (map && map->dso) {
144 const char *dso_name = !verbose ? map->dso->short_name :
145 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300146 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300147 }
John Kacurdd68ada2009-09-24 18:02:49 +0200148
Ian Munsie1437a302010-12-06 13:37:04 +1100149 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200150}
151
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300152static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100153 size_t size, unsigned int width)
154{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300155 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100156}
157
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900158struct sort_entry sort_dso = {
159 .se_header = "Shared Object",
160 .se_cmp = sort__dso_cmp,
161 .se_snprintf = hist_entry__dso_snprintf,
162 .se_width_idx = HISTC_DSO,
163};
164
165/* --sort symbol */
166
Namhyung Kim51f27d12013-02-06 14:57:15 +0900167static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900168{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900169 u64 ip_l, ip_r;
170
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900171 if (!sym_l || !sym_r)
172 return cmp_null(sym_l, sym_r);
173
174 if (sym_l == sym_r)
175 return 0;
176
177 ip_l = sym_l->start;
178 ip_r = sym_r->start;
179
180 return (int64_t)(ip_r - ip_l);
181}
182
183static int64_t
184sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
185{
Namhyung Kim09600e02013-10-15 11:01:56 +0900186 int64_t ret;
187
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900188 if (!left->ms.sym && !right->ms.sym)
189 return right->level - left->level;
190
Namhyung Kim09600e02013-10-15 11:01:56 +0900191 /*
192 * comparing symbol address alone is not enough since it's a
193 * relative address within a dso.
194 */
195 ret = sort__dso_cmp(left, right);
196 if (ret != 0)
197 return ret;
198
Namhyung Kim51f27d12013-02-06 14:57:15 +0900199 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900200}
201
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100202static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
203 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900204 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100205{
206 size_t ret = 0;
207
208 if (verbose) {
209 char o = map ? dso__symtab_origin(map->dso) : '!';
210 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900211 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100212 }
213
214 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100215 if (sym && map) {
216 if (map->type == MAP__VARIABLE) {
217 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
218 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100219 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100220 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
221 width - ret, "");
222 } else {
223 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
224 width - ret,
225 sym->name);
226 }
227 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100228 size_t len = BITS_PER_LONG / 4;
229 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
230 len, ip);
231 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
232 width - ret, "");
233 }
234
235 return ret;
236}
237
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300238static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900239 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100240{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300241 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
242 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100243}
John Kacurdd68ada2009-09-24 18:02:49 +0200244
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200245struct sort_entry sort_sym = {
246 .se_header = "Symbol",
247 .se_cmp = sort__sym_cmp,
248 .se_snprintf = hist_entry__sym_snprintf,
249 .se_width_idx = HISTC_SYMBOL,
250};
John Kacurdd68ada2009-09-24 18:02:49 +0200251
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300252/* --sort srcline */
253
254static int64_t
255sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
256{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900257 if (!left->srcline) {
258 if (!left->ms.map)
259 left->srcline = SRCLINE_UNKNOWN;
260 else {
261 struct map *map = left->ms.map;
262 left->srcline = get_srcline(map->dso,
263 map__rip_2objdump(map, left->ip));
264 }
265 }
266 if (!right->srcline) {
267 if (!right->ms.map)
268 right->srcline = SRCLINE_UNKNOWN;
269 else {
270 struct map *map = right->ms.map;
271 right->srcline = get_srcline(map->dso,
272 map__rip_2objdump(map, right->ip));
273 }
274 }
275 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300276}
277
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300278static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300279 size_t size,
280 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300281{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300282 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300283}
284
285struct sort_entry sort_srcline = {
286 .se_header = "Source:Line",
287 .se_cmp = sort__srcline_cmp,
288 .se_snprintf = hist_entry__srcline_snprintf,
289 .se_width_idx = HISTC_SRCLINE,
290};
291
John Kacurdd68ada2009-09-24 18:02:49 +0200292/* --sort parent */
293
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200294static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200295sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
296{
297 struct symbol *sym_l = left->parent;
298 struct symbol *sym_r = right->parent;
299
300 if (!sym_l || !sym_r)
301 return cmp_null(sym_l, sym_r);
302
303 return strcmp(sym_l->name, sym_r->name);
304}
305
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300306static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300307 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200308{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300309 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300310 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200311}
312
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200313struct sort_entry sort_parent = {
314 .se_header = "Parent symbol",
315 .se_cmp = sort__parent_cmp,
316 .se_snprintf = hist_entry__parent_snprintf,
317 .se_width_idx = HISTC_PARENT,
318};
319
Arun Sharmaf60f3592010-06-04 11:27:10 -0300320/* --sort cpu */
321
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200322static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300323sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
324{
325 return right->cpu - left->cpu;
326}
327
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300328static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
329 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300330{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300331 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300332}
333
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200334struct sort_entry sort_cpu = {
335 .se_header = "CPU",
336 .se_cmp = sort__cpu_cmp,
337 .se_snprintf = hist_entry__cpu_snprintf,
338 .se_width_idx = HISTC_CPU,
339};
340
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900341/* sort keys for branch stacks */
342
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100343static int64_t
344sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
345{
346 return _sort__dso_cmp(left->branch_info->from.map,
347 right->branch_info->from.map);
348}
349
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300350static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100351 size_t size, unsigned int width)
352{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300353 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100354 bf, size, width);
355}
356
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100357static int64_t
358sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
359{
360 return _sort__dso_cmp(left->branch_info->to.map,
361 right->branch_info->to.map);
362}
363
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300364static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100365 size_t size, unsigned int width)
366{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300367 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100368 bf, size, width);
369}
370
371static int64_t
372sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
373{
374 struct addr_map_symbol *from_l = &left->branch_info->from;
375 struct addr_map_symbol *from_r = &right->branch_info->from;
376
377 if (!from_l->sym && !from_r->sym)
378 return right->level - left->level;
379
Namhyung Kim51f27d12013-02-06 14:57:15 +0900380 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100381}
382
383static int64_t
384sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 struct addr_map_symbol *to_l = &left->branch_info->to;
387 struct addr_map_symbol *to_r = &right->branch_info->to;
388
389 if (!to_l->sym && !to_r->sym)
390 return right->level - left->level;
391
Namhyung Kim51f27d12013-02-06 14:57:15 +0900392 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393}
394
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300395static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900396 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100397{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300398 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100399 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300400 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100401
402}
403
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300404static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900405 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100406{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300407 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100408 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300409 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100410
411}
412
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900413struct sort_entry sort_dso_from = {
414 .se_header = "Source Shared Object",
415 .se_cmp = sort__dso_from_cmp,
416 .se_snprintf = hist_entry__dso_from_snprintf,
417 .se_width_idx = HISTC_DSO_FROM,
418};
419
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100420struct sort_entry sort_dso_to = {
421 .se_header = "Target Shared Object",
422 .se_cmp = sort__dso_to_cmp,
423 .se_snprintf = hist_entry__dso_to_snprintf,
424 .se_width_idx = HISTC_DSO_TO,
425};
426
427struct sort_entry sort_sym_from = {
428 .se_header = "Source Symbol",
429 .se_cmp = sort__sym_from_cmp,
430 .se_snprintf = hist_entry__sym_from_snprintf,
431 .se_width_idx = HISTC_SYMBOL_FROM,
432};
433
434struct sort_entry sort_sym_to = {
435 .se_header = "Target Symbol",
436 .se_cmp = sort__sym_to_cmp,
437 .se_snprintf = hist_entry__sym_to_snprintf,
438 .se_width_idx = HISTC_SYMBOL_TO,
439};
440
441static int64_t
442sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
443{
444 const unsigned char mp = left->branch_info->flags.mispred !=
445 right->branch_info->flags.mispred;
446 const unsigned char p = left->branch_info->flags.predicted !=
447 right->branch_info->flags.predicted;
448
449 return mp || p;
450}
451
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300452static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100453 size_t size, unsigned int width){
454 static const char *out = "N/A";
455
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300456 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100457 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300458 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100459 out = "Y";
460
461 return repsep_snprintf(bf, size, "%-*s", width, out);
462}
463
Stephane Eranian98a3b322013-01-24 16:10:35 +0100464/* --sort daddr_sym */
465static int64_t
466sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
467{
468 uint64_t l = 0, r = 0;
469
470 if (left->mem_info)
471 l = left->mem_info->daddr.addr;
472 if (right->mem_info)
473 r = right->mem_info->daddr.addr;
474
475 return (int64_t)(r - l);
476}
477
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300478static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100479 size_t size, unsigned int width)
480{
481 uint64_t addr = 0;
482 struct map *map = NULL;
483 struct symbol *sym = NULL;
484
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300485 if (he->mem_info) {
486 addr = he->mem_info->daddr.addr;
487 map = he->mem_info->daddr.map;
488 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100489 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300490 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100491 width);
492}
493
494static int64_t
495sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
496{
497 struct map *map_l = NULL;
498 struct map *map_r = NULL;
499
500 if (left->mem_info)
501 map_l = left->mem_info->daddr.map;
502 if (right->mem_info)
503 map_r = right->mem_info->daddr.map;
504
505 return _sort__dso_cmp(map_l, map_r);
506}
507
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300508static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100509 size_t size, unsigned int width)
510{
511 struct map *map = NULL;
512
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300513 if (he->mem_info)
514 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100515
516 return _hist_entry__dso_snprintf(map, bf, size, width);
517}
518
519static int64_t
520sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
521{
522 union perf_mem_data_src data_src_l;
523 union perf_mem_data_src data_src_r;
524
525 if (left->mem_info)
526 data_src_l = left->mem_info->data_src;
527 else
528 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
529
530 if (right->mem_info)
531 data_src_r = right->mem_info->data_src;
532 else
533 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
534
535 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
536}
537
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300538static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100539 size_t size, unsigned int width)
540{
541 const char *out;
542 u64 mask = PERF_MEM_LOCK_NA;
543
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300544 if (he->mem_info)
545 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100546
547 if (mask & PERF_MEM_LOCK_NA)
548 out = "N/A";
549 else if (mask & PERF_MEM_LOCK_LOCKED)
550 out = "Yes";
551 else
552 out = "No";
553
554 return repsep_snprintf(bf, size, "%-*s", width, out);
555}
556
557static int64_t
558sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
559{
560 union perf_mem_data_src data_src_l;
561 union perf_mem_data_src data_src_r;
562
563 if (left->mem_info)
564 data_src_l = left->mem_info->data_src;
565 else
566 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
567
568 if (right->mem_info)
569 data_src_r = right->mem_info->data_src;
570 else
571 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
572
573 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
574}
575
576static const char * const tlb_access[] = {
577 "N/A",
578 "HIT",
579 "MISS",
580 "L1",
581 "L2",
582 "Walker",
583 "Fault",
584};
585#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
586
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300587static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100588 size_t size, unsigned int width)
589{
590 char out[64];
591 size_t sz = sizeof(out) - 1; /* -1 for null termination */
592 size_t l = 0, i;
593 u64 m = PERF_MEM_TLB_NA;
594 u64 hit, miss;
595
596 out[0] = '\0';
597
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300598 if (he->mem_info)
599 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100600
601 hit = m & PERF_MEM_TLB_HIT;
602 miss = m & PERF_MEM_TLB_MISS;
603
604 /* already taken care of */
605 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
606
607 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
608 if (!(m & 0x1))
609 continue;
610 if (l) {
611 strcat(out, " or ");
612 l += 4;
613 }
614 strncat(out, tlb_access[i], sz - l);
615 l += strlen(tlb_access[i]);
616 }
617 if (*out == '\0')
618 strcpy(out, "N/A");
619 if (hit)
620 strncat(out, " hit", sz - l);
621 if (miss)
622 strncat(out, " miss", sz - l);
623
624 return repsep_snprintf(bf, size, "%-*s", width, out);
625}
626
627static int64_t
628sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
629{
630 union perf_mem_data_src data_src_l;
631 union perf_mem_data_src data_src_r;
632
633 if (left->mem_info)
634 data_src_l = left->mem_info->data_src;
635 else
636 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
637
638 if (right->mem_info)
639 data_src_r = right->mem_info->data_src;
640 else
641 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
642
643 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
644}
645
646static const char * const mem_lvl[] = {
647 "N/A",
648 "HIT",
649 "MISS",
650 "L1",
651 "LFB",
652 "L2",
653 "L3",
654 "Local RAM",
655 "Remote RAM (1 hop)",
656 "Remote RAM (2 hops)",
657 "Remote Cache (1 hop)",
658 "Remote Cache (2 hops)",
659 "I/O",
660 "Uncached",
661};
662#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
663
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300664static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100665 size_t size, unsigned int width)
666{
667 char out[64];
668 size_t sz = sizeof(out) - 1; /* -1 for null termination */
669 size_t i, l = 0;
670 u64 m = PERF_MEM_LVL_NA;
671 u64 hit, miss;
672
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300673 if (he->mem_info)
674 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100675
676 out[0] = '\0';
677
678 hit = m & PERF_MEM_LVL_HIT;
679 miss = m & PERF_MEM_LVL_MISS;
680
681 /* already taken care of */
682 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
683
684 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
685 if (!(m & 0x1))
686 continue;
687 if (l) {
688 strcat(out, " or ");
689 l += 4;
690 }
691 strncat(out, mem_lvl[i], sz - l);
692 l += strlen(mem_lvl[i]);
693 }
694 if (*out == '\0')
695 strcpy(out, "N/A");
696 if (hit)
697 strncat(out, " hit", sz - l);
698 if (miss)
699 strncat(out, " miss", sz - l);
700
701 return repsep_snprintf(bf, size, "%-*s", width, out);
702}
703
704static int64_t
705sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
706{
707 union perf_mem_data_src data_src_l;
708 union perf_mem_data_src data_src_r;
709
710 if (left->mem_info)
711 data_src_l = left->mem_info->data_src;
712 else
713 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
714
715 if (right->mem_info)
716 data_src_r = right->mem_info->data_src;
717 else
718 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
719
720 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
721}
722
723static const char * const snoop_access[] = {
724 "N/A",
725 "None",
726 "Miss",
727 "Hit",
728 "HitM",
729};
730#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
731
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300732static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100733 size_t size, unsigned int width)
734{
735 char out[64];
736 size_t sz = sizeof(out) - 1; /* -1 for null termination */
737 size_t i, l = 0;
738 u64 m = PERF_MEM_SNOOP_NA;
739
740 out[0] = '\0';
741
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300742 if (he->mem_info)
743 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100744
745 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
746 if (!(m & 0x1))
747 continue;
748 if (l) {
749 strcat(out, " or ");
750 l += 4;
751 }
752 strncat(out, snoop_access[i], sz - l);
753 l += strlen(snoop_access[i]);
754 }
755
756 if (*out == '\0')
757 strcpy(out, "N/A");
758
759 return repsep_snprintf(bf, size, "%-*s", width, out);
760}
761
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100762struct sort_entry sort_mispredict = {
763 .se_header = "Branch Mispredicted",
764 .se_cmp = sort__mispredict_cmp,
765 .se_snprintf = hist_entry__mispredict_snprintf,
766 .se_width_idx = HISTC_MISPREDICT,
767};
768
Andi Kleen05484292013-01-24 16:10:29 +0100769static u64 he_weight(struct hist_entry *he)
770{
771 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
772}
773
774static int64_t
775sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
776{
777 return he_weight(left) - he_weight(right);
778}
779
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300780static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100781 size_t size, unsigned int width)
782{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300783 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100784}
785
786struct sort_entry sort_local_weight = {
787 .se_header = "Local Weight",
788 .se_cmp = sort__local_weight_cmp,
789 .se_snprintf = hist_entry__local_weight_snprintf,
790 .se_width_idx = HISTC_LOCAL_WEIGHT,
791};
792
793static int64_t
794sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
795{
796 return left->stat.weight - right->stat.weight;
797}
798
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300799static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100800 size_t size, unsigned int width)
801{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300802 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100803}
804
805struct sort_entry sort_global_weight = {
806 .se_header = "Weight",
807 .se_cmp = sort__global_weight_cmp,
808 .se_snprintf = hist_entry__global_weight_snprintf,
809 .se_width_idx = HISTC_GLOBAL_WEIGHT,
810};
811
Stephane Eranian98a3b322013-01-24 16:10:35 +0100812struct sort_entry sort_mem_daddr_sym = {
813 .se_header = "Data Symbol",
814 .se_cmp = sort__daddr_cmp,
815 .se_snprintf = hist_entry__daddr_snprintf,
816 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
817};
818
819struct sort_entry sort_mem_daddr_dso = {
820 .se_header = "Data Object",
821 .se_cmp = sort__dso_daddr_cmp,
822 .se_snprintf = hist_entry__dso_daddr_snprintf,
823 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
824};
825
826struct sort_entry sort_mem_locked = {
827 .se_header = "Locked",
828 .se_cmp = sort__locked_cmp,
829 .se_snprintf = hist_entry__locked_snprintf,
830 .se_width_idx = HISTC_MEM_LOCKED,
831};
832
833struct sort_entry sort_mem_tlb = {
834 .se_header = "TLB access",
835 .se_cmp = sort__tlb_cmp,
836 .se_snprintf = hist_entry__tlb_snprintf,
837 .se_width_idx = HISTC_MEM_TLB,
838};
839
840struct sort_entry sort_mem_lvl = {
841 .se_header = "Memory access",
842 .se_cmp = sort__lvl_cmp,
843 .se_snprintf = hist_entry__lvl_snprintf,
844 .se_width_idx = HISTC_MEM_LVL,
845};
846
847struct sort_entry sort_mem_snoop = {
848 .se_header = "Snoop",
849 .se_cmp = sort__snoop_cmp,
850 .se_snprintf = hist_entry__snoop_snprintf,
851 .se_width_idx = HISTC_MEM_SNOOP,
852};
853
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700854static int64_t
855sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
856{
857 return left->branch_info->flags.abort !=
858 right->branch_info->flags.abort;
859}
860
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300861static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700862 size_t size, unsigned int width)
863{
864 static const char *out = ".";
865
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300866 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700867 out = "A";
868 return repsep_snprintf(bf, size, "%-*s", width, out);
869}
870
871struct sort_entry sort_abort = {
872 .se_header = "Transaction abort",
873 .se_cmp = sort__abort_cmp,
874 .se_snprintf = hist_entry__abort_snprintf,
875 .se_width_idx = HISTC_ABORT,
876};
877
878static int64_t
879sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
880{
881 return left->branch_info->flags.in_tx !=
882 right->branch_info->flags.in_tx;
883}
884
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300885static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700886 size_t size, unsigned int width)
887{
888 static const char *out = ".";
889
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300890 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700891 out = "T";
892
893 return repsep_snprintf(bf, size, "%-*s", width, out);
894}
895
896struct sort_entry sort_in_tx = {
897 .se_header = "Branch in transaction",
898 .se_cmp = sort__in_tx_cmp,
899 .se_snprintf = hist_entry__in_tx_snprintf,
900 .se_width_idx = HISTC_IN_TX,
901};
902
Andi Kleen475eeab2013-09-20 07:40:43 -0700903static int64_t
904sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
905{
906 return left->transaction - right->transaction;
907}
908
909static inline char *add_str(char *p, const char *str)
910{
911 strcpy(p, str);
912 return p + strlen(str);
913}
914
915static struct txbit {
916 unsigned flag;
917 const char *name;
918 int skip_for_len;
919} txbits[] = {
920 { PERF_TXN_ELISION, "EL ", 0 },
921 { PERF_TXN_TRANSACTION, "TX ", 1 },
922 { PERF_TXN_SYNC, "SYNC ", 1 },
923 { PERF_TXN_ASYNC, "ASYNC ", 0 },
924 { PERF_TXN_RETRY, "RETRY ", 0 },
925 { PERF_TXN_CONFLICT, "CON ", 0 },
926 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
927 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
928 { 0, NULL, 0 }
929};
930
931int hist_entry__transaction_len(void)
932{
933 int i;
934 int len = 0;
935
936 for (i = 0; txbits[i].name; i++) {
937 if (!txbits[i].skip_for_len)
938 len += strlen(txbits[i].name);
939 }
940 len += 4; /* :XX<space> */
941 return len;
942}
943
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300944static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700945 size_t size, unsigned int width)
946{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300947 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700948 char buf[128];
949 char *p = buf;
950 int i;
951
952 buf[0] = 0;
953 for (i = 0; txbits[i].name; i++)
954 if (txbits[i].flag & t)
955 p = add_str(p, txbits[i].name);
956 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
957 p = add_str(p, "NEITHER ");
958 if (t & PERF_TXN_ABORT_MASK) {
959 sprintf(p, ":%" PRIx64,
960 (t & PERF_TXN_ABORT_MASK) >>
961 PERF_TXN_ABORT_SHIFT);
962 p += strlen(p);
963 }
964
965 return repsep_snprintf(bf, size, "%-*s", width, buf);
966}
967
968struct sort_entry sort_transaction = {
969 .se_header = "Transaction ",
970 .se_cmp = sort__transaction_cmp,
971 .se_snprintf = hist_entry__transaction_snprintf,
972 .se_width_idx = HISTC_TRANSACTION,
973};
974
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200975struct sort_dimension {
976 const char *name;
977 struct sort_entry *entry;
978 int taken;
979};
980
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100981#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
982
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900983static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100984 DIM(SORT_PID, "pid", sort_thread),
985 DIM(SORT_COMM, "comm", sort_comm),
986 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100987 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100988 DIM(SORT_PARENT, "parent", sort_parent),
989 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300990 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -0700991 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
992 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -0700993 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200994};
995
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900996#undef DIM
997
998#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
999
1000static struct sort_dimension bstack_sort_dimensions[] = {
1001 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1002 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1003 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1004 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1005 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001006 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1007 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001008};
1009
1010#undef DIM
1011
Namhyung Kimafab87b2013-04-03 21:26:11 +09001012#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1013
1014static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001015 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1016 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1017 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1018 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1019 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1020 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1021};
1022
1023#undef DIM
1024
Namhyung Kim2f532d02013-04-03 21:26:10 +09001025static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1026{
1027 if (sd->taken)
1028 return;
1029
1030 if (sd->entry->se_collapse)
1031 sort__need_collapse = 1;
1032
1033 if (list_empty(&hist_entry__sort_list))
1034 sort__first_dimension = idx;
1035
1036 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1037 sd->taken = 1;
1038}
1039
John Kacurdd68ada2009-09-24 18:02:49 +02001040int sort_dimension__add(const char *tok)
1041{
1042 unsigned int i;
1043
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001044 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1045 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001046
John Kacurdd68ada2009-09-24 18:02:49 +02001047 if (strncasecmp(tok, sd->name, strlen(tok)))
1048 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001049
John Kacurdd68ada2009-09-24 18:02:49 +02001050 if (sd->entry == &sort_parent) {
1051 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1052 if (ret) {
1053 char err[BUFSIZ];
1054
1055 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001056 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1057 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001058 }
1059 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001060 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001061 sort__has_sym = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001062 }
1063
Namhyung Kim2f532d02013-04-03 21:26:10 +09001064 __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001065 return 0;
1066 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001067
1068 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1069 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1070
1071 if (strncasecmp(tok, sd->name, strlen(tok)))
1072 continue;
1073
Namhyung Kim55369fc2013-04-01 20:35:20 +09001074 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001075 return -EINVAL;
1076
1077 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1078 sort__has_sym = 1;
1079
Namhyung Kim2f532d02013-04-03 21:26:10 +09001080 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001081 return 0;
1082 }
1083
Namhyung Kimafab87b2013-04-03 21:26:11 +09001084 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1085 struct sort_dimension *sd = &memory_sort_dimensions[i];
1086
1087 if (strncasecmp(tok, sd->name, strlen(tok)))
1088 continue;
1089
1090 if (sort__mode != SORT_MODE__MEMORY)
1091 return -EINVAL;
1092
1093 if (sd->entry == &sort_mem_daddr_sym)
1094 sort__has_sym = 1;
1095
1096 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1097 return 0;
1098 }
1099
John Kacurdd68ada2009-09-24 18:02:49 +02001100 return -ESRCH;
1101}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001102
Namhyung Kim55309982013-02-06 14:57:16 +09001103int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001104{
1105 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +09001106 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001107
Namhyung Kim5936f542013-02-06 14:57:17 +09001108 if (str == NULL) {
1109 error("Not enough memory to setup sort keys");
1110 return -ENOMEM;
1111 }
1112
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001113 for (tok = strtok_r(str, ", ", &tmp);
1114 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001115 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001116 if (ret == -EINVAL) {
1117 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001118 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001119 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001120 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001121 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001122 }
1123 }
1124
1125 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001126 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001127}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001128
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001129static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001130 struct strlist *list,
1131 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001132{
1133 if (list && strlist__nr_entries(list) == 1) {
1134 if (fp != NULL)
1135 fprintf(fp, "# %s: %s\n", list_name,
1136 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001137 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001138 }
1139}
Namhyung Kim08e71542013-04-03 21:26:19 +09001140
1141void sort__setup_elide(FILE *output)
1142{
1143 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1144 "dso", output);
1145 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1146 "comm", output);
1147 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1148 "symbol", output);
1149
1150 if (sort__mode == SORT_MODE__BRANCH) {
1151 sort_entry__setup_elide(&sort_dso_from,
1152 symbol_conf.dso_from_list,
1153 "dso_from", output);
1154 sort_entry__setup_elide(&sort_dso_to,
1155 symbol_conf.dso_to_list,
1156 "dso_to", output);
1157 sort_entry__setup_elide(&sort_sym_from,
1158 symbol_conf.sym_from_list,
1159 "sym_from", output);
1160 sort_entry__setup_elide(&sort_sym_to,
1161 symbol_conf.sym_to_list,
1162 "sym_to", output);
1163 } else if (sort__mode == SORT_MODE__MEMORY) {
1164 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1165 "symbol_daddr", output);
1166 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1167 "dso_daddr", output);
1168 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1169 "mem", output);
1170 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1171 "local_weight", output);
1172 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1173 "tlb", output);
1174 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1175 "snoop", output);
1176 }
1177
1178}