blob: b2829f9470536a11dd4be10a2e89a0aad7ed05cb [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 Kim4dfced32013-09-13 16:28:57 +09003#include "comm.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09004#include "symbol.h"
Namhyung Kim8b536992014-03-03 11:46:55 +09005#include "evsel.h"
John Kacurdd68ada2009-09-24 18:02:49 +02006
7regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03008const char default_parent_pattern[] = "^sys_|^do_page_fault";
9const char *parent_pattern = default_parent_pattern;
10const char default_sort_order[] = "comm,dso,symbol";
11const char *sort_order = default_sort_order;
Greg Priceb21484f2012-12-06 21:48:05 -080012regex_t ignore_callees_regex;
13int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020014int sort__need_collapse = 0;
15int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090016int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090017int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090018enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020019
20enum sort_type sort__first_dimension;
John Kacurdd68ada2009-09-24 18:02:49 +020021
John Kacurdd68ada2009-09-24 18:02:49 +020022LIST_HEAD(hist_entry__sort_list);
23
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030024static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020025{
26 int n;
27 va_list ap;
28
29 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030030 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020031 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030032 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020033
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030034 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020035 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030036 if (sep == NULL)
37 break;
38 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020039 }
John Kacurdd68ada2009-09-24 18:02:49 +020040 }
41 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110042
43 if (n >= (int)size)
44 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020045 return n;
46}
47
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020048static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020049{
50 if (!l && !r)
51 return 0;
52 else if (!l)
53 return -1;
54 else
55 return 1;
56}
57
58/* --sort pid */
59
60static int64_t
61sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
62{
Adrian Hunter38051232013-07-04 16:20:31 +030063 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020064}
65
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030066static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030067 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020068{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020069 const char *comm = thread__comm_str(he->thread);
Namhyung Kimfb29a332012-12-27 18:11:40 +090070 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020071 comm ?: "", he->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020072}
73
Frederic Weisbecker872a8782011-06-29 03:14:52 +020074struct sort_entry sort_thread = {
75 .se_header = "Command: Pid",
76 .se_cmp = sort__thread_cmp,
77 .se_snprintf = hist_entry__thread_snprintf,
78 .se_width_idx = HISTC_THREAD,
79};
80
81/* --sort comm */
82
83static int64_t
84sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
85{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020086 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090087 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020088}
89
90static int64_t
91sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
92{
Namhyung Kim4dfced32013-09-13 16:28:57 +090093 /* Compare the addr that should be unique among comm */
94 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020095}
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{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900100 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->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 Kim2037be52013-12-18 14:21:09 +0900166static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
167{
168 return (int64_t)(right_ip - left_ip);
169}
170
Namhyung Kim51f27d12013-02-06 14:57:15 +0900171static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900172{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900173 u64 ip_l, ip_r;
174
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900175 if (!sym_l || !sym_r)
176 return cmp_null(sym_l, sym_r);
177
178 if (sym_l == sym_r)
179 return 0;
180
181 ip_l = sym_l->start;
182 ip_r = sym_r->start;
183
184 return (int64_t)(ip_r - ip_l);
185}
186
187static int64_t
188sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
189{
Namhyung Kim09600e02013-10-15 11:01:56 +0900190 int64_t ret;
191
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900192 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900193 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900194
Namhyung Kim09600e02013-10-15 11:01:56 +0900195 /*
196 * comparing symbol address alone is not enough since it's a
197 * relative address within a dso.
198 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900199 if (!sort__has_dso) {
200 ret = sort__dso_cmp(left, right);
201 if (ret != 0)
202 return ret;
203 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900204
Namhyung Kim51f27d12013-02-06 14:57:15 +0900205 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206}
207
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100208static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
209 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900210 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100211{
212 size_t ret = 0;
213
214 if (verbose) {
215 char o = map ? dso__symtab_origin(map->dso) : '!';
216 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900217 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100218 }
219
220 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100221 if (sym && map) {
222 if (map->type == MAP__VARIABLE) {
223 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
224 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100225 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100226 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
227 width - ret, "");
228 } else {
229 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
230 width - ret,
231 sym->name);
232 }
233 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100234 size_t len = BITS_PER_LONG / 4;
235 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
236 len, ip);
237 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
238 width - ret, "");
239 }
240
241 return ret;
242}
243
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300244static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900245 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100246{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300247 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
248 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100249}
John Kacurdd68ada2009-09-24 18:02:49 +0200250
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200251struct sort_entry sort_sym = {
252 .se_header = "Symbol",
253 .se_cmp = sort__sym_cmp,
254 .se_snprintf = hist_entry__sym_snprintf,
255 .se_width_idx = HISTC_SYMBOL,
256};
John Kacurdd68ada2009-09-24 18:02:49 +0200257
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300258/* --sort srcline */
259
260static int64_t
261sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
262{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900263 if (!left->srcline) {
264 if (!left->ms.map)
265 left->srcline = SRCLINE_UNKNOWN;
266 else {
267 struct map *map = left->ms.map;
268 left->srcline = get_srcline(map->dso,
269 map__rip_2objdump(map, left->ip));
270 }
271 }
272 if (!right->srcline) {
273 if (!right->ms.map)
274 right->srcline = SRCLINE_UNKNOWN;
275 else {
276 struct map *map = right->ms.map;
277 right->srcline = get_srcline(map->dso,
278 map__rip_2objdump(map, right->ip));
279 }
280 }
281 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300282}
283
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300284static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300285 size_t size,
286 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300287{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300288 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300289}
290
291struct sort_entry sort_srcline = {
292 .se_header = "Source:Line",
293 .se_cmp = sort__srcline_cmp,
294 .se_snprintf = hist_entry__srcline_snprintf,
295 .se_width_idx = HISTC_SRCLINE,
296};
297
John Kacurdd68ada2009-09-24 18:02:49 +0200298/* --sort parent */
299
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200300static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200301sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
302{
303 struct symbol *sym_l = left->parent;
304 struct symbol *sym_r = right->parent;
305
306 if (!sym_l || !sym_r)
307 return cmp_null(sym_l, sym_r);
308
309 return strcmp(sym_l->name, sym_r->name);
310}
311
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300312static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300313 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200314{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300315 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300316 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200317}
318
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200319struct sort_entry sort_parent = {
320 .se_header = "Parent symbol",
321 .se_cmp = sort__parent_cmp,
322 .se_snprintf = hist_entry__parent_snprintf,
323 .se_width_idx = HISTC_PARENT,
324};
325
Arun Sharmaf60f3592010-06-04 11:27:10 -0300326/* --sort cpu */
327
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200328static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300329sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
330{
331 return right->cpu - left->cpu;
332}
333
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300334static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
335 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300336{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300337 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300338}
339
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200340struct sort_entry sort_cpu = {
341 .se_header = "CPU",
342 .se_cmp = sort__cpu_cmp,
343 .se_snprintf = hist_entry__cpu_snprintf,
344 .se_width_idx = HISTC_CPU,
345};
346
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900347/* sort keys for branch stacks */
348
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100349static int64_t
350sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
351{
352 return _sort__dso_cmp(left->branch_info->from.map,
353 right->branch_info->from.map);
354}
355
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300356static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100357 size_t size, unsigned int width)
358{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300359 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100360 bf, size, width);
361}
362
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100363static int64_t
364sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
365{
366 return _sort__dso_cmp(left->branch_info->to.map,
367 right->branch_info->to.map);
368}
369
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300370static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100371 size_t size, unsigned int width)
372{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300373 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100374 bf, size, width);
375}
376
377static int64_t
378sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
379{
380 struct addr_map_symbol *from_l = &left->branch_info->from;
381 struct addr_map_symbol *from_r = &right->branch_info->from;
382
383 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900384 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100385
Namhyung Kim51f27d12013-02-06 14:57:15 +0900386 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100387}
388
389static int64_t
390sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
391{
392 struct addr_map_symbol *to_l = &left->branch_info->to;
393 struct addr_map_symbol *to_r = &right->branch_info->to;
394
395 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900396 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100397
Namhyung Kim51f27d12013-02-06 14:57:15 +0900398 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100399}
400
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300401static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900402 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100403{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300404 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100405 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300406 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407
408}
409
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300410static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900411 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100412{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300413 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100414 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300415 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100416
417}
418
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900419struct sort_entry sort_dso_from = {
420 .se_header = "Source Shared Object",
421 .se_cmp = sort__dso_from_cmp,
422 .se_snprintf = hist_entry__dso_from_snprintf,
423 .se_width_idx = HISTC_DSO_FROM,
424};
425
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100426struct sort_entry sort_dso_to = {
427 .se_header = "Target Shared Object",
428 .se_cmp = sort__dso_to_cmp,
429 .se_snprintf = hist_entry__dso_to_snprintf,
430 .se_width_idx = HISTC_DSO_TO,
431};
432
433struct sort_entry sort_sym_from = {
434 .se_header = "Source Symbol",
435 .se_cmp = sort__sym_from_cmp,
436 .se_snprintf = hist_entry__sym_from_snprintf,
437 .se_width_idx = HISTC_SYMBOL_FROM,
438};
439
440struct sort_entry sort_sym_to = {
441 .se_header = "Target Symbol",
442 .se_cmp = sort__sym_to_cmp,
443 .se_snprintf = hist_entry__sym_to_snprintf,
444 .se_width_idx = HISTC_SYMBOL_TO,
445};
446
447static int64_t
448sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
449{
450 const unsigned char mp = left->branch_info->flags.mispred !=
451 right->branch_info->flags.mispred;
452 const unsigned char p = left->branch_info->flags.predicted !=
453 right->branch_info->flags.predicted;
454
455 return mp || p;
456}
457
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300458static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100459 size_t size, unsigned int width){
460 static const char *out = "N/A";
461
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300462 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100463 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300464 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100465 out = "Y";
466
467 return repsep_snprintf(bf, size, "%-*s", width, out);
468}
469
Stephane Eranian98a3b322013-01-24 16:10:35 +0100470/* --sort daddr_sym */
471static int64_t
472sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
473{
474 uint64_t l = 0, r = 0;
475
476 if (left->mem_info)
477 l = left->mem_info->daddr.addr;
478 if (right->mem_info)
479 r = right->mem_info->daddr.addr;
480
481 return (int64_t)(r - l);
482}
483
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300484static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100485 size_t size, unsigned int width)
486{
487 uint64_t addr = 0;
488 struct map *map = NULL;
489 struct symbol *sym = NULL;
490
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300491 if (he->mem_info) {
492 addr = he->mem_info->daddr.addr;
493 map = he->mem_info->daddr.map;
494 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100495 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300496 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100497 width);
498}
499
500static int64_t
501sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
502{
503 struct map *map_l = NULL;
504 struct map *map_r = NULL;
505
506 if (left->mem_info)
507 map_l = left->mem_info->daddr.map;
508 if (right->mem_info)
509 map_r = right->mem_info->daddr.map;
510
511 return _sort__dso_cmp(map_l, map_r);
512}
513
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300514static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100515 size_t size, unsigned int width)
516{
517 struct map *map = NULL;
518
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300519 if (he->mem_info)
520 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100521
522 return _hist_entry__dso_snprintf(map, bf, size, width);
523}
524
525static int64_t
526sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
527{
528 union perf_mem_data_src data_src_l;
529 union perf_mem_data_src data_src_r;
530
531 if (left->mem_info)
532 data_src_l = left->mem_info->data_src;
533 else
534 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
535
536 if (right->mem_info)
537 data_src_r = right->mem_info->data_src;
538 else
539 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
540
541 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
542}
543
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300544static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100545 size_t size, unsigned int width)
546{
547 const char *out;
548 u64 mask = PERF_MEM_LOCK_NA;
549
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300550 if (he->mem_info)
551 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100552
553 if (mask & PERF_MEM_LOCK_NA)
554 out = "N/A";
555 else if (mask & PERF_MEM_LOCK_LOCKED)
556 out = "Yes";
557 else
558 out = "No";
559
560 return repsep_snprintf(bf, size, "%-*s", width, out);
561}
562
563static int64_t
564sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
565{
566 union perf_mem_data_src data_src_l;
567 union perf_mem_data_src data_src_r;
568
569 if (left->mem_info)
570 data_src_l = left->mem_info->data_src;
571 else
572 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
573
574 if (right->mem_info)
575 data_src_r = right->mem_info->data_src;
576 else
577 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
578
579 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
580}
581
582static const char * const tlb_access[] = {
583 "N/A",
584 "HIT",
585 "MISS",
586 "L1",
587 "L2",
588 "Walker",
589 "Fault",
590};
591#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
592
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300593static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100594 size_t size, unsigned int width)
595{
596 char out[64];
597 size_t sz = sizeof(out) - 1; /* -1 for null termination */
598 size_t l = 0, i;
599 u64 m = PERF_MEM_TLB_NA;
600 u64 hit, miss;
601
602 out[0] = '\0';
603
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300604 if (he->mem_info)
605 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100606
607 hit = m & PERF_MEM_TLB_HIT;
608 miss = m & PERF_MEM_TLB_MISS;
609
610 /* already taken care of */
611 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
612
613 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
614 if (!(m & 0x1))
615 continue;
616 if (l) {
617 strcat(out, " or ");
618 l += 4;
619 }
620 strncat(out, tlb_access[i], sz - l);
621 l += strlen(tlb_access[i]);
622 }
623 if (*out == '\0')
624 strcpy(out, "N/A");
625 if (hit)
626 strncat(out, " hit", sz - l);
627 if (miss)
628 strncat(out, " miss", sz - l);
629
630 return repsep_snprintf(bf, size, "%-*s", width, out);
631}
632
633static int64_t
634sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
635{
636 union perf_mem_data_src data_src_l;
637 union perf_mem_data_src data_src_r;
638
639 if (left->mem_info)
640 data_src_l = left->mem_info->data_src;
641 else
642 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
643
644 if (right->mem_info)
645 data_src_r = right->mem_info->data_src;
646 else
647 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
648
649 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
650}
651
652static const char * const mem_lvl[] = {
653 "N/A",
654 "HIT",
655 "MISS",
656 "L1",
657 "LFB",
658 "L2",
659 "L3",
660 "Local RAM",
661 "Remote RAM (1 hop)",
662 "Remote RAM (2 hops)",
663 "Remote Cache (1 hop)",
664 "Remote Cache (2 hops)",
665 "I/O",
666 "Uncached",
667};
668#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
669
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300670static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100671 size_t size, unsigned int width)
672{
673 char out[64];
674 size_t sz = sizeof(out) - 1; /* -1 for null termination */
675 size_t i, l = 0;
676 u64 m = PERF_MEM_LVL_NA;
677 u64 hit, miss;
678
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300679 if (he->mem_info)
680 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100681
682 out[0] = '\0';
683
684 hit = m & PERF_MEM_LVL_HIT;
685 miss = m & PERF_MEM_LVL_MISS;
686
687 /* already taken care of */
688 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
689
690 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
691 if (!(m & 0x1))
692 continue;
693 if (l) {
694 strcat(out, " or ");
695 l += 4;
696 }
697 strncat(out, mem_lvl[i], sz - l);
698 l += strlen(mem_lvl[i]);
699 }
700 if (*out == '\0')
701 strcpy(out, "N/A");
702 if (hit)
703 strncat(out, " hit", sz - l);
704 if (miss)
705 strncat(out, " miss", sz - l);
706
707 return repsep_snprintf(bf, size, "%-*s", width, out);
708}
709
710static int64_t
711sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
712{
713 union perf_mem_data_src data_src_l;
714 union perf_mem_data_src data_src_r;
715
716 if (left->mem_info)
717 data_src_l = left->mem_info->data_src;
718 else
719 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
720
721 if (right->mem_info)
722 data_src_r = right->mem_info->data_src;
723 else
724 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
725
726 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
727}
728
729static const char * const snoop_access[] = {
730 "N/A",
731 "None",
732 "Miss",
733 "Hit",
734 "HitM",
735};
736#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
737
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300738static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100739 size_t size, unsigned int width)
740{
741 char out[64];
742 size_t sz = sizeof(out) - 1; /* -1 for null termination */
743 size_t i, l = 0;
744 u64 m = PERF_MEM_SNOOP_NA;
745
746 out[0] = '\0';
747
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300748 if (he->mem_info)
749 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100750
751 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
752 if (!(m & 0x1))
753 continue;
754 if (l) {
755 strcat(out, " or ");
756 l += 4;
757 }
758 strncat(out, snoop_access[i], sz - l);
759 l += strlen(snoop_access[i]);
760 }
761
762 if (*out == '\0')
763 strcpy(out, "N/A");
764
765 return repsep_snprintf(bf, size, "%-*s", width, out);
766}
767
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100768struct sort_entry sort_mispredict = {
769 .se_header = "Branch Mispredicted",
770 .se_cmp = sort__mispredict_cmp,
771 .se_snprintf = hist_entry__mispredict_snprintf,
772 .se_width_idx = HISTC_MISPREDICT,
773};
774
Andi Kleen05484292013-01-24 16:10:29 +0100775static u64 he_weight(struct hist_entry *he)
776{
777 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
778}
779
780static int64_t
781sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
782{
783 return he_weight(left) - he_weight(right);
784}
785
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300786static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100787 size_t size, unsigned int width)
788{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300789 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100790}
791
792struct sort_entry sort_local_weight = {
793 .se_header = "Local Weight",
794 .se_cmp = sort__local_weight_cmp,
795 .se_snprintf = hist_entry__local_weight_snprintf,
796 .se_width_idx = HISTC_LOCAL_WEIGHT,
797};
798
799static int64_t
800sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
801{
802 return left->stat.weight - right->stat.weight;
803}
804
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300805static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100806 size_t size, unsigned int width)
807{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300808 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100809}
810
811struct sort_entry sort_global_weight = {
812 .se_header = "Weight",
813 .se_cmp = sort__global_weight_cmp,
814 .se_snprintf = hist_entry__global_weight_snprintf,
815 .se_width_idx = HISTC_GLOBAL_WEIGHT,
816};
817
Stephane Eranian98a3b322013-01-24 16:10:35 +0100818struct sort_entry sort_mem_daddr_sym = {
819 .se_header = "Data Symbol",
820 .se_cmp = sort__daddr_cmp,
821 .se_snprintf = hist_entry__daddr_snprintf,
822 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
823};
824
825struct sort_entry sort_mem_daddr_dso = {
826 .se_header = "Data Object",
827 .se_cmp = sort__dso_daddr_cmp,
828 .se_snprintf = hist_entry__dso_daddr_snprintf,
829 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
830};
831
832struct sort_entry sort_mem_locked = {
833 .se_header = "Locked",
834 .se_cmp = sort__locked_cmp,
835 .se_snprintf = hist_entry__locked_snprintf,
836 .se_width_idx = HISTC_MEM_LOCKED,
837};
838
839struct sort_entry sort_mem_tlb = {
840 .se_header = "TLB access",
841 .se_cmp = sort__tlb_cmp,
842 .se_snprintf = hist_entry__tlb_snprintf,
843 .se_width_idx = HISTC_MEM_TLB,
844};
845
846struct sort_entry sort_mem_lvl = {
847 .se_header = "Memory access",
848 .se_cmp = sort__lvl_cmp,
849 .se_snprintf = hist_entry__lvl_snprintf,
850 .se_width_idx = HISTC_MEM_LVL,
851};
852
853struct sort_entry sort_mem_snoop = {
854 .se_header = "Snoop",
855 .se_cmp = sort__snoop_cmp,
856 .se_snprintf = hist_entry__snoop_snprintf,
857 .se_width_idx = HISTC_MEM_SNOOP,
858};
859
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700860static int64_t
861sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
862{
863 return left->branch_info->flags.abort !=
864 right->branch_info->flags.abort;
865}
866
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300867static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700868 size_t size, unsigned int width)
869{
870 static const char *out = ".";
871
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300872 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700873 out = "A";
874 return repsep_snprintf(bf, size, "%-*s", width, out);
875}
876
877struct sort_entry sort_abort = {
878 .se_header = "Transaction abort",
879 .se_cmp = sort__abort_cmp,
880 .se_snprintf = hist_entry__abort_snprintf,
881 .se_width_idx = HISTC_ABORT,
882};
883
884static int64_t
885sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
886{
887 return left->branch_info->flags.in_tx !=
888 right->branch_info->flags.in_tx;
889}
890
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300891static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700892 size_t size, unsigned int width)
893{
894 static const char *out = ".";
895
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300896 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700897 out = "T";
898
899 return repsep_snprintf(bf, size, "%-*s", width, out);
900}
901
902struct sort_entry sort_in_tx = {
903 .se_header = "Branch in transaction",
904 .se_cmp = sort__in_tx_cmp,
905 .se_snprintf = hist_entry__in_tx_snprintf,
906 .se_width_idx = HISTC_IN_TX,
907};
908
Andi Kleen475eeab2013-09-20 07:40:43 -0700909static int64_t
910sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
911{
912 return left->transaction - right->transaction;
913}
914
915static inline char *add_str(char *p, const char *str)
916{
917 strcpy(p, str);
918 return p + strlen(str);
919}
920
921static struct txbit {
922 unsigned flag;
923 const char *name;
924 int skip_for_len;
925} txbits[] = {
926 { PERF_TXN_ELISION, "EL ", 0 },
927 { PERF_TXN_TRANSACTION, "TX ", 1 },
928 { PERF_TXN_SYNC, "SYNC ", 1 },
929 { PERF_TXN_ASYNC, "ASYNC ", 0 },
930 { PERF_TXN_RETRY, "RETRY ", 0 },
931 { PERF_TXN_CONFLICT, "CON ", 0 },
932 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
933 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
934 { 0, NULL, 0 }
935};
936
937int hist_entry__transaction_len(void)
938{
939 int i;
940 int len = 0;
941
942 for (i = 0; txbits[i].name; i++) {
943 if (!txbits[i].skip_for_len)
944 len += strlen(txbits[i].name);
945 }
946 len += 4; /* :XX<space> */
947 return len;
948}
949
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300950static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700951 size_t size, unsigned int width)
952{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300953 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700954 char buf[128];
955 char *p = buf;
956 int i;
957
958 buf[0] = 0;
959 for (i = 0; txbits[i].name; i++)
960 if (txbits[i].flag & t)
961 p = add_str(p, txbits[i].name);
962 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
963 p = add_str(p, "NEITHER ");
964 if (t & PERF_TXN_ABORT_MASK) {
965 sprintf(p, ":%" PRIx64,
966 (t & PERF_TXN_ABORT_MASK) >>
967 PERF_TXN_ABORT_SHIFT);
968 p += strlen(p);
969 }
970
971 return repsep_snprintf(bf, size, "%-*s", width, buf);
972}
973
974struct sort_entry sort_transaction = {
975 .se_header = "Transaction ",
976 .se_cmp = sort__transaction_cmp,
977 .se_snprintf = hist_entry__transaction_snprintf,
978 .se_width_idx = HISTC_TRANSACTION,
979};
980
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200981struct sort_dimension {
982 const char *name;
983 struct sort_entry *entry;
984 int taken;
985};
986
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100987#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
988
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900989static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100990 DIM(SORT_PID, "pid", sort_thread),
991 DIM(SORT_COMM, "comm", sort_comm),
992 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100993 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100994 DIM(SORT_PARENT, "parent", sort_parent),
995 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300996 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -0700997 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
998 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -0700999 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001000};
1001
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001002#undef DIM
1003
1004#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1005
1006static struct sort_dimension bstack_sort_dimensions[] = {
1007 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1008 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1009 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1010 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1011 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001012 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1013 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001014};
1015
1016#undef DIM
1017
Namhyung Kimafab87b2013-04-03 21:26:11 +09001018#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1019
1020static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001021 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1022 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1023 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1024 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1025 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1026 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1027};
1028
1029#undef DIM
1030
Namhyung Kim8b536992014-03-03 11:46:55 +09001031struct hpp_sort_entry {
1032 struct perf_hpp_fmt hpp;
1033 struct sort_entry *se;
1034};
1035
1036static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1037 struct perf_evsel *evsel)
1038{
1039 struct hpp_sort_entry *hse;
1040 size_t len;
1041
1042 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1043 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1044
1045 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1046}
1047
1048static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1049 struct perf_hpp *hpp __maybe_unused,
1050 struct perf_evsel *evsel)
1051{
1052 struct hpp_sort_entry *hse;
1053
1054 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1055
1056 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1057}
1058
1059static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1060 struct hist_entry *he)
1061{
1062 struct hpp_sort_entry *hse;
1063 size_t len;
1064
1065 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1066 len = hists__col_len(he->hists, hse->se->se_width_idx);
1067
1068 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1069}
1070
1071static int __sort_dimension__add_hpp(struct sort_dimension *sd)
1072{
1073 struct hpp_sort_entry *hse;
1074
1075 hse = malloc(sizeof(*hse));
1076 if (hse == NULL) {
1077 pr_err("Memory allocation failed\n");
1078 return -1;
1079 }
1080
1081 hse->se = sd->entry;
1082 hse->hpp.header = __sort__hpp_header;
1083 hse->hpp.width = __sort__hpp_width;
1084 hse->hpp.entry = __sort__hpp_entry;
1085 hse->hpp.color = NULL;
1086
1087 hse->hpp.cmp = sd->entry->se_cmp;
1088 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1089 hse->hpp.sort = hse->hpp.collapse;
1090
1091 INIT_LIST_HEAD(&hse->hpp.list);
1092 INIT_LIST_HEAD(&hse->hpp.sort_list);
1093
1094 perf_hpp__register_sort_field(&hse->hpp);
1095 return 0;
1096}
1097
1098static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001099{
1100 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001101 return 0;
1102
1103 if (__sort_dimension__add_hpp(sd) < 0)
1104 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001105
1106 if (sd->entry->se_collapse)
1107 sort__need_collapse = 1;
1108
1109 if (list_empty(&hist_entry__sort_list))
1110 sort__first_dimension = idx;
1111
1112 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1113 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001114
1115 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001116}
1117
John Kacurdd68ada2009-09-24 18:02:49 +02001118int sort_dimension__add(const char *tok)
1119{
1120 unsigned int i;
1121
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001122 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1123 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001124
John Kacurdd68ada2009-09-24 18:02:49 +02001125 if (strncasecmp(tok, sd->name, strlen(tok)))
1126 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001127
John Kacurdd68ada2009-09-24 18:02:49 +02001128 if (sd->entry == &sort_parent) {
1129 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1130 if (ret) {
1131 char err[BUFSIZ];
1132
1133 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001134 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1135 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001136 }
1137 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001138 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001139 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001140 } else if (sd->entry == &sort_dso) {
1141 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001142 }
1143
Namhyung Kim8b536992014-03-03 11:46:55 +09001144 return __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001145 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001146
1147 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1148 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1149
1150 if (strncasecmp(tok, sd->name, strlen(tok)))
1151 continue;
1152
Namhyung Kim55369fc2013-04-01 20:35:20 +09001153 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001154 return -EINVAL;
1155
1156 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1157 sort__has_sym = 1;
1158
Namhyung Kim2f532d092013-04-03 21:26:10 +09001159 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001160 return 0;
1161 }
1162
Namhyung Kimafab87b2013-04-03 21:26:11 +09001163 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1164 struct sort_dimension *sd = &memory_sort_dimensions[i];
1165
1166 if (strncasecmp(tok, sd->name, strlen(tok)))
1167 continue;
1168
1169 if (sort__mode != SORT_MODE__MEMORY)
1170 return -EINVAL;
1171
1172 if (sd->entry == &sort_mem_daddr_sym)
1173 sort__has_sym = 1;
1174
1175 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1176 return 0;
1177 }
1178
John Kacurdd68ada2009-09-24 18:02:49 +02001179 return -ESRCH;
1180}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001181
Namhyung Kim55309982013-02-06 14:57:16 +09001182int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001183{
1184 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +09001185 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001186
Namhyung Kim5936f542013-02-06 14:57:17 +09001187 if (str == NULL) {
1188 error("Not enough memory to setup sort keys");
1189 return -ENOMEM;
1190 }
1191
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001192 for (tok = strtok_r(str, ", ", &tmp);
1193 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001194 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001195 if (ret == -EINVAL) {
1196 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001197 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001198 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001199 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001200 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001201 }
1202 }
1203
1204 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001205 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001206}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001207
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001208static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001209 struct strlist *list,
1210 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001211{
1212 if (list && strlist__nr_entries(list) == 1) {
1213 if (fp != NULL)
1214 fprintf(fp, "# %s: %s\n", list_name,
1215 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001216 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001217 }
1218}
Namhyung Kim08e71542013-04-03 21:26:19 +09001219
1220void sort__setup_elide(FILE *output)
1221{
Namhyung Kim7524f632013-11-08 17:53:42 +09001222 struct sort_entry *se;
1223
Namhyung Kim08e71542013-04-03 21:26:19 +09001224 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1225 "dso", output);
1226 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1227 "comm", output);
1228 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1229 "symbol", output);
1230
1231 if (sort__mode == SORT_MODE__BRANCH) {
1232 sort_entry__setup_elide(&sort_dso_from,
1233 symbol_conf.dso_from_list,
1234 "dso_from", output);
1235 sort_entry__setup_elide(&sort_dso_to,
1236 symbol_conf.dso_to_list,
1237 "dso_to", output);
1238 sort_entry__setup_elide(&sort_sym_from,
1239 symbol_conf.sym_from_list,
1240 "sym_from", output);
1241 sort_entry__setup_elide(&sort_sym_to,
1242 symbol_conf.sym_to_list,
1243 "sym_to", output);
1244 } else if (sort__mode == SORT_MODE__MEMORY) {
1245 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1246 "symbol_daddr", output);
1247 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1248 "dso_daddr", output);
1249 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1250 "mem", output);
1251 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1252 "local_weight", output);
1253 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1254 "tlb", output);
1255 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1256 "snoop", output);
1257 }
1258
Namhyung Kim7524f632013-11-08 17:53:42 +09001259 /*
1260 * It makes no sense to elide all of sort entries.
1261 * Just revert them to show up again.
1262 */
1263 list_for_each_entry(se, &hist_entry__sort_list, list) {
1264 if (!se->elide)
1265 return;
1266 }
1267
1268 list_for_each_entry(se, &hist_entry__sort_list, list)
1269 se->elide = false;
Namhyung Kim08e71542013-04-03 21:26:19 +09001270}