blob: 0fe7cbe47ea34790680705b5151852598aeea4ff [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;
Namhyung Kima7d945b2014-03-04 10:46:34 +090016const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080017regex_t ignore_callees_regex;
18int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020019int sort__need_collapse = 0;
20int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090021int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090022int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090023enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020024
25enum sort_type sort__first_dimension;
John Kacurdd68ada2009-09-24 18:02:49 +020026
John Kacurdd68ada2009-09-24 18:02:49 +020027LIST_HEAD(hist_entry__sort_list);
28
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030029static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020030{
31 int n;
32 va_list ap;
33
34 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030035 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020036 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030037 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020038
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030039 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020040 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030041 if (sep == NULL)
42 break;
43 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020044 }
John Kacurdd68ada2009-09-24 18:02:49 +020045 }
46 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110047
48 if (n >= (int)size)
49 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020050 return n;
51}
52
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020053static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020054{
55 if (!l && !r)
56 return 0;
57 else if (!l)
58 return -1;
59 else
60 return 1;
61}
62
63/* --sort pid */
64
65static int64_t
66sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
67{
Adrian Hunter38051232013-07-04 16:20:31 +030068 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020069}
70
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030071static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030072 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020073{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020074 const char *comm = thread__comm_str(he->thread);
Namhyung Kimfb29a332012-12-27 18:11:40 +090075 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020076 comm ?: "", he->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020077}
78
Frederic Weisbecker872a8782011-06-29 03:14:52 +020079struct sort_entry sort_thread = {
80 .se_header = "Command: Pid",
81 .se_cmp = sort__thread_cmp,
82 .se_snprintf = hist_entry__thread_snprintf,
83 .se_width_idx = HISTC_THREAD,
84};
85
86/* --sort comm */
87
88static int64_t
89sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
90{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020091 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090092 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020093}
94
95static int64_t
96sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97{
Namhyung Kim4dfced32013-09-13 16:28:57 +090098 /* Compare the addr that should be unique among comm */
99 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200100}
101
Namhyung Kim202e7a62014-03-04 11:01:41 +0900102static int64_t
103sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104{
105 return strcmp(comm__str(right->comm), comm__str(left->comm));
106}
107
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300108static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300109 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200110{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900111 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200112}
113
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900114struct sort_entry sort_comm = {
115 .se_header = "Command",
116 .se_cmp = sort__comm_cmp,
117 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900118 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900119 .se_snprintf = hist_entry__comm_snprintf,
120 .se_width_idx = HISTC_COMM,
121};
122
123/* --sort dso */
124
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100125static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200126{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100127 struct dso *dso_l = map_l ? map_l->dso : NULL;
128 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300129 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200130
131 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900132 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200133
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300134 if (verbose) {
135 dso_name_l = dso_l->long_name;
136 dso_name_r = dso_r->long_name;
137 } else {
138 dso_name_l = dso_l->short_name;
139 dso_name_r = dso_r->short_name;
140 }
141
142 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200143}
144
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100145static int64_t
146sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200147{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900148 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149}
150
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100151static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 size_t size, unsigned int width)
153{
154 if (map && map->dso) {
155 const char *dso_name = !verbose ? map->dso->short_name :
156 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300157 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300158 }
John Kacurdd68ada2009-09-24 18:02:49 +0200159
Ian Munsie1437a302010-12-06 13:37:04 +1100160 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200161}
162
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300163static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164 size_t size, unsigned int width)
165{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300166 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100167}
168
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900169struct sort_entry sort_dso = {
170 .se_header = "Shared Object",
171 .se_cmp = sort__dso_cmp,
172 .se_snprintf = hist_entry__dso_snprintf,
173 .se_width_idx = HISTC_DSO,
174};
175
176/* --sort symbol */
177
Namhyung Kim2037be52013-12-18 14:21:09 +0900178static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179{
180 return (int64_t)(right_ip - left_ip);
181}
182
Namhyung Kim51f27d12013-02-06 14:57:15 +0900183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900184{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900185 u64 ip_l, ip_r;
186
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187 if (!sym_l || !sym_r)
188 return cmp_null(sym_l, sym_r);
189
190 if (sym_l == sym_r)
191 return 0;
192
193 ip_l = sym_l->start;
194 ip_r = sym_r->start;
195
196 return (int64_t)(ip_r - ip_l);
197}
198
199static int64_t
200sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
201{
Namhyung Kim09600e02013-10-15 11:01:56 +0900202 int64_t ret;
203
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900205 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Namhyung Kim09600e02013-10-15 11:01:56 +0900207 /*
208 * comparing symbol address alone is not enough since it's a
209 * relative address within a dso.
210 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900211 if (!sort__has_dso) {
212 ret = sort__dso_cmp(left, right);
213 if (ret != 0)
214 return ret;
215 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900216
Namhyung Kim51f27d12013-02-06 14:57:15 +0900217 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900218}
219
Namhyung Kim202e7a62014-03-04 11:01:41 +0900220static int64_t
221sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
222{
223 if (!left->ms.sym || !right->ms.sym)
224 return cmp_null(left->ms.sym, right->ms.sym);
225
226 return strcmp(right->ms.sym->name, left->ms.sym->name);
227}
228
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
230 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900231 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100232{
233 size_t ret = 0;
234
235 if (verbose) {
236 char o = map ? dso__symtab_origin(map->dso) : '!';
237 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900238 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239 }
240
241 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100242 if (sym && map) {
243 if (map->type == MAP__VARIABLE) {
244 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
245 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100246 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100247 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
248 width - ret, "");
249 } else {
250 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
251 width - ret,
252 sym->name);
253 }
254 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100255 size_t len = BITS_PER_LONG / 4;
256 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
257 len, ip);
258 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259 width - ret, "");
260 }
261
262 return ret;
263}
264
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300265static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900266 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100267{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300268 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
269 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270}
John Kacurdd68ada2009-09-24 18:02:49 +0200271
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200272struct sort_entry sort_sym = {
273 .se_header = "Symbol",
274 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900275 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200276 .se_snprintf = hist_entry__sym_snprintf,
277 .se_width_idx = HISTC_SYMBOL,
278};
John Kacurdd68ada2009-09-24 18:02:49 +0200279
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300280/* --sort srcline */
281
282static int64_t
283sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
284{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900285 if (!left->srcline) {
286 if (!left->ms.map)
287 left->srcline = SRCLINE_UNKNOWN;
288 else {
289 struct map *map = left->ms.map;
290 left->srcline = get_srcline(map->dso,
291 map__rip_2objdump(map, left->ip));
292 }
293 }
294 if (!right->srcline) {
295 if (!right->ms.map)
296 right->srcline = SRCLINE_UNKNOWN;
297 else {
298 struct map *map = right->ms.map;
299 right->srcline = get_srcline(map->dso,
300 map__rip_2objdump(map, right->ip));
301 }
302 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900303 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300304}
305
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300306static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300307 size_t size,
308 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300309{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300310 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300311}
312
313struct sort_entry sort_srcline = {
314 .se_header = "Source:Line",
315 .se_cmp = sort__srcline_cmp,
316 .se_snprintf = hist_entry__srcline_snprintf,
317 .se_width_idx = HISTC_SRCLINE,
318};
319
John Kacurdd68ada2009-09-24 18:02:49 +0200320/* --sort parent */
321
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200322static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200323sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
324{
325 struct symbol *sym_l = left->parent;
326 struct symbol *sym_r = right->parent;
327
328 if (!sym_l || !sym_r)
329 return cmp_null(sym_l, sym_r);
330
Namhyung Kim202e7a62014-03-04 11:01:41 +0900331 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200332}
333
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300334static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300335 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200336{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300337 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300338 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200339}
340
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200341struct sort_entry sort_parent = {
342 .se_header = "Parent symbol",
343 .se_cmp = sort__parent_cmp,
344 .se_snprintf = hist_entry__parent_snprintf,
345 .se_width_idx = HISTC_PARENT,
346};
347
Arun Sharmaf60f3592010-06-04 11:27:10 -0300348/* --sort cpu */
349
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200350static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300351sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
352{
353 return right->cpu - left->cpu;
354}
355
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300356static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
357 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300358{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300359 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300360}
361
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200362struct sort_entry sort_cpu = {
363 .se_header = "CPU",
364 .se_cmp = sort__cpu_cmp,
365 .se_snprintf = hist_entry__cpu_snprintf,
366 .se_width_idx = HISTC_CPU,
367};
368
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900369/* sort keys for branch stacks */
370
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100371static int64_t
372sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
373{
374 return _sort__dso_cmp(left->branch_info->from.map,
375 right->branch_info->from.map);
376}
377
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300378static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100379 size_t size, unsigned int width)
380{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300381 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100382 bf, size, width);
383}
384
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100385static int64_t
386sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
387{
388 return _sort__dso_cmp(left->branch_info->to.map,
389 right->branch_info->to.map);
390}
391
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300392static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393 size_t size, unsigned int width)
394{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300395 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100396 bf, size, width);
397}
398
399static int64_t
400sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
401{
402 struct addr_map_symbol *from_l = &left->branch_info->from;
403 struct addr_map_symbol *from_r = &right->branch_info->from;
404
405 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900406 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407
Namhyung Kim51f27d12013-02-06 14:57:15 +0900408 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409}
410
411static int64_t
412sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
413{
414 struct addr_map_symbol *to_l = &left->branch_info->to;
415 struct addr_map_symbol *to_r = &right->branch_info->to;
416
417 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900418 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100419
Namhyung Kim51f27d12013-02-06 14:57:15 +0900420 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421}
422
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300423static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900424 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100425{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300426 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300428 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429
430}
431
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300432static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900433 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100434{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300435 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100436 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300437 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100438
439}
440
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900441struct sort_entry sort_dso_from = {
442 .se_header = "Source Shared Object",
443 .se_cmp = sort__dso_from_cmp,
444 .se_snprintf = hist_entry__dso_from_snprintf,
445 .se_width_idx = HISTC_DSO_FROM,
446};
447
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100448struct sort_entry sort_dso_to = {
449 .se_header = "Target Shared Object",
450 .se_cmp = sort__dso_to_cmp,
451 .se_snprintf = hist_entry__dso_to_snprintf,
452 .se_width_idx = HISTC_DSO_TO,
453};
454
455struct sort_entry sort_sym_from = {
456 .se_header = "Source Symbol",
457 .se_cmp = sort__sym_from_cmp,
458 .se_snprintf = hist_entry__sym_from_snprintf,
459 .se_width_idx = HISTC_SYMBOL_FROM,
460};
461
462struct sort_entry sort_sym_to = {
463 .se_header = "Target Symbol",
464 .se_cmp = sort__sym_to_cmp,
465 .se_snprintf = hist_entry__sym_to_snprintf,
466 .se_width_idx = HISTC_SYMBOL_TO,
467};
468
469static int64_t
470sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
471{
472 const unsigned char mp = left->branch_info->flags.mispred !=
473 right->branch_info->flags.mispred;
474 const unsigned char p = left->branch_info->flags.predicted !=
475 right->branch_info->flags.predicted;
476
477 return mp || p;
478}
479
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300480static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100481 size_t size, unsigned int width){
482 static const char *out = "N/A";
483
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300484 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100485 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300486 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100487 out = "Y";
488
489 return repsep_snprintf(bf, size, "%-*s", width, out);
490}
491
Stephane Eranian98a3b322013-01-24 16:10:35 +0100492/* --sort daddr_sym */
493static int64_t
494sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
495{
496 uint64_t l = 0, r = 0;
497
498 if (left->mem_info)
499 l = left->mem_info->daddr.addr;
500 if (right->mem_info)
501 r = right->mem_info->daddr.addr;
502
503 return (int64_t)(r - l);
504}
505
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300506static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100507 size_t size, unsigned int width)
508{
509 uint64_t addr = 0;
510 struct map *map = NULL;
511 struct symbol *sym = NULL;
512
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300513 if (he->mem_info) {
514 addr = he->mem_info->daddr.addr;
515 map = he->mem_info->daddr.map;
516 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100517 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300518 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100519 width);
520}
521
522static int64_t
523sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
524{
525 struct map *map_l = NULL;
526 struct map *map_r = NULL;
527
528 if (left->mem_info)
529 map_l = left->mem_info->daddr.map;
530 if (right->mem_info)
531 map_r = right->mem_info->daddr.map;
532
533 return _sort__dso_cmp(map_l, map_r);
534}
535
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300536static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100537 size_t size, unsigned int width)
538{
539 struct map *map = NULL;
540
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300541 if (he->mem_info)
542 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100543
544 return _hist_entry__dso_snprintf(map, bf, size, width);
545}
546
547static int64_t
548sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
549{
550 union perf_mem_data_src data_src_l;
551 union perf_mem_data_src data_src_r;
552
553 if (left->mem_info)
554 data_src_l = left->mem_info->data_src;
555 else
556 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
557
558 if (right->mem_info)
559 data_src_r = right->mem_info->data_src;
560 else
561 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
562
563 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
564}
565
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300566static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100567 size_t size, unsigned int width)
568{
569 const char *out;
570 u64 mask = PERF_MEM_LOCK_NA;
571
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300572 if (he->mem_info)
573 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100574
575 if (mask & PERF_MEM_LOCK_NA)
576 out = "N/A";
577 else if (mask & PERF_MEM_LOCK_LOCKED)
578 out = "Yes";
579 else
580 out = "No";
581
582 return repsep_snprintf(bf, size, "%-*s", width, out);
583}
584
585static int64_t
586sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
587{
588 union perf_mem_data_src data_src_l;
589 union perf_mem_data_src data_src_r;
590
591 if (left->mem_info)
592 data_src_l = left->mem_info->data_src;
593 else
594 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
595
596 if (right->mem_info)
597 data_src_r = right->mem_info->data_src;
598 else
599 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
600
601 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
602}
603
604static const char * const tlb_access[] = {
605 "N/A",
606 "HIT",
607 "MISS",
608 "L1",
609 "L2",
610 "Walker",
611 "Fault",
612};
613#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
614
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300615static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100616 size_t size, unsigned int width)
617{
618 char out[64];
619 size_t sz = sizeof(out) - 1; /* -1 for null termination */
620 size_t l = 0, i;
621 u64 m = PERF_MEM_TLB_NA;
622 u64 hit, miss;
623
624 out[0] = '\0';
625
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300626 if (he->mem_info)
627 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100628
629 hit = m & PERF_MEM_TLB_HIT;
630 miss = m & PERF_MEM_TLB_MISS;
631
632 /* already taken care of */
633 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
634
635 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
636 if (!(m & 0x1))
637 continue;
638 if (l) {
639 strcat(out, " or ");
640 l += 4;
641 }
642 strncat(out, tlb_access[i], sz - l);
643 l += strlen(tlb_access[i]);
644 }
645 if (*out == '\0')
646 strcpy(out, "N/A");
647 if (hit)
648 strncat(out, " hit", sz - l);
649 if (miss)
650 strncat(out, " miss", sz - l);
651
652 return repsep_snprintf(bf, size, "%-*s", width, out);
653}
654
655static int64_t
656sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
657{
658 union perf_mem_data_src data_src_l;
659 union perf_mem_data_src data_src_r;
660
661 if (left->mem_info)
662 data_src_l = left->mem_info->data_src;
663 else
664 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
665
666 if (right->mem_info)
667 data_src_r = right->mem_info->data_src;
668 else
669 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
670
671 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
672}
673
674static const char * const mem_lvl[] = {
675 "N/A",
676 "HIT",
677 "MISS",
678 "L1",
679 "LFB",
680 "L2",
681 "L3",
682 "Local RAM",
683 "Remote RAM (1 hop)",
684 "Remote RAM (2 hops)",
685 "Remote Cache (1 hop)",
686 "Remote Cache (2 hops)",
687 "I/O",
688 "Uncached",
689};
690#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
691
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300692static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100693 size_t size, unsigned int width)
694{
695 char out[64];
696 size_t sz = sizeof(out) - 1; /* -1 for null termination */
697 size_t i, l = 0;
698 u64 m = PERF_MEM_LVL_NA;
699 u64 hit, miss;
700
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300701 if (he->mem_info)
702 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100703
704 out[0] = '\0';
705
706 hit = m & PERF_MEM_LVL_HIT;
707 miss = m & PERF_MEM_LVL_MISS;
708
709 /* already taken care of */
710 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
711
712 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
713 if (!(m & 0x1))
714 continue;
715 if (l) {
716 strcat(out, " or ");
717 l += 4;
718 }
719 strncat(out, mem_lvl[i], sz - l);
720 l += strlen(mem_lvl[i]);
721 }
722 if (*out == '\0')
723 strcpy(out, "N/A");
724 if (hit)
725 strncat(out, " hit", sz - l);
726 if (miss)
727 strncat(out, " miss", sz - l);
728
729 return repsep_snprintf(bf, size, "%-*s", width, out);
730}
731
732static int64_t
733sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
734{
735 union perf_mem_data_src data_src_l;
736 union perf_mem_data_src data_src_r;
737
738 if (left->mem_info)
739 data_src_l = left->mem_info->data_src;
740 else
741 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
742
743 if (right->mem_info)
744 data_src_r = right->mem_info->data_src;
745 else
746 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
747
748 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
749}
750
751static const char * const snoop_access[] = {
752 "N/A",
753 "None",
754 "Miss",
755 "Hit",
756 "HitM",
757};
758#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
759
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300760static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100761 size_t size, unsigned int width)
762{
763 char out[64];
764 size_t sz = sizeof(out) - 1; /* -1 for null termination */
765 size_t i, l = 0;
766 u64 m = PERF_MEM_SNOOP_NA;
767
768 out[0] = '\0';
769
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300770 if (he->mem_info)
771 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100772
773 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
774 if (!(m & 0x1))
775 continue;
776 if (l) {
777 strcat(out, " or ");
778 l += 4;
779 }
780 strncat(out, snoop_access[i], sz - l);
781 l += strlen(snoop_access[i]);
782 }
783
784 if (*out == '\0')
785 strcpy(out, "N/A");
786
787 return repsep_snprintf(bf, size, "%-*s", width, out);
788}
789
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100790struct sort_entry sort_mispredict = {
791 .se_header = "Branch Mispredicted",
792 .se_cmp = sort__mispredict_cmp,
793 .se_snprintf = hist_entry__mispredict_snprintf,
794 .se_width_idx = HISTC_MISPREDICT,
795};
796
Andi Kleen05484292013-01-24 16:10:29 +0100797static u64 he_weight(struct hist_entry *he)
798{
799 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
800}
801
802static int64_t
803sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
804{
805 return he_weight(left) - he_weight(right);
806}
807
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300808static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100809 size_t size, unsigned int width)
810{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300811 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100812}
813
814struct sort_entry sort_local_weight = {
815 .se_header = "Local Weight",
816 .se_cmp = sort__local_weight_cmp,
817 .se_snprintf = hist_entry__local_weight_snprintf,
818 .se_width_idx = HISTC_LOCAL_WEIGHT,
819};
820
821static int64_t
822sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
823{
824 return left->stat.weight - right->stat.weight;
825}
826
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300827static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100828 size_t size, unsigned int width)
829{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300830 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100831}
832
833struct sort_entry sort_global_weight = {
834 .se_header = "Weight",
835 .se_cmp = sort__global_weight_cmp,
836 .se_snprintf = hist_entry__global_weight_snprintf,
837 .se_width_idx = HISTC_GLOBAL_WEIGHT,
838};
839
Stephane Eranian98a3b322013-01-24 16:10:35 +0100840struct sort_entry sort_mem_daddr_sym = {
841 .se_header = "Data Symbol",
842 .se_cmp = sort__daddr_cmp,
843 .se_snprintf = hist_entry__daddr_snprintf,
844 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
845};
846
847struct sort_entry sort_mem_daddr_dso = {
848 .se_header = "Data Object",
849 .se_cmp = sort__dso_daddr_cmp,
850 .se_snprintf = hist_entry__dso_daddr_snprintf,
851 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
852};
853
854struct sort_entry sort_mem_locked = {
855 .se_header = "Locked",
856 .se_cmp = sort__locked_cmp,
857 .se_snprintf = hist_entry__locked_snprintf,
858 .se_width_idx = HISTC_MEM_LOCKED,
859};
860
861struct sort_entry sort_mem_tlb = {
862 .se_header = "TLB access",
863 .se_cmp = sort__tlb_cmp,
864 .se_snprintf = hist_entry__tlb_snprintf,
865 .se_width_idx = HISTC_MEM_TLB,
866};
867
868struct sort_entry sort_mem_lvl = {
869 .se_header = "Memory access",
870 .se_cmp = sort__lvl_cmp,
871 .se_snprintf = hist_entry__lvl_snprintf,
872 .se_width_idx = HISTC_MEM_LVL,
873};
874
875struct sort_entry sort_mem_snoop = {
876 .se_header = "Snoop",
877 .se_cmp = sort__snoop_cmp,
878 .se_snprintf = hist_entry__snoop_snprintf,
879 .se_width_idx = HISTC_MEM_SNOOP,
880};
881
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700882static int64_t
883sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
884{
885 return left->branch_info->flags.abort !=
886 right->branch_info->flags.abort;
887}
888
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300889static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700890 size_t size, unsigned int width)
891{
892 static const char *out = ".";
893
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300894 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700895 out = "A";
896 return repsep_snprintf(bf, size, "%-*s", width, out);
897}
898
899struct sort_entry sort_abort = {
900 .se_header = "Transaction abort",
901 .se_cmp = sort__abort_cmp,
902 .se_snprintf = hist_entry__abort_snprintf,
903 .se_width_idx = HISTC_ABORT,
904};
905
906static int64_t
907sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
908{
909 return left->branch_info->flags.in_tx !=
910 right->branch_info->flags.in_tx;
911}
912
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300913static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700914 size_t size, unsigned int width)
915{
916 static const char *out = ".";
917
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300918 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700919 out = "T";
920
921 return repsep_snprintf(bf, size, "%-*s", width, out);
922}
923
924struct sort_entry sort_in_tx = {
925 .se_header = "Branch in transaction",
926 .se_cmp = sort__in_tx_cmp,
927 .se_snprintf = hist_entry__in_tx_snprintf,
928 .se_width_idx = HISTC_IN_TX,
929};
930
Andi Kleen475eeab2013-09-20 07:40:43 -0700931static int64_t
932sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
933{
934 return left->transaction - right->transaction;
935}
936
937static inline char *add_str(char *p, const char *str)
938{
939 strcpy(p, str);
940 return p + strlen(str);
941}
942
943static struct txbit {
944 unsigned flag;
945 const char *name;
946 int skip_for_len;
947} txbits[] = {
948 { PERF_TXN_ELISION, "EL ", 0 },
949 { PERF_TXN_TRANSACTION, "TX ", 1 },
950 { PERF_TXN_SYNC, "SYNC ", 1 },
951 { PERF_TXN_ASYNC, "ASYNC ", 0 },
952 { PERF_TXN_RETRY, "RETRY ", 0 },
953 { PERF_TXN_CONFLICT, "CON ", 0 },
954 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
955 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
956 { 0, NULL, 0 }
957};
958
959int hist_entry__transaction_len(void)
960{
961 int i;
962 int len = 0;
963
964 for (i = 0; txbits[i].name; i++) {
965 if (!txbits[i].skip_for_len)
966 len += strlen(txbits[i].name);
967 }
968 len += 4; /* :XX<space> */
969 return len;
970}
971
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300972static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700973 size_t size, unsigned int width)
974{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300975 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700976 char buf[128];
977 char *p = buf;
978 int i;
979
980 buf[0] = 0;
981 for (i = 0; txbits[i].name; i++)
982 if (txbits[i].flag & t)
983 p = add_str(p, txbits[i].name);
984 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
985 p = add_str(p, "NEITHER ");
986 if (t & PERF_TXN_ABORT_MASK) {
987 sprintf(p, ":%" PRIx64,
988 (t & PERF_TXN_ABORT_MASK) >>
989 PERF_TXN_ABORT_SHIFT);
990 p += strlen(p);
991 }
992
993 return repsep_snprintf(bf, size, "%-*s", width, buf);
994}
995
996struct sort_entry sort_transaction = {
997 .se_header = "Transaction ",
998 .se_cmp = sort__transaction_cmp,
999 .se_snprintf = hist_entry__transaction_snprintf,
1000 .se_width_idx = HISTC_TRANSACTION,
1001};
1002
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001003struct sort_dimension {
1004 const char *name;
1005 struct sort_entry *entry;
1006 int taken;
1007};
1008
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001009#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1010
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001011static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001012 DIM(SORT_PID, "pid", sort_thread),
1013 DIM(SORT_COMM, "comm", sort_comm),
1014 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001015 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001016 DIM(SORT_PARENT, "parent", sort_parent),
1017 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001018 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001019 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1020 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001021 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001022};
1023
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001024#undef DIM
1025
1026#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1027
1028static struct sort_dimension bstack_sort_dimensions[] = {
1029 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1030 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1031 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1032 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1033 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001034 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1035 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001036};
1037
1038#undef DIM
1039
Namhyung Kimafab87b2013-04-03 21:26:11 +09001040#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1041
1042static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001043 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1044 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1045 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1046 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1047 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1048 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1049};
1050
1051#undef DIM
1052
Namhyung Kima2ce0672014-03-04 09:06:42 +09001053struct hpp_dimension {
1054 const char *name;
1055 struct perf_hpp_fmt *fmt;
1056 int taken;
1057};
1058
1059#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1060
1061static struct hpp_dimension hpp_sort_dimensions[] = {
1062 DIM(PERF_HPP__OVERHEAD, "overhead"),
1063 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1064 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1065 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1066 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1067 DIM(PERF_HPP__SAMPLES, "sample"),
1068 DIM(PERF_HPP__PERIOD, "period"),
1069};
1070
1071#undef DIM
1072
Namhyung Kim8b536992014-03-03 11:46:55 +09001073struct hpp_sort_entry {
1074 struct perf_hpp_fmt hpp;
1075 struct sort_entry *se;
1076};
1077
Namhyung Kima7d945b2014-03-04 10:46:34 +09001078bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1079{
1080 struct hpp_sort_entry *hse_a;
1081 struct hpp_sort_entry *hse_b;
1082
1083 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1084 return false;
1085
1086 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1087 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1088
1089 return hse_a->se == hse_b->se;
1090}
1091
Namhyung Kim8b536992014-03-03 11:46:55 +09001092static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1093 struct perf_evsel *evsel)
1094{
1095 struct hpp_sort_entry *hse;
1096 size_t len;
1097
1098 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1099 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1100
1101 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1102}
1103
1104static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1105 struct perf_hpp *hpp __maybe_unused,
1106 struct perf_evsel *evsel)
1107{
1108 struct hpp_sort_entry *hse;
1109
1110 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1111
1112 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1113}
1114
1115static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1116 struct hist_entry *he)
1117{
1118 struct hpp_sort_entry *hse;
1119 size_t len;
1120
1121 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1122 len = hists__col_len(he->hists, hse->se->se_width_idx);
1123
1124 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1125}
1126
Namhyung Kima7d945b2014-03-04 10:46:34 +09001127static struct hpp_sort_entry *
1128__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001129{
1130 struct hpp_sort_entry *hse;
1131
1132 hse = malloc(sizeof(*hse));
1133 if (hse == NULL) {
1134 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001135 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001136 }
1137
1138 hse->se = sd->entry;
1139 hse->hpp.header = __sort__hpp_header;
1140 hse->hpp.width = __sort__hpp_width;
1141 hse->hpp.entry = __sort__hpp_entry;
1142 hse->hpp.color = NULL;
1143
1144 hse->hpp.cmp = sd->entry->se_cmp;
1145 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001146 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001147
1148 INIT_LIST_HEAD(&hse->hpp.list);
1149 INIT_LIST_HEAD(&hse->hpp.sort_list);
1150
Namhyung Kima7d945b2014-03-04 10:46:34 +09001151 return hse;
1152}
1153
1154bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1155{
1156 return format->header == __sort__hpp_header;
1157}
1158
1159static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1160{
1161 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1162
1163 if (hse == NULL)
1164 return -1;
1165
Namhyung Kim8b536992014-03-03 11:46:55 +09001166 perf_hpp__register_sort_field(&hse->hpp);
1167 return 0;
1168}
1169
Namhyung Kima7d945b2014-03-04 10:46:34 +09001170static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1171{
1172 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1173
1174 if (hse == NULL)
1175 return -1;
1176
1177 perf_hpp__column_register(&hse->hpp);
1178 return 0;
1179}
1180
Namhyung Kim8b536992014-03-03 11:46:55 +09001181static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
Namhyung Kim2f532d02013-04-03 21:26:10 +09001182{
1183 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001184 return 0;
1185
Namhyung Kima7d945b2014-03-04 10:46:34 +09001186 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001187 return -1;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001188
1189 if (sd->entry->se_collapse)
1190 sort__need_collapse = 1;
1191
1192 if (list_empty(&hist_entry__sort_list))
1193 sort__first_dimension = idx;
1194
1195 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1196 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001197
1198 return 0;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001199}
1200
Namhyung Kima2ce0672014-03-04 09:06:42 +09001201static int __hpp_dimension__add(struct hpp_dimension *hd)
1202{
1203 if (!hd->taken) {
1204 hd->taken = 1;
1205
1206 perf_hpp__register_sort_field(hd->fmt);
1207 }
1208 return 0;
1209}
1210
Namhyung Kima7d945b2014-03-04 10:46:34 +09001211static int __sort_dimension__add_output(struct sort_dimension *sd)
1212{
1213 if (sd->taken)
1214 return 0;
1215
1216 if (__sort_dimension__add_hpp_output(sd) < 0)
1217 return -1;
1218
1219 sd->taken = 1;
1220 return 0;
1221}
1222
1223static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1224{
1225 if (!hd->taken) {
1226 hd->taken = 1;
1227
1228 perf_hpp__column_register(hd->fmt);
1229 }
1230 return 0;
1231}
1232
John Kacurdd68ada2009-09-24 18:02:49 +02001233int sort_dimension__add(const char *tok)
1234{
1235 unsigned int i;
1236
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001237 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1238 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001239
John Kacurdd68ada2009-09-24 18:02:49 +02001240 if (strncasecmp(tok, sd->name, strlen(tok)))
1241 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001242
John Kacurdd68ada2009-09-24 18:02:49 +02001243 if (sd->entry == &sort_parent) {
1244 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1245 if (ret) {
1246 char err[BUFSIZ];
1247
1248 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001249 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1250 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001251 }
1252 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001253 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001254 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001255 } else if (sd->entry == &sort_dso) {
1256 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001257 }
1258
Namhyung Kim8b536992014-03-03 11:46:55 +09001259 return __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001260 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001261
Namhyung Kima2ce0672014-03-04 09:06:42 +09001262 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1263 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1264
1265 if (strncasecmp(tok, hd->name, strlen(tok)))
1266 continue;
1267
1268 return __hpp_dimension__add(hd);
1269 }
1270
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001271 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1272 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1273
1274 if (strncasecmp(tok, sd->name, strlen(tok)))
1275 continue;
1276
Namhyung Kim55369fc2013-04-01 20:35:20 +09001277 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001278 return -EINVAL;
1279
1280 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1281 sort__has_sym = 1;
1282
Namhyung Kim2f532d02013-04-03 21:26:10 +09001283 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001284 return 0;
1285 }
1286
Namhyung Kimafab87b2013-04-03 21:26:11 +09001287 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1288 struct sort_dimension *sd = &memory_sort_dimensions[i];
1289
1290 if (strncasecmp(tok, sd->name, strlen(tok)))
1291 continue;
1292
1293 if (sort__mode != SORT_MODE__MEMORY)
1294 return -EINVAL;
1295
1296 if (sd->entry == &sort_mem_daddr_sym)
1297 sort__has_sym = 1;
1298
1299 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1300 return 0;
1301 }
1302
John Kacurdd68ada2009-09-24 18:02:49 +02001303 return -ESRCH;
1304}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001305
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001306static const char *get_default_sort_order(void)
1307{
1308 const char *default_sort_orders[] = {
1309 default_sort_order,
1310 default_branch_sort_order,
1311 default_mem_sort_order,
1312 default_top_sort_order,
1313 default_diff_sort_order,
1314 };
1315
1316 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1317
1318 return default_sort_orders[sort__mode];
1319}
1320
Namhyung Kima7d945b2014-03-04 10:46:34 +09001321static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001322{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001323 char *tmp, *tok, *str;
1324 const char *sort_keys = sort_order;
Namhyung Kim55309982013-02-06 14:57:16 +09001325 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001326
Namhyung Kima7d945b2014-03-04 10:46:34 +09001327 if (sort_keys == NULL) {
1328 if (field_order) {
1329 /*
1330 * If user specified field order but no sort order,
1331 * we'll honor it and not add default sort orders.
1332 */
1333 return 0;
1334 }
1335
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001336 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001337 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001338
1339 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001340 if (str == NULL) {
1341 error("Not enough memory to setup sort keys");
1342 return -ENOMEM;
1343 }
1344
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001345 for (tok = strtok_r(str, ", ", &tmp);
1346 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001347 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001348 if (ret == -EINVAL) {
1349 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001350 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001351 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001352 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001353 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001354 }
1355 }
1356
1357 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001358 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001359}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001360
Namhyung Kime67d49a2014-03-18 13:00:59 +09001361bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
1362{
1363 if (perf_hpp__is_sort_entry(format)) {
1364 struct hpp_sort_entry *hse;
1365
1366 hse = container_of(format, struct hpp_sort_entry, hpp);
1367 return hse->se->elide;
1368 }
1369 return false;
1370}
1371
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001372static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001373 struct strlist *list,
1374 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001375{
1376 if (list && strlist__nr_entries(list) == 1) {
1377 if (fp != NULL)
1378 fprintf(fp, "# %s: %s\n", list_name,
1379 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001380 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001381 }
1382}
Namhyung Kim08e71542013-04-03 21:26:19 +09001383
1384void sort__setup_elide(FILE *output)
1385{
Namhyung Kim7524f632013-11-08 17:53:42 +09001386 struct sort_entry *se;
1387
Namhyung Kim08e71542013-04-03 21:26:19 +09001388 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1389 "dso", output);
1390 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1391 "comm", output);
1392 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1393 "symbol", output);
1394
1395 if (sort__mode == SORT_MODE__BRANCH) {
1396 sort_entry__setup_elide(&sort_dso_from,
1397 symbol_conf.dso_from_list,
1398 "dso_from", output);
1399 sort_entry__setup_elide(&sort_dso_to,
1400 symbol_conf.dso_to_list,
1401 "dso_to", output);
1402 sort_entry__setup_elide(&sort_sym_from,
1403 symbol_conf.sym_from_list,
1404 "sym_from", output);
1405 sort_entry__setup_elide(&sort_sym_to,
1406 symbol_conf.sym_to_list,
1407 "sym_to", output);
1408 } else if (sort__mode == SORT_MODE__MEMORY) {
1409 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1410 "symbol_daddr", output);
1411 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1412 "dso_daddr", output);
1413 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1414 "mem", output);
1415 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1416 "local_weight", output);
1417 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1418 "tlb", output);
1419 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1420 "snoop", output);
1421 }
1422
Namhyung Kim7524f632013-11-08 17:53:42 +09001423 /*
1424 * It makes no sense to elide all of sort entries.
1425 * Just revert them to show up again.
1426 */
1427 list_for_each_entry(se, &hist_entry__sort_list, list) {
1428 if (!se->elide)
1429 return;
1430 }
1431
1432 list_for_each_entry(se, &hist_entry__sort_list, list)
1433 se->elide = false;
Namhyung Kim08e71542013-04-03 21:26:19 +09001434}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001435
1436static int output_field_add(char *tok)
1437{
1438 unsigned int i;
1439
1440 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1441 struct sort_dimension *sd = &common_sort_dimensions[i];
1442
1443 if (strncasecmp(tok, sd->name, strlen(tok)))
1444 continue;
1445
1446 return __sort_dimension__add_output(sd);
1447 }
1448
1449 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1450 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1451
1452 if (strncasecmp(tok, hd->name, strlen(tok)))
1453 continue;
1454
1455 return __hpp_dimension__add_output(hd);
1456 }
1457
1458 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1459 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1460
1461 if (strncasecmp(tok, sd->name, strlen(tok)))
1462 continue;
1463
1464 return __sort_dimension__add_output(sd);
1465 }
1466
1467 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1468 struct sort_dimension *sd = &memory_sort_dimensions[i];
1469
1470 if (strncasecmp(tok, sd->name, strlen(tok)))
1471 continue;
1472
1473 return __sort_dimension__add_output(sd);
1474 }
1475
1476 return -ESRCH;
1477}
1478
1479static void reset_dimensions(void)
1480{
1481 unsigned int i;
1482
1483 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1484 common_sort_dimensions[i].taken = 0;
1485
1486 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1487 hpp_sort_dimensions[i].taken = 0;
1488
1489 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1490 bstack_sort_dimensions[i].taken = 0;
1491
1492 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1493 memory_sort_dimensions[i].taken = 0;
1494}
1495
1496static int __setup_output_field(void)
1497{
1498 char *tmp, *tok, *str;
1499 int ret = 0;
1500
1501 if (field_order == NULL)
1502 return 0;
1503
1504 reset_dimensions();
1505
1506 str = strdup(field_order);
1507 if (str == NULL) {
1508 error("Not enough memory to setup output fields");
1509 return -ENOMEM;
1510 }
1511
1512 for (tok = strtok_r(str, ", ", &tmp);
1513 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1514 ret = output_field_add(tok);
1515 if (ret == -EINVAL) {
1516 error("Invalid --fields key: `%s'", tok);
1517 break;
1518 } else if (ret == -ESRCH) {
1519 error("Unknown --fields key: `%s'", tok);
1520 break;
1521 }
1522 }
1523
1524 free(str);
1525 return ret;
1526}
1527
1528int setup_sorting(void)
1529{
1530 int err;
1531
1532 err = __setup_sorting();
1533 if (err < 0)
1534 return err;
1535
1536 if (parent_pattern != default_parent_pattern) {
1537 err = sort_dimension__add("parent");
1538 if (err < 0)
1539 return err;
1540 }
1541
1542 reset_dimensions();
1543
1544 /*
1545 * perf diff doesn't use default hpp output fields.
1546 */
1547 if (sort__mode != SORT_MODE__DIFF)
1548 perf_hpp__init();
1549
1550 err = __setup_output_field();
1551 if (err < 0)
1552 return err;
1553
1554 /* copy sort keys to output fields */
1555 perf_hpp__setup_output_field();
1556 /* and then copy output fields to sort keys */
1557 perf_hpp__append_sort_keys();
1558
1559 return 0;
1560}