blob: 19b4aa279d1ee1d1257136bd67b3aa20e07beaf5 [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 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{
Namhyung Kimfb29a332012-12-27 18:11:40 +090066 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030067 he->thread->comm ?: "", he->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 Meloc824c432013-10-22 19:01:31 -030097static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030098 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020099{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300100 return repsep_snprintf(bf, size, "%*s", width, he->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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300151static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100152 size_t size, unsigned int width)
153{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300154 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100155}
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 Kim09600e02013-10-15 11:01:56 +0900185 int64_t ret;
186
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187 if (!left->ms.sym && !right->ms.sym)
188 return right->level - left->level;
189
Namhyung Kim09600e02013-10-15 11:01:56 +0900190 /*
191 * comparing symbol address alone is not enough since it's a
192 * relative address within a dso.
193 */
194 ret = sort__dso_cmp(left, right);
195 if (ret != 0)
196 return ret;
197
Namhyung Kim51f27d12013-02-06 14:57:15 +0900198 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900199}
200
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100201static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
202 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900203 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100204{
205 size_t ret = 0;
206
207 if (verbose) {
208 char o = map ? dso__symtab_origin(map->dso) : '!';
209 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900210 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100211 }
212
213 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100214 if (sym && map) {
215 if (map->type == MAP__VARIABLE) {
216 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
217 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100218 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100219 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
220 width - ret, "");
221 } else {
222 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
223 width - ret,
224 sym->name);
225 }
226 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100227 size_t len = BITS_PER_LONG / 4;
228 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
229 len, ip);
230 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
231 width - ret, "");
232 }
233
234 return ret;
235}
236
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300237static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900238 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300240 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
241 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100242}
John Kacurdd68ada2009-09-24 18:02:49 +0200243
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200244struct sort_entry sort_sym = {
245 .se_header = "Symbol",
246 .se_cmp = sort__sym_cmp,
247 .se_snprintf = hist_entry__sym_snprintf,
248 .se_width_idx = HISTC_SYMBOL,
249};
John Kacurdd68ada2009-09-24 18:02:49 +0200250
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300251/* --sort srcline */
252
253static int64_t
254sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
255{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900256 if (!left->srcline) {
257 if (!left->ms.map)
258 left->srcline = SRCLINE_UNKNOWN;
259 else {
260 struct map *map = left->ms.map;
261 left->srcline = get_srcline(map->dso,
262 map__rip_2objdump(map, left->ip));
263 }
264 }
265 if (!right->srcline) {
266 if (!right->ms.map)
267 right->srcline = SRCLINE_UNKNOWN;
268 else {
269 struct map *map = right->ms.map;
270 right->srcline = get_srcline(map->dso,
271 map__rip_2objdump(map, right->ip));
272 }
273 }
274 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300275}
276
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300277static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300278 size_t size,
279 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300280{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300281 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300282}
283
284struct sort_entry sort_srcline = {
285 .se_header = "Source:Line",
286 .se_cmp = sort__srcline_cmp,
287 .se_snprintf = hist_entry__srcline_snprintf,
288 .se_width_idx = HISTC_SRCLINE,
289};
290
John Kacurdd68ada2009-09-24 18:02:49 +0200291/* --sort parent */
292
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200293static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200294sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
295{
296 struct symbol *sym_l = left->parent;
297 struct symbol *sym_r = right->parent;
298
299 if (!sym_l || !sym_r)
300 return cmp_null(sym_l, sym_r);
301
302 return strcmp(sym_l->name, sym_r->name);
303}
304
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300305static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300306 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200307{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300308 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300309 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200310}
311
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200312struct sort_entry sort_parent = {
313 .se_header = "Parent symbol",
314 .se_cmp = sort__parent_cmp,
315 .se_snprintf = hist_entry__parent_snprintf,
316 .se_width_idx = HISTC_PARENT,
317};
318
Arun Sharmaf60f3592010-06-04 11:27:10 -0300319/* --sort cpu */
320
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200321static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300322sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
323{
324 return right->cpu - left->cpu;
325}
326
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300327static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
328 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300329{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300330 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300331}
332
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200333struct sort_entry sort_cpu = {
334 .se_header = "CPU",
335 .se_cmp = sort__cpu_cmp,
336 .se_snprintf = hist_entry__cpu_snprintf,
337 .se_width_idx = HISTC_CPU,
338};
339
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900340/* sort keys for branch stacks */
341
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100342static int64_t
343sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
344{
345 return _sort__dso_cmp(left->branch_info->from.map,
346 right->branch_info->from.map);
347}
348
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300349static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100350 size_t size, unsigned int width)
351{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300352 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100353 bf, size, width);
354}
355
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100356static int64_t
357sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
358{
359 return _sort__dso_cmp(left->branch_info->to.map,
360 right->branch_info->to.map);
361}
362
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300363static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100364 size_t size, unsigned int width)
365{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300366 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100367 bf, size, width);
368}
369
370static int64_t
371sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
372{
373 struct addr_map_symbol *from_l = &left->branch_info->from;
374 struct addr_map_symbol *from_r = &right->branch_info->from;
375
376 if (!from_l->sym && !from_r->sym)
377 return right->level - left->level;
378
Namhyung Kim51f27d12013-02-06 14:57:15 +0900379 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100380}
381
382static int64_t
383sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
384{
385 struct addr_map_symbol *to_l = &left->branch_info->to;
386 struct addr_map_symbol *to_r = &right->branch_info->to;
387
388 if (!to_l->sym && !to_r->sym)
389 return right->level - left->level;
390
Namhyung Kim51f27d12013-02-06 14:57:15 +0900391 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100392}
393
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300394static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900395 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100396{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100398 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300399 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100400
401}
402
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300403static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900404 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100405{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300406 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300408 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409
410}
411
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900412struct sort_entry sort_dso_from = {
413 .se_header = "Source Shared Object",
414 .se_cmp = sort__dso_from_cmp,
415 .se_snprintf = hist_entry__dso_from_snprintf,
416 .se_width_idx = HISTC_DSO_FROM,
417};
418
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100419struct sort_entry sort_dso_to = {
420 .se_header = "Target Shared Object",
421 .se_cmp = sort__dso_to_cmp,
422 .se_snprintf = hist_entry__dso_to_snprintf,
423 .se_width_idx = HISTC_DSO_TO,
424};
425
426struct sort_entry sort_sym_from = {
427 .se_header = "Source Symbol",
428 .se_cmp = sort__sym_from_cmp,
429 .se_snprintf = hist_entry__sym_from_snprintf,
430 .se_width_idx = HISTC_SYMBOL_FROM,
431};
432
433struct sort_entry sort_sym_to = {
434 .se_header = "Target Symbol",
435 .se_cmp = sort__sym_to_cmp,
436 .se_snprintf = hist_entry__sym_to_snprintf,
437 .se_width_idx = HISTC_SYMBOL_TO,
438};
439
440static int64_t
441sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
442{
443 const unsigned char mp = left->branch_info->flags.mispred !=
444 right->branch_info->flags.mispred;
445 const unsigned char p = left->branch_info->flags.predicted !=
446 right->branch_info->flags.predicted;
447
448 return mp || p;
449}
450
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300451static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100452 size_t size, unsigned int width){
453 static const char *out = "N/A";
454
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300455 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100456 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300457 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100458 out = "Y";
459
460 return repsep_snprintf(bf, size, "%-*s", width, out);
461}
462
Stephane Eranian98a3b322013-01-24 16:10:35 +0100463/* --sort daddr_sym */
464static int64_t
465sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
466{
467 uint64_t l = 0, r = 0;
468
469 if (left->mem_info)
470 l = left->mem_info->daddr.addr;
471 if (right->mem_info)
472 r = right->mem_info->daddr.addr;
473
474 return (int64_t)(r - l);
475}
476
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300477static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100478 size_t size, unsigned int width)
479{
480 uint64_t addr = 0;
481 struct map *map = NULL;
482 struct symbol *sym = NULL;
483
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300484 if (he->mem_info) {
485 addr = he->mem_info->daddr.addr;
486 map = he->mem_info->daddr.map;
487 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100488 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300489 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100490 width);
491}
492
493static int64_t
494sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
495{
496 struct map *map_l = NULL;
497 struct map *map_r = NULL;
498
499 if (left->mem_info)
500 map_l = left->mem_info->daddr.map;
501 if (right->mem_info)
502 map_r = right->mem_info->daddr.map;
503
504 return _sort__dso_cmp(map_l, map_r);
505}
506
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300507static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100508 size_t size, unsigned int width)
509{
510 struct map *map = NULL;
511
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300512 if (he->mem_info)
513 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100514
515 return _hist_entry__dso_snprintf(map, bf, size, width);
516}
517
518static int64_t
519sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
520{
521 union perf_mem_data_src data_src_l;
522 union perf_mem_data_src data_src_r;
523
524 if (left->mem_info)
525 data_src_l = left->mem_info->data_src;
526 else
527 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
528
529 if (right->mem_info)
530 data_src_r = right->mem_info->data_src;
531 else
532 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
533
534 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
535}
536
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300537static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100538 size_t size, unsigned int width)
539{
540 const char *out;
541 u64 mask = PERF_MEM_LOCK_NA;
542
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543 if (he->mem_info)
544 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100545
546 if (mask & PERF_MEM_LOCK_NA)
547 out = "N/A";
548 else if (mask & PERF_MEM_LOCK_LOCKED)
549 out = "Yes";
550 else
551 out = "No";
552
553 return repsep_snprintf(bf, size, "%-*s", width, out);
554}
555
556static int64_t
557sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
558{
559 union perf_mem_data_src data_src_l;
560 union perf_mem_data_src data_src_r;
561
562 if (left->mem_info)
563 data_src_l = left->mem_info->data_src;
564 else
565 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
566
567 if (right->mem_info)
568 data_src_r = right->mem_info->data_src;
569 else
570 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
571
572 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
573}
574
575static const char * const tlb_access[] = {
576 "N/A",
577 "HIT",
578 "MISS",
579 "L1",
580 "L2",
581 "Walker",
582 "Fault",
583};
584#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
585
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300586static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100587 size_t size, unsigned int width)
588{
589 char out[64];
590 size_t sz = sizeof(out) - 1; /* -1 for null termination */
591 size_t l = 0, i;
592 u64 m = PERF_MEM_TLB_NA;
593 u64 hit, miss;
594
595 out[0] = '\0';
596
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300597 if (he->mem_info)
598 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100599
600 hit = m & PERF_MEM_TLB_HIT;
601 miss = m & PERF_MEM_TLB_MISS;
602
603 /* already taken care of */
604 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
605
606 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
607 if (!(m & 0x1))
608 continue;
609 if (l) {
610 strcat(out, " or ");
611 l += 4;
612 }
613 strncat(out, tlb_access[i], sz - l);
614 l += strlen(tlb_access[i]);
615 }
616 if (*out == '\0')
617 strcpy(out, "N/A");
618 if (hit)
619 strncat(out, " hit", sz - l);
620 if (miss)
621 strncat(out, " miss", sz - l);
622
623 return repsep_snprintf(bf, size, "%-*s", width, out);
624}
625
626static int64_t
627sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
628{
629 union perf_mem_data_src data_src_l;
630 union perf_mem_data_src data_src_r;
631
632 if (left->mem_info)
633 data_src_l = left->mem_info->data_src;
634 else
635 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
636
637 if (right->mem_info)
638 data_src_r = right->mem_info->data_src;
639 else
640 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
641
642 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
643}
644
645static const char * const mem_lvl[] = {
646 "N/A",
647 "HIT",
648 "MISS",
649 "L1",
650 "LFB",
651 "L2",
652 "L3",
653 "Local RAM",
654 "Remote RAM (1 hop)",
655 "Remote RAM (2 hops)",
656 "Remote Cache (1 hop)",
657 "Remote Cache (2 hops)",
658 "I/O",
659 "Uncached",
660};
661#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
662
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300663static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100664 size_t size, unsigned int width)
665{
666 char out[64];
667 size_t sz = sizeof(out) - 1; /* -1 for null termination */
668 size_t i, l = 0;
669 u64 m = PERF_MEM_LVL_NA;
670 u64 hit, miss;
671
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300672 if (he->mem_info)
673 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100674
675 out[0] = '\0';
676
677 hit = m & PERF_MEM_LVL_HIT;
678 miss = m & PERF_MEM_LVL_MISS;
679
680 /* already taken care of */
681 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
682
683 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
684 if (!(m & 0x1))
685 continue;
686 if (l) {
687 strcat(out, " or ");
688 l += 4;
689 }
690 strncat(out, mem_lvl[i], sz - l);
691 l += strlen(mem_lvl[i]);
692 }
693 if (*out == '\0')
694 strcpy(out, "N/A");
695 if (hit)
696 strncat(out, " hit", sz - l);
697 if (miss)
698 strncat(out, " miss", sz - l);
699
700 return repsep_snprintf(bf, size, "%-*s", width, out);
701}
702
703static int64_t
704sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
705{
706 union perf_mem_data_src data_src_l;
707 union perf_mem_data_src data_src_r;
708
709 if (left->mem_info)
710 data_src_l = left->mem_info->data_src;
711 else
712 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
713
714 if (right->mem_info)
715 data_src_r = right->mem_info->data_src;
716 else
717 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
718
719 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
720}
721
722static const char * const snoop_access[] = {
723 "N/A",
724 "None",
725 "Miss",
726 "Hit",
727 "HitM",
728};
729#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
730
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300731static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100732 size_t size, unsigned int width)
733{
734 char out[64];
735 size_t sz = sizeof(out) - 1; /* -1 for null termination */
736 size_t i, l = 0;
737 u64 m = PERF_MEM_SNOOP_NA;
738
739 out[0] = '\0';
740
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300741 if (he->mem_info)
742 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100743
744 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
745 if (!(m & 0x1))
746 continue;
747 if (l) {
748 strcat(out, " or ");
749 l += 4;
750 }
751 strncat(out, snoop_access[i], sz - l);
752 l += strlen(snoop_access[i]);
753 }
754
755 if (*out == '\0')
756 strcpy(out, "N/A");
757
758 return repsep_snprintf(bf, size, "%-*s", width, out);
759}
760
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100761struct sort_entry sort_mispredict = {
762 .se_header = "Branch Mispredicted",
763 .se_cmp = sort__mispredict_cmp,
764 .se_snprintf = hist_entry__mispredict_snprintf,
765 .se_width_idx = HISTC_MISPREDICT,
766};
767
Andi Kleen05484292013-01-24 16:10:29 +0100768static u64 he_weight(struct hist_entry *he)
769{
770 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
771}
772
773static int64_t
774sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
775{
776 return he_weight(left) - he_weight(right);
777}
778
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300779static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100780 size_t size, unsigned int width)
781{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300782 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100783}
784
785struct sort_entry sort_local_weight = {
786 .se_header = "Local Weight",
787 .se_cmp = sort__local_weight_cmp,
788 .se_snprintf = hist_entry__local_weight_snprintf,
789 .se_width_idx = HISTC_LOCAL_WEIGHT,
790};
791
792static int64_t
793sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
794{
795 return left->stat.weight - right->stat.weight;
796}
797
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300798static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100799 size_t size, unsigned int width)
800{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300801 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100802}
803
804struct sort_entry sort_global_weight = {
805 .se_header = "Weight",
806 .se_cmp = sort__global_weight_cmp,
807 .se_snprintf = hist_entry__global_weight_snprintf,
808 .se_width_idx = HISTC_GLOBAL_WEIGHT,
809};
810
Stephane Eranian98a3b322013-01-24 16:10:35 +0100811struct sort_entry sort_mem_daddr_sym = {
812 .se_header = "Data Symbol",
813 .se_cmp = sort__daddr_cmp,
814 .se_snprintf = hist_entry__daddr_snprintf,
815 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
816};
817
818struct sort_entry sort_mem_daddr_dso = {
819 .se_header = "Data Object",
820 .se_cmp = sort__dso_daddr_cmp,
821 .se_snprintf = hist_entry__dso_daddr_snprintf,
822 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
823};
824
825struct sort_entry sort_mem_locked = {
826 .se_header = "Locked",
827 .se_cmp = sort__locked_cmp,
828 .se_snprintf = hist_entry__locked_snprintf,
829 .se_width_idx = HISTC_MEM_LOCKED,
830};
831
832struct sort_entry sort_mem_tlb = {
833 .se_header = "TLB access",
834 .se_cmp = sort__tlb_cmp,
835 .se_snprintf = hist_entry__tlb_snprintf,
836 .se_width_idx = HISTC_MEM_TLB,
837};
838
839struct sort_entry sort_mem_lvl = {
840 .se_header = "Memory access",
841 .se_cmp = sort__lvl_cmp,
842 .se_snprintf = hist_entry__lvl_snprintf,
843 .se_width_idx = HISTC_MEM_LVL,
844};
845
846struct sort_entry sort_mem_snoop = {
847 .se_header = "Snoop",
848 .se_cmp = sort__snoop_cmp,
849 .se_snprintf = hist_entry__snoop_snprintf,
850 .se_width_idx = HISTC_MEM_SNOOP,
851};
852
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700853static int64_t
854sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
855{
856 return left->branch_info->flags.abort !=
857 right->branch_info->flags.abort;
858}
859
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300860static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700861 size_t size, unsigned int width)
862{
863 static const char *out = ".";
864
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300865 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700866 out = "A";
867 return repsep_snprintf(bf, size, "%-*s", width, out);
868}
869
870struct sort_entry sort_abort = {
871 .se_header = "Transaction abort",
872 .se_cmp = sort__abort_cmp,
873 .se_snprintf = hist_entry__abort_snprintf,
874 .se_width_idx = HISTC_ABORT,
875};
876
877static int64_t
878sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
879{
880 return left->branch_info->flags.in_tx !=
881 right->branch_info->flags.in_tx;
882}
883
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300884static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700885 size_t size, unsigned int width)
886{
887 static const char *out = ".";
888
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300889 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700890 out = "T";
891
892 return repsep_snprintf(bf, size, "%-*s", width, out);
893}
894
895struct sort_entry sort_in_tx = {
896 .se_header = "Branch in transaction",
897 .se_cmp = sort__in_tx_cmp,
898 .se_snprintf = hist_entry__in_tx_snprintf,
899 .se_width_idx = HISTC_IN_TX,
900};
901
Andi Kleen475eeab2013-09-20 07:40:43 -0700902static int64_t
903sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
904{
905 return left->transaction - right->transaction;
906}
907
908static inline char *add_str(char *p, const char *str)
909{
910 strcpy(p, str);
911 return p + strlen(str);
912}
913
914static struct txbit {
915 unsigned flag;
916 const char *name;
917 int skip_for_len;
918} txbits[] = {
919 { PERF_TXN_ELISION, "EL ", 0 },
920 { PERF_TXN_TRANSACTION, "TX ", 1 },
921 { PERF_TXN_SYNC, "SYNC ", 1 },
922 { PERF_TXN_ASYNC, "ASYNC ", 0 },
923 { PERF_TXN_RETRY, "RETRY ", 0 },
924 { PERF_TXN_CONFLICT, "CON ", 0 },
925 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
926 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
927 { 0, NULL, 0 }
928};
929
930int hist_entry__transaction_len(void)
931{
932 int i;
933 int len = 0;
934
935 for (i = 0; txbits[i].name; i++) {
936 if (!txbits[i].skip_for_len)
937 len += strlen(txbits[i].name);
938 }
939 len += 4; /* :XX<space> */
940 return len;
941}
942
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300943static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700944 size_t size, unsigned int width)
945{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300946 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700947 char buf[128];
948 char *p = buf;
949 int i;
950
951 buf[0] = 0;
952 for (i = 0; txbits[i].name; i++)
953 if (txbits[i].flag & t)
954 p = add_str(p, txbits[i].name);
955 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
956 p = add_str(p, "NEITHER ");
957 if (t & PERF_TXN_ABORT_MASK) {
958 sprintf(p, ":%" PRIx64,
959 (t & PERF_TXN_ABORT_MASK) >>
960 PERF_TXN_ABORT_SHIFT);
961 p += strlen(p);
962 }
963
964 return repsep_snprintf(bf, size, "%-*s", width, buf);
965}
966
967struct sort_entry sort_transaction = {
968 .se_header = "Transaction ",
969 .se_cmp = sort__transaction_cmp,
970 .se_snprintf = hist_entry__transaction_snprintf,
971 .se_width_idx = HISTC_TRANSACTION,
972};
973
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200974struct sort_dimension {
975 const char *name;
976 struct sort_entry *entry;
977 int taken;
978};
979
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100980#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
981
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900982static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100983 DIM(SORT_PID, "pid", sort_thread),
984 DIM(SORT_COMM, "comm", sort_comm),
985 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100986 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100987 DIM(SORT_PARENT, "parent", sort_parent),
988 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300989 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -0700990 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
991 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -0700992 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200993};
994
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900995#undef DIM
996
997#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
998
999static struct sort_dimension bstack_sort_dimensions[] = {
1000 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1001 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1002 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1003 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1004 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001005 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1006 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001007};
1008
1009#undef DIM
1010
Namhyung Kimafab87b2013-04-03 21:26:11 +09001011#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1012
1013static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001014 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1015 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1016 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1017 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1018 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1019 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1020};
1021
1022#undef DIM
1023
Namhyung Kim2f532d092013-04-03 21:26:10 +09001024static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
1025{
1026 if (sd->taken)
1027 return;
1028
1029 if (sd->entry->se_collapse)
1030 sort__need_collapse = 1;
1031
1032 if (list_empty(&hist_entry__sort_list))
1033 sort__first_dimension = idx;
1034
1035 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1036 sd->taken = 1;
1037}
1038
John Kacurdd68ada2009-09-24 18:02:49 +02001039int sort_dimension__add(const char *tok)
1040{
1041 unsigned int i;
1042
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001043 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1044 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001045
John Kacurdd68ada2009-09-24 18:02:49 +02001046 if (strncasecmp(tok, sd->name, strlen(tok)))
1047 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001048
John Kacurdd68ada2009-09-24 18:02:49 +02001049 if (sd->entry == &sort_parent) {
1050 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1051 if (ret) {
1052 char err[BUFSIZ];
1053
1054 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001055 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1056 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001057 }
1058 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001059 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001060 sort__has_sym = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001061 }
1062
Namhyung Kim2f532d092013-04-03 21:26:10 +09001063 __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001064 return 0;
1065 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001066
1067 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1068 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1069
1070 if (strncasecmp(tok, sd->name, strlen(tok)))
1071 continue;
1072
Namhyung Kim55369fc2013-04-01 20:35:20 +09001073 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001074 return -EINVAL;
1075
1076 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1077 sort__has_sym = 1;
1078
Namhyung Kim2f532d092013-04-03 21:26:10 +09001079 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001080 return 0;
1081 }
1082
Namhyung Kimafab87b2013-04-03 21:26:11 +09001083 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1084 struct sort_dimension *sd = &memory_sort_dimensions[i];
1085
1086 if (strncasecmp(tok, sd->name, strlen(tok)))
1087 continue;
1088
1089 if (sort__mode != SORT_MODE__MEMORY)
1090 return -EINVAL;
1091
1092 if (sd->entry == &sort_mem_daddr_sym)
1093 sort__has_sym = 1;
1094
1095 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1096 return 0;
1097 }
1098
John Kacurdd68ada2009-09-24 18:02:49 +02001099 return -ESRCH;
1100}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001101
Namhyung Kim55309982013-02-06 14:57:16 +09001102int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001103{
1104 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +09001105 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001106
Namhyung Kim5936f542013-02-06 14:57:17 +09001107 if (str == NULL) {
1108 error("Not enough memory to setup sort keys");
1109 return -ENOMEM;
1110 }
1111
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001112 for (tok = strtok_r(str, ", ", &tmp);
1113 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001114 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001115 if (ret == -EINVAL) {
1116 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001117 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001118 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001119 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001120 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001121 }
1122 }
1123
1124 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001125 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001126}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001127
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001128static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001129 struct strlist *list,
1130 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001131{
1132 if (list && strlist__nr_entries(list) == 1) {
1133 if (fp != NULL)
1134 fprintf(fp, "# %s: %s\n", list_name,
1135 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001136 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001137 }
1138}
Namhyung Kim08e71542013-04-03 21:26:19 +09001139
1140void sort__setup_elide(FILE *output)
1141{
1142 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1143 "dso", output);
1144 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1145 "comm", output);
1146 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1147 "symbol", output);
1148
1149 if (sort__mode == SORT_MODE__BRANCH) {
1150 sort_entry__setup_elide(&sort_dso_from,
1151 symbol_conf.dso_from_list,
1152 "dso_from", output);
1153 sort_entry__setup_elide(&sort_dso_to,
1154 symbol_conf.dso_to_list,
1155 "dso_to", output);
1156 sort_entry__setup_elide(&sort_sym_from,
1157 symbol_conf.sym_from_list,
1158 "sym_from", output);
1159 sort_entry__setup_elide(&sort_sym_to,
1160 symbol_conf.sym_to_list,
1161 "sym_to", output);
1162 } else if (sort__mode == SORT_MODE__MEMORY) {
1163 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1164 "symbol_daddr", output);
1165 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1166 "dso_daddr", output);
1167 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1168 "mem", output);
1169 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1170 "local_weight", output);
1171 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1172 "tlb", output);
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "snoop", output);
1175 }
1176
1177}