blob: d64c1e58f1b1a54705ef28270dd3b5ff5b0c2936 [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";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090011const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
12const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
13const char default_top_sort_order[] = "dso,symbol";
14const char default_diff_sort_order[] = "dso,symbol";
15const char *sort_order;
Greg Priceb21484f2012-12-06 21:48:05 -080016regex_t ignore_callees_regex;
17int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020018int sort__need_collapse = 0;
19int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090020int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090021int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090022enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020023
24enum sort_type sort__first_dimension;
John Kacurdd68ada2009-09-24 18:02:49 +020025
John Kacurdd68ada2009-09-24 18:02:49 +020026LIST_HEAD(hist_entry__sort_list);
27
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030028static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020029{
30 int n;
31 va_list ap;
32
33 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030034 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020035 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030036 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020037
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030038 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020039 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030040 if (sep == NULL)
41 break;
42 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020043 }
John Kacurdd68ada2009-09-24 18:02:49 +020044 }
45 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110046
47 if (n >= (int)size)
48 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020049 return n;
50}
51
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020052static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020053{
54 if (!l && !r)
55 return 0;
56 else if (!l)
57 return -1;
58 else
59 return 1;
60}
61
62/* --sort pid */
63
64static int64_t
65sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
66{
Adrian Hunter38051232013-07-04 16:20:31 +030067 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020068}
69
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030070static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030071 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020072{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020073 const char *comm = thread__comm_str(he->thread);
Namhyung Kimfb29a332012-12-27 18:11:40 +090074 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020075 comm ?: "", he->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020076}
77
Frederic Weisbecker872a8782011-06-29 03:14:52 +020078struct sort_entry sort_thread = {
79 .se_header = "Command: Pid",
80 .se_cmp = sort__thread_cmp,
81 .se_snprintf = hist_entry__thread_snprintf,
82 .se_width_idx = HISTC_THREAD,
83};
84
85/* --sort comm */
86
87static int64_t
88sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
89{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020090 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090091 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020092}
93
94static int64_t
95sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
96{
Namhyung Kim4dfced32013-09-13 16:28:57 +090097 /* Compare the addr that should be unique among comm */
98 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020099}
100
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300101static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300102 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200103{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900104 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200105}
106
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900107struct sort_entry sort_comm = {
108 .se_header = "Command",
109 .se_cmp = sort__comm_cmp,
110 .se_collapse = sort__comm_collapse,
111 .se_snprintf = hist_entry__comm_snprintf,
112 .se_width_idx = HISTC_COMM,
113};
114
115/* --sort dso */
116
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100117static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200118{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100119 struct dso *dso_l = map_l ? map_l->dso : NULL;
120 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300121 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200122
123 if (!dso_l || !dso_r)
124 return cmp_null(dso_l, dso_r);
125
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300126 if (verbose) {
127 dso_name_l = dso_l->long_name;
128 dso_name_r = dso_r->long_name;
129 } else {
130 dso_name_l = dso_l->short_name;
131 dso_name_r = dso_r->short_name;
132 }
133
134 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200135}
136
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100137static int64_t
138sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200139{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100140 return _sort__dso_cmp(left->ms.map, right->ms.map);
141}
142
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100143static int _hist_entry__dso_snprintf(struct map *map, char *bf,
144 size_t size, unsigned int width)
145{
146 if (map && map->dso) {
147 const char *dso_name = !verbose ? map->dso->short_name :
148 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300149 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300150 }
John Kacurdd68ada2009-09-24 18:02:49 +0200151
Ian Munsie1437a302010-12-06 13:37:04 +1100152 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200153}
154
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300155static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100156 size_t size, unsigned int width)
157{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300158 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100159}
160
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900161struct sort_entry sort_dso = {
162 .se_header = "Shared Object",
163 .se_cmp = sort__dso_cmp,
164 .se_snprintf = hist_entry__dso_snprintf,
165 .se_width_idx = HISTC_DSO,
166};
167
168/* --sort symbol */
169
Namhyung Kim2037be52013-12-18 14:21:09 +0900170static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
171{
172 return (int64_t)(right_ip - left_ip);
173}
174
Namhyung Kim51f27d12013-02-06 14:57:15 +0900175static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900176{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900177 u64 ip_l, ip_r;
178
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900179 if (!sym_l || !sym_r)
180 return cmp_null(sym_l, sym_r);
181
182 if (sym_l == sym_r)
183 return 0;
184
185 ip_l = sym_l->start;
186 ip_r = sym_r->start;
187
188 return (int64_t)(ip_r - ip_l);
189}
190
191static int64_t
192sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
193{
Namhyung Kim09600e02013-10-15 11:01:56 +0900194 int64_t ret;
195
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900196 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900197 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900198
Namhyung Kim09600e02013-10-15 11:01:56 +0900199 /*
200 * comparing symbol address alone is not enough since it's a
201 * relative address within a dso.
202 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900203 if (!sort__has_dso) {
204 ret = sort__dso_cmp(left, right);
205 if (ret != 0)
206 return ret;
207 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900208
Namhyung Kim51f27d12013-02-06 14:57:15 +0900209 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900210}
211
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100212static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
213 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900214 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100215{
216 size_t ret = 0;
217
218 if (verbose) {
219 char o = map ? dso__symtab_origin(map->dso) : '!';
220 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900221 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100222 }
223
224 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100225 if (sym && map) {
226 if (map->type == MAP__VARIABLE) {
227 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
228 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100229 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100230 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
231 width - ret, "");
232 } else {
233 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
234 width - ret,
235 sym->name);
236 }
237 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100238 size_t len = BITS_PER_LONG / 4;
239 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
240 len, ip);
241 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
242 width - ret, "");
243 }
244
245 return ret;
246}
247
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300248static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900249 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100250{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300251 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
252 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100253}
John Kacurdd68ada2009-09-24 18:02:49 +0200254
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200255struct sort_entry sort_sym = {
256 .se_header = "Symbol",
257 .se_cmp = sort__sym_cmp,
258 .se_snprintf = hist_entry__sym_snprintf,
259 .se_width_idx = HISTC_SYMBOL,
260};
John Kacurdd68ada2009-09-24 18:02:49 +0200261
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300262/* --sort srcline */
263
264static int64_t
265sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
266{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900267 if (!left->srcline) {
268 if (!left->ms.map)
269 left->srcline = SRCLINE_UNKNOWN;
270 else {
271 struct map *map = left->ms.map;
272 left->srcline = get_srcline(map->dso,
273 map__rip_2objdump(map, left->ip));
274 }
275 }
276 if (!right->srcline) {
277 if (!right->ms.map)
278 right->srcline = SRCLINE_UNKNOWN;
279 else {
280 struct map *map = right->ms.map;
281 right->srcline = get_srcline(map->dso,
282 map__rip_2objdump(map, right->ip));
283 }
284 }
285 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300286}
287
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300288static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300289 size_t size,
290 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300291{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300292 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300293}
294
295struct sort_entry sort_srcline = {
296 .se_header = "Source:Line",
297 .se_cmp = sort__srcline_cmp,
298 .se_snprintf = hist_entry__srcline_snprintf,
299 .se_width_idx = HISTC_SRCLINE,
300};
301
John Kacurdd68ada2009-09-24 18:02:49 +0200302/* --sort parent */
303
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200304static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200305sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
306{
307 struct symbol *sym_l = left->parent;
308 struct symbol *sym_r = right->parent;
309
310 if (!sym_l || !sym_r)
311 return cmp_null(sym_l, sym_r);
312
313 return strcmp(sym_l->name, sym_r->name);
314}
315
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300316static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300317 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200318{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300319 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300320 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200321}
322
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200323struct sort_entry sort_parent = {
324 .se_header = "Parent symbol",
325 .se_cmp = sort__parent_cmp,
326 .se_snprintf = hist_entry__parent_snprintf,
327 .se_width_idx = HISTC_PARENT,
328};
329
Arun Sharmaf60f3592010-06-04 11:27:10 -0300330/* --sort cpu */
331
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200332static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300333sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
334{
335 return right->cpu - left->cpu;
336}
337
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300338static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
339 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300340{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300341 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300342}
343
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200344struct sort_entry sort_cpu = {
345 .se_header = "CPU",
346 .se_cmp = sort__cpu_cmp,
347 .se_snprintf = hist_entry__cpu_snprintf,
348 .se_width_idx = HISTC_CPU,
349};
350
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900351/* sort keys for branch stacks */
352
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100353static int64_t
354sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
355{
356 return _sort__dso_cmp(left->branch_info->from.map,
357 right->branch_info->from.map);
358}
359
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300360static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100361 size_t size, unsigned int width)
362{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300363 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100364 bf, size, width);
365}
366
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100367static int64_t
368sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
369{
370 return _sort__dso_cmp(left->branch_info->to.map,
371 right->branch_info->to.map);
372}
373
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300374static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100375 size_t size, unsigned int width)
376{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300377 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100378 bf, size, width);
379}
380
381static int64_t
382sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct addr_map_symbol *from_l = &left->branch_info->from;
385 struct addr_map_symbol *from_r = &right->branch_info->from;
386
387 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900388 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100389
Namhyung Kim51f27d12013-02-06 14:57:15 +0900390 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100391}
392
393static int64_t
394sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
395{
396 struct addr_map_symbol *to_l = &left->branch_info->to;
397 struct addr_map_symbol *to_r = &right->branch_info->to;
398
399 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900400 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100401
Namhyung Kim51f27d12013-02-06 14:57:15 +0900402 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100403}
404
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300405static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900406 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300408 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300410 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411
412}
413
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300414static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900415 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100416{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300417 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100418 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300419 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100420
421}
422
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900423struct sort_entry sort_dso_from = {
424 .se_header = "Source Shared Object",
425 .se_cmp = sort__dso_from_cmp,
426 .se_snprintf = hist_entry__dso_from_snprintf,
427 .se_width_idx = HISTC_DSO_FROM,
428};
429
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100430struct sort_entry sort_dso_to = {
431 .se_header = "Target Shared Object",
432 .se_cmp = sort__dso_to_cmp,
433 .se_snprintf = hist_entry__dso_to_snprintf,
434 .se_width_idx = HISTC_DSO_TO,
435};
436
437struct sort_entry sort_sym_from = {
438 .se_header = "Source Symbol",
439 .se_cmp = sort__sym_from_cmp,
440 .se_snprintf = hist_entry__sym_from_snprintf,
441 .se_width_idx = HISTC_SYMBOL_FROM,
442};
443
444struct sort_entry sort_sym_to = {
445 .se_header = "Target Symbol",
446 .se_cmp = sort__sym_to_cmp,
447 .se_snprintf = hist_entry__sym_to_snprintf,
448 .se_width_idx = HISTC_SYMBOL_TO,
449};
450
451static int64_t
452sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
453{
454 const unsigned char mp = left->branch_info->flags.mispred !=
455 right->branch_info->flags.mispred;
456 const unsigned char p = left->branch_info->flags.predicted !=
457 right->branch_info->flags.predicted;
458
459 return mp || p;
460}
461
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300462static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100463 size_t size, unsigned int width){
464 static const char *out = "N/A";
465
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300466 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100467 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300468 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100469 out = "Y";
470
471 return repsep_snprintf(bf, size, "%-*s", width, out);
472}
473
Stephane Eranian98a3b322013-01-24 16:10:35 +0100474/* --sort daddr_sym */
475static int64_t
476sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
477{
478 uint64_t l = 0, r = 0;
479
480 if (left->mem_info)
481 l = left->mem_info->daddr.addr;
482 if (right->mem_info)
483 r = right->mem_info->daddr.addr;
484
485 return (int64_t)(r - l);
486}
487
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300488static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100489 size_t size, unsigned int width)
490{
491 uint64_t addr = 0;
492 struct map *map = NULL;
493 struct symbol *sym = NULL;
494
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300495 if (he->mem_info) {
496 addr = he->mem_info->daddr.addr;
497 map = he->mem_info->daddr.map;
498 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100499 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300500 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100501 width);
502}
503
504static int64_t
505sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
506{
507 struct map *map_l = NULL;
508 struct map *map_r = NULL;
509
510 if (left->mem_info)
511 map_l = left->mem_info->daddr.map;
512 if (right->mem_info)
513 map_r = right->mem_info->daddr.map;
514
515 return _sort__dso_cmp(map_l, map_r);
516}
517
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300518static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100519 size_t size, unsigned int width)
520{
521 struct map *map = NULL;
522
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300523 if (he->mem_info)
524 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100525
526 return _hist_entry__dso_snprintf(map, bf, size, width);
527}
528
529static int64_t
530sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
531{
532 union perf_mem_data_src data_src_l;
533 union perf_mem_data_src data_src_r;
534
535 if (left->mem_info)
536 data_src_l = left->mem_info->data_src;
537 else
538 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
539
540 if (right->mem_info)
541 data_src_r = right->mem_info->data_src;
542 else
543 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
544
545 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
546}
547
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300548static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100549 size_t size, unsigned int width)
550{
551 const char *out;
552 u64 mask = PERF_MEM_LOCK_NA;
553
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300554 if (he->mem_info)
555 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100556
557 if (mask & PERF_MEM_LOCK_NA)
558 out = "N/A";
559 else if (mask & PERF_MEM_LOCK_LOCKED)
560 out = "Yes";
561 else
562 out = "No";
563
564 return repsep_snprintf(bf, size, "%-*s", width, out);
565}
566
567static int64_t
568sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
569{
570 union perf_mem_data_src data_src_l;
571 union perf_mem_data_src data_src_r;
572
573 if (left->mem_info)
574 data_src_l = left->mem_info->data_src;
575 else
576 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
577
578 if (right->mem_info)
579 data_src_r = right->mem_info->data_src;
580 else
581 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
582
583 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
584}
585
586static const char * const tlb_access[] = {
587 "N/A",
588 "HIT",
589 "MISS",
590 "L1",
591 "L2",
592 "Walker",
593 "Fault",
594};
595#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
596
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300597static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100598 size_t size, unsigned int width)
599{
600 char out[64];
601 size_t sz = sizeof(out) - 1; /* -1 for null termination */
602 size_t l = 0, i;
603 u64 m = PERF_MEM_TLB_NA;
604 u64 hit, miss;
605
606 out[0] = '\0';
607
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300608 if (he->mem_info)
609 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100610
611 hit = m & PERF_MEM_TLB_HIT;
612 miss = m & PERF_MEM_TLB_MISS;
613
614 /* already taken care of */
615 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
616
617 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
618 if (!(m & 0x1))
619 continue;
620 if (l) {
621 strcat(out, " or ");
622 l += 4;
623 }
624 strncat(out, tlb_access[i], sz - l);
625 l += strlen(tlb_access[i]);
626 }
627 if (*out == '\0')
628 strcpy(out, "N/A");
629 if (hit)
630 strncat(out, " hit", sz - l);
631 if (miss)
632 strncat(out, " miss", sz - l);
633
634 return repsep_snprintf(bf, size, "%-*s", width, out);
635}
636
637static int64_t
638sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
639{
640 union perf_mem_data_src data_src_l;
641 union perf_mem_data_src data_src_r;
642
643 if (left->mem_info)
644 data_src_l = left->mem_info->data_src;
645 else
646 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
647
648 if (right->mem_info)
649 data_src_r = right->mem_info->data_src;
650 else
651 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
652
653 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
654}
655
656static const char * const mem_lvl[] = {
657 "N/A",
658 "HIT",
659 "MISS",
660 "L1",
661 "LFB",
662 "L2",
663 "L3",
664 "Local RAM",
665 "Remote RAM (1 hop)",
666 "Remote RAM (2 hops)",
667 "Remote Cache (1 hop)",
668 "Remote Cache (2 hops)",
669 "I/O",
670 "Uncached",
671};
672#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
673
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300674static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100675 size_t size, unsigned int width)
676{
677 char out[64];
678 size_t sz = sizeof(out) - 1; /* -1 for null termination */
679 size_t i, l = 0;
680 u64 m = PERF_MEM_LVL_NA;
681 u64 hit, miss;
682
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300683 if (he->mem_info)
684 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100685
686 out[0] = '\0';
687
688 hit = m & PERF_MEM_LVL_HIT;
689 miss = m & PERF_MEM_LVL_MISS;
690
691 /* already taken care of */
692 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
693
694 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
695 if (!(m & 0x1))
696 continue;
697 if (l) {
698 strcat(out, " or ");
699 l += 4;
700 }
701 strncat(out, mem_lvl[i], sz - l);
702 l += strlen(mem_lvl[i]);
703 }
704 if (*out == '\0')
705 strcpy(out, "N/A");
706 if (hit)
707 strncat(out, " hit", sz - l);
708 if (miss)
709 strncat(out, " miss", sz - l);
710
711 return repsep_snprintf(bf, size, "%-*s", width, out);
712}
713
714static int64_t
715sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
716{
717 union perf_mem_data_src data_src_l;
718 union perf_mem_data_src data_src_r;
719
720 if (left->mem_info)
721 data_src_l = left->mem_info->data_src;
722 else
723 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
724
725 if (right->mem_info)
726 data_src_r = right->mem_info->data_src;
727 else
728 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
729
730 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
731}
732
733static const char * const snoop_access[] = {
734 "N/A",
735 "None",
736 "Miss",
737 "Hit",
738 "HitM",
739};
740#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
741
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300742static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100743 size_t size, unsigned int width)
744{
745 char out[64];
746 size_t sz = sizeof(out) - 1; /* -1 for null termination */
747 size_t i, l = 0;
748 u64 m = PERF_MEM_SNOOP_NA;
749
750 out[0] = '\0';
751
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300752 if (he->mem_info)
753 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100754
755 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
756 if (!(m & 0x1))
757 continue;
758 if (l) {
759 strcat(out, " or ");
760 l += 4;
761 }
762 strncat(out, snoop_access[i], sz - l);
763 l += strlen(snoop_access[i]);
764 }
765
766 if (*out == '\0')
767 strcpy(out, "N/A");
768
769 return repsep_snprintf(bf, size, "%-*s", width, out);
770}
771
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100772struct sort_entry sort_mispredict = {
773 .se_header = "Branch Mispredicted",
774 .se_cmp = sort__mispredict_cmp,
775 .se_snprintf = hist_entry__mispredict_snprintf,
776 .se_width_idx = HISTC_MISPREDICT,
777};
778
Andi Kleen05484292013-01-24 16:10:29 +0100779static u64 he_weight(struct hist_entry *he)
780{
781 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
782}
783
784static int64_t
785sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
786{
787 return he_weight(left) - he_weight(right);
788}
789
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300790static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100791 size_t size, unsigned int width)
792{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300793 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100794}
795
796struct sort_entry sort_local_weight = {
797 .se_header = "Local Weight",
798 .se_cmp = sort__local_weight_cmp,
799 .se_snprintf = hist_entry__local_weight_snprintf,
800 .se_width_idx = HISTC_LOCAL_WEIGHT,
801};
802
803static int64_t
804sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
805{
806 return left->stat.weight - right->stat.weight;
807}
808
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300809static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100810 size_t size, unsigned int width)
811{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300812 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100813}
814
815struct sort_entry sort_global_weight = {
816 .se_header = "Weight",
817 .se_cmp = sort__global_weight_cmp,
818 .se_snprintf = hist_entry__global_weight_snprintf,
819 .se_width_idx = HISTC_GLOBAL_WEIGHT,
820};
821
Stephane Eranian98a3b322013-01-24 16:10:35 +0100822struct sort_entry sort_mem_daddr_sym = {
823 .se_header = "Data Symbol",
824 .se_cmp = sort__daddr_cmp,
825 .se_snprintf = hist_entry__daddr_snprintf,
826 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
827};
828
829struct sort_entry sort_mem_daddr_dso = {
830 .se_header = "Data Object",
831 .se_cmp = sort__dso_daddr_cmp,
832 .se_snprintf = hist_entry__dso_daddr_snprintf,
833 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
834};
835
836struct sort_entry sort_mem_locked = {
837 .se_header = "Locked",
838 .se_cmp = sort__locked_cmp,
839 .se_snprintf = hist_entry__locked_snprintf,
840 .se_width_idx = HISTC_MEM_LOCKED,
841};
842
843struct sort_entry sort_mem_tlb = {
844 .se_header = "TLB access",
845 .se_cmp = sort__tlb_cmp,
846 .se_snprintf = hist_entry__tlb_snprintf,
847 .se_width_idx = HISTC_MEM_TLB,
848};
849
850struct sort_entry sort_mem_lvl = {
851 .se_header = "Memory access",
852 .se_cmp = sort__lvl_cmp,
853 .se_snprintf = hist_entry__lvl_snprintf,
854 .se_width_idx = HISTC_MEM_LVL,
855};
856
857struct sort_entry sort_mem_snoop = {
858 .se_header = "Snoop",
859 .se_cmp = sort__snoop_cmp,
860 .se_snprintf = hist_entry__snoop_snprintf,
861 .se_width_idx = HISTC_MEM_SNOOP,
862};
863
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700864static int64_t
865sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
866{
867 return left->branch_info->flags.abort !=
868 right->branch_info->flags.abort;
869}
870
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300871static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700872 size_t size, unsigned int width)
873{
874 static const char *out = ".";
875
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300876 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700877 out = "A";
878 return repsep_snprintf(bf, size, "%-*s", width, out);
879}
880
881struct sort_entry sort_abort = {
882 .se_header = "Transaction abort",
883 .se_cmp = sort__abort_cmp,
884 .se_snprintf = hist_entry__abort_snprintf,
885 .se_width_idx = HISTC_ABORT,
886};
887
888static int64_t
889sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
890{
891 return left->branch_info->flags.in_tx !=
892 right->branch_info->flags.in_tx;
893}
894
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300895static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700896 size_t size, unsigned int width)
897{
898 static const char *out = ".";
899
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300900 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700901 out = "T";
902
903 return repsep_snprintf(bf, size, "%-*s", width, out);
904}
905
906struct sort_entry sort_in_tx = {
907 .se_header = "Branch in transaction",
908 .se_cmp = sort__in_tx_cmp,
909 .se_snprintf = hist_entry__in_tx_snprintf,
910 .se_width_idx = HISTC_IN_TX,
911};
912
Andi Kleen475eeab2013-09-20 07:40:43 -0700913static int64_t
914sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
915{
916 return left->transaction - right->transaction;
917}
918
919static inline char *add_str(char *p, const char *str)
920{
921 strcpy(p, str);
922 return p + strlen(str);
923}
924
925static struct txbit {
926 unsigned flag;
927 const char *name;
928 int skip_for_len;
929} txbits[] = {
930 { PERF_TXN_ELISION, "EL ", 0 },
931 { PERF_TXN_TRANSACTION, "TX ", 1 },
932 { PERF_TXN_SYNC, "SYNC ", 1 },
933 { PERF_TXN_ASYNC, "ASYNC ", 0 },
934 { PERF_TXN_RETRY, "RETRY ", 0 },
935 { PERF_TXN_CONFLICT, "CON ", 0 },
936 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
937 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
938 { 0, NULL, 0 }
939};
940
941int hist_entry__transaction_len(void)
942{
943 int i;
944 int len = 0;
945
946 for (i = 0; txbits[i].name; i++) {
947 if (!txbits[i].skip_for_len)
948 len += strlen(txbits[i].name);
949 }
950 len += 4; /* :XX<space> */
951 return len;
952}
953
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300954static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700955 size_t size, unsigned int width)
956{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300957 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700958 char buf[128];
959 char *p = buf;
960 int i;
961
962 buf[0] = 0;
963 for (i = 0; txbits[i].name; i++)
964 if (txbits[i].flag & t)
965 p = add_str(p, txbits[i].name);
966 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
967 p = add_str(p, "NEITHER ");
968 if (t & PERF_TXN_ABORT_MASK) {
969 sprintf(p, ":%" PRIx64,
970 (t & PERF_TXN_ABORT_MASK) >>
971 PERF_TXN_ABORT_SHIFT);
972 p += strlen(p);
973 }
974
975 return repsep_snprintf(bf, size, "%-*s", width, buf);
976}
977
978struct sort_entry sort_transaction = {
979 .se_header = "Transaction ",
980 .se_cmp = sort__transaction_cmp,
981 .se_snprintf = hist_entry__transaction_snprintf,
982 .se_width_idx = HISTC_TRANSACTION,
983};
984
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200985struct sort_dimension {
986 const char *name;
987 struct sort_entry *entry;
988 int taken;
989};
990
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100991#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
992
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900993static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100994 DIM(SORT_PID, "pid", sort_thread),
995 DIM(SORT_COMM, "comm", sort_comm),
996 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100997 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100998 DIM(SORT_PARENT, "parent", sort_parent),
999 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001000 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001001 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1002 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001003 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001004};
1005
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001006#undef DIM
1007
1008#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1009
1010static struct sort_dimension bstack_sort_dimensions[] = {
1011 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1012 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1013 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1014 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1015 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001016 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1017 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001018};
1019
1020#undef DIM
1021
Namhyung Kimafab87b2013-04-03 21:26:11 +09001022#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1023
1024static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001025 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1026 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1027 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1028 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1029 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1030 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1031};
1032
1033#undef DIM
1034
Namhyung Kima2ce0672014-03-04 09:06:42 +09001035struct hpp_dimension {
1036 const char *name;
1037 struct perf_hpp_fmt *fmt;
1038 int taken;
1039};
1040
1041#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1042
1043static struct hpp_dimension hpp_sort_dimensions[] = {
1044 DIM(PERF_HPP__OVERHEAD, "overhead"),
1045 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1046 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1047 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1048 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1049 DIM(PERF_HPP__SAMPLES, "sample"),
1050 DIM(PERF_HPP__PERIOD, "period"),
1051};
1052
1053#undef DIM
1054
Namhyung Kim8b536992014-03-03 11:46:55 +09001055struct hpp_sort_entry {
1056 struct perf_hpp_fmt hpp;
1057 struct sort_entry *se;
1058};
1059
1060static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1061 struct perf_evsel *evsel)
1062{
1063 struct hpp_sort_entry *hse;
1064 size_t len;
1065
1066 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1067 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1068
1069 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1070}
1071
1072static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1073 struct perf_hpp *hpp __maybe_unused,
1074 struct perf_evsel *evsel)
1075{
1076 struct hpp_sort_entry *hse;
1077
1078 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1079
1080 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1081}
1082
1083static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1084 struct hist_entry *he)
1085{
1086 struct hpp_sort_entry *hse;
1087 size_t len;
1088
1089 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1090 len = hists__col_len(he->hists, hse->se->se_width_idx);
1091
1092 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1093}
1094
1095static int __sort_dimension__add_hpp(struct sort_dimension *sd)
1096{
1097 struct hpp_sort_entry *hse;
1098
1099 hse = malloc(sizeof(*hse));
1100 if (hse == NULL) {
1101 pr_err("Memory allocation failed\n");
1102 return -1;
1103 }
1104
1105 hse->se = sd->entry;
1106 hse->hpp.header = __sort__hpp_header;
1107 hse->hpp.width = __sort__hpp_width;
1108 hse->hpp.entry = __sort__hpp_entry;
1109 hse->hpp.color = NULL;
1110
1111 hse->hpp.cmp = sd->entry->se_cmp;
1112 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1113 hse->hpp.sort = hse->hpp.collapse;
1114
1115 INIT_LIST_HEAD(&hse->hpp.list);
1116 INIT_LIST_HEAD(&hse->hpp.sort_list);
1117
1118 perf_hpp__register_sort_field(&hse->hpp);
1119 return 0;
1120}
1121
1122static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001123{
1124 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001125 return 0;
1126
1127 if (__sort_dimension__add_hpp(sd) < 0)
1128 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001129
1130 if (sd->entry->se_collapse)
1131 sort__need_collapse = 1;
1132
1133 if (list_empty(&hist_entry__sort_list))
1134 sort__first_dimension = idx;
1135
1136 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1137 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001138
1139 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001140}
1141
Namhyung Kima2ce0672014-03-04 09:06:42 +09001142static int __hpp_dimension__add(struct hpp_dimension *hd)
1143{
1144 if (!hd->taken) {
1145 hd->taken = 1;
1146
1147 perf_hpp__register_sort_field(hd->fmt);
1148 }
1149 return 0;
1150}
1151
John Kacurdd68ada2009-09-24 18:02:49 +02001152int sort_dimension__add(const char *tok)
1153{
1154 unsigned int i;
1155
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001156 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1157 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001158
John Kacurdd68ada2009-09-24 18:02:49 +02001159 if (strncasecmp(tok, sd->name, strlen(tok)))
1160 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001161
John Kacurdd68ada2009-09-24 18:02:49 +02001162 if (sd->entry == &sort_parent) {
1163 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1164 if (ret) {
1165 char err[BUFSIZ];
1166
1167 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001168 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1169 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001170 }
1171 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001172 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001173 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001174 } else if (sd->entry == &sort_dso) {
1175 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001176 }
1177
Namhyung Kim8b536992014-03-03 11:46:55 +09001178 return __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001179 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001180
Namhyung Kima2ce0672014-03-04 09:06:42 +09001181 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1182 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1183
1184 if (strncasecmp(tok, hd->name, strlen(tok)))
1185 continue;
1186
1187 return __hpp_dimension__add(hd);
1188 }
1189
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001190 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1191 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1192
1193 if (strncasecmp(tok, sd->name, strlen(tok)))
1194 continue;
1195
Namhyung Kim55369fc2013-04-01 20:35:20 +09001196 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001197 return -EINVAL;
1198
1199 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1200 sort__has_sym = 1;
1201
Namhyung Kim2f532d092013-04-03 21:26:10 +09001202 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001203 return 0;
1204 }
1205
Namhyung Kimafab87b2013-04-03 21:26:11 +09001206 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1207 struct sort_dimension *sd = &memory_sort_dimensions[i];
1208
1209 if (strncasecmp(tok, sd->name, strlen(tok)))
1210 continue;
1211
1212 if (sort__mode != SORT_MODE__MEMORY)
1213 return -EINVAL;
1214
1215 if (sd->entry == &sort_mem_daddr_sym)
1216 sort__has_sym = 1;
1217
1218 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1219 return 0;
1220 }
1221
John Kacurdd68ada2009-09-24 18:02:49 +02001222 return -ESRCH;
1223}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001224
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001225static const char *get_default_sort_order(void)
1226{
1227 const char *default_sort_orders[] = {
1228 default_sort_order,
1229 default_branch_sort_order,
1230 default_mem_sort_order,
1231 default_top_sort_order,
1232 default_diff_sort_order,
1233 };
1234
1235 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1236
1237 return default_sort_orders[sort__mode];
1238}
1239
Namhyung Kim55309982013-02-06 14:57:16 +09001240int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001241{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001242 char *tmp, *tok, *str;
1243 const char *sort_keys = sort_order;
Namhyung Kim55309982013-02-06 14:57:16 +09001244 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001245
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001246 if (sort_keys == NULL)
1247 sort_keys = get_default_sort_order();
1248
1249 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001250 if (str == NULL) {
1251 error("Not enough memory to setup sort keys");
1252 return -ENOMEM;
1253 }
1254
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001255 for (tok = strtok_r(str, ", ", &tmp);
1256 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001257 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001258 if (ret == -EINVAL) {
1259 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001260 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001261 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001262 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001263 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001264 }
1265 }
1266
1267 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001268 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001269}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001270
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001271static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001272 struct strlist *list,
1273 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001274{
1275 if (list && strlist__nr_entries(list) == 1) {
1276 if (fp != NULL)
1277 fprintf(fp, "# %s: %s\n", list_name,
1278 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001279 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001280 }
1281}
Namhyung Kim08e71542013-04-03 21:26:19 +09001282
1283void sort__setup_elide(FILE *output)
1284{
Namhyung Kim7524f632013-11-08 17:53:42 +09001285 struct sort_entry *se;
1286
Namhyung Kim08e71542013-04-03 21:26:19 +09001287 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1288 "dso", output);
1289 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1290 "comm", output);
1291 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1292 "symbol", output);
1293
1294 if (sort__mode == SORT_MODE__BRANCH) {
1295 sort_entry__setup_elide(&sort_dso_from,
1296 symbol_conf.dso_from_list,
1297 "dso_from", output);
1298 sort_entry__setup_elide(&sort_dso_to,
1299 symbol_conf.dso_to_list,
1300 "dso_to", output);
1301 sort_entry__setup_elide(&sort_sym_from,
1302 symbol_conf.sym_from_list,
1303 "sym_from", output);
1304 sort_entry__setup_elide(&sort_sym_to,
1305 symbol_conf.sym_to_list,
1306 "sym_to", output);
1307 } else if (sort__mode == SORT_MODE__MEMORY) {
1308 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1309 "symbol_daddr", output);
1310 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1311 "dso_daddr", output);
1312 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1313 "mem", output);
1314 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1315 "local_weight", output);
1316 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1317 "tlb", output);
1318 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1319 "snoop", output);
1320 }
1321
Namhyung Kim7524f632013-11-08 17:53:42 +09001322 /*
1323 * It makes no sense to elide all of sort entries.
1324 * Just revert them to show up again.
1325 */
1326 list_for_each_entry(se, &hist_entry__sort_list, list) {
1327 if (!se->elide)
1328 return;
1329 }
1330
1331 list_for_each_entry(se, &hist_entry__sort_list, list)
1332 se->elide = false;
Namhyung Kim08e71542013-04-03 21:26:19 +09001333}