blob: b748b02fcb78ae32815b595dc1fa7c414e4f8441 [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
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300102static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300103 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200104{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900105 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200106}
107
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900108struct sort_entry sort_comm = {
109 .se_header = "Command",
110 .se_cmp = sort__comm_cmp,
111 .se_collapse = sort__comm_collapse,
112 .se_snprintf = hist_entry__comm_snprintf,
113 .se_width_idx = HISTC_COMM,
114};
115
116/* --sort dso */
117
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100118static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200119{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100120 struct dso *dso_l = map_l ? map_l->dso : NULL;
121 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300122 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200123
124 if (!dso_l || !dso_r)
125 return cmp_null(dso_l, dso_r);
126
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300127 if (verbose) {
128 dso_name_l = dso_l->long_name;
129 dso_name_r = dso_r->long_name;
130 } else {
131 dso_name_l = dso_l->short_name;
132 dso_name_r = dso_r->short_name;
133 }
134
135 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200136}
137
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100138static int64_t
139sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200140{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100141 return _sort__dso_cmp(left->ms.map, right->ms.map);
142}
143
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100144static int _hist_entry__dso_snprintf(struct map *map, char *bf,
145 size_t size, unsigned int width)
146{
147 if (map && map->dso) {
148 const char *dso_name = !verbose ? map->dso->short_name :
149 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300150 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300151 }
John Kacurdd68ada2009-09-24 18:02:49 +0200152
Ian Munsie1437a302010-12-06 13:37:04 +1100153 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200154}
155
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300156static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100157 size_t size, unsigned int width)
158{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300159 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100160}
161
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900162struct sort_entry sort_dso = {
163 .se_header = "Shared Object",
164 .se_cmp = sort__dso_cmp,
165 .se_snprintf = hist_entry__dso_snprintf,
166 .se_width_idx = HISTC_DSO,
167};
168
169/* --sort symbol */
170
Namhyung Kim2037be52013-12-18 14:21:09 +0900171static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
172{
173 return (int64_t)(right_ip - left_ip);
174}
175
Namhyung Kim51f27d12013-02-06 14:57:15 +0900176static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900177{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900178 u64 ip_l, ip_r;
179
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900180 if (!sym_l || !sym_r)
181 return cmp_null(sym_l, sym_r);
182
183 if (sym_l == sym_r)
184 return 0;
185
186 ip_l = sym_l->start;
187 ip_r = sym_r->start;
188
189 return (int64_t)(ip_r - ip_l);
190}
191
192static int64_t
193sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
194{
Namhyung Kim09600e02013-10-15 11:01:56 +0900195 int64_t ret;
196
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900197 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900198 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900199
Namhyung Kim09600e02013-10-15 11:01:56 +0900200 /*
201 * comparing symbol address alone is not enough since it's a
202 * relative address within a dso.
203 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900204 if (!sort__has_dso) {
205 ret = sort__dso_cmp(left, right);
206 if (ret != 0)
207 return ret;
208 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900209
Namhyung Kim51f27d12013-02-06 14:57:15 +0900210 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900211}
212
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100213static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
214 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900215 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100216{
217 size_t ret = 0;
218
219 if (verbose) {
220 char o = map ? dso__symtab_origin(map->dso) : '!';
221 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900222 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100223 }
224
225 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100226 if (sym && map) {
227 if (map->type == MAP__VARIABLE) {
228 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
229 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100230 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100231 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
232 width - ret, "");
233 } else {
234 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
235 width - ret,
236 sym->name);
237 }
238 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239 size_t len = BITS_PER_LONG / 4;
240 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
241 len, ip);
242 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
243 width - ret, "");
244 }
245
246 return ret;
247}
248
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300249static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900250 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100251{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300252 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
253 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100254}
John Kacurdd68ada2009-09-24 18:02:49 +0200255
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200256struct sort_entry sort_sym = {
257 .se_header = "Symbol",
258 .se_cmp = sort__sym_cmp,
259 .se_snprintf = hist_entry__sym_snprintf,
260 .se_width_idx = HISTC_SYMBOL,
261};
John Kacurdd68ada2009-09-24 18:02:49 +0200262
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300263/* --sort srcline */
264
265static int64_t
266sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
267{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900268 if (!left->srcline) {
269 if (!left->ms.map)
270 left->srcline = SRCLINE_UNKNOWN;
271 else {
272 struct map *map = left->ms.map;
273 left->srcline = get_srcline(map->dso,
274 map__rip_2objdump(map, left->ip));
275 }
276 }
277 if (!right->srcline) {
278 if (!right->ms.map)
279 right->srcline = SRCLINE_UNKNOWN;
280 else {
281 struct map *map = right->ms.map;
282 right->srcline = get_srcline(map->dso,
283 map__rip_2objdump(map, right->ip));
284 }
285 }
286 return strcmp(left->srcline, right->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300287}
288
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300289static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300290 size_t size,
291 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300292{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300293 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300294}
295
296struct sort_entry sort_srcline = {
297 .se_header = "Source:Line",
298 .se_cmp = sort__srcline_cmp,
299 .se_snprintf = hist_entry__srcline_snprintf,
300 .se_width_idx = HISTC_SRCLINE,
301};
302
John Kacurdd68ada2009-09-24 18:02:49 +0200303/* --sort parent */
304
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200305static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200306sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
307{
308 struct symbol *sym_l = left->parent;
309 struct symbol *sym_r = right->parent;
310
311 if (!sym_l || !sym_r)
312 return cmp_null(sym_l, sym_r);
313
314 return strcmp(sym_l->name, sym_r->name);
315}
316
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300317static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300318 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200319{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300320 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300321 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200322}
323
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200324struct sort_entry sort_parent = {
325 .se_header = "Parent symbol",
326 .se_cmp = sort__parent_cmp,
327 .se_snprintf = hist_entry__parent_snprintf,
328 .se_width_idx = HISTC_PARENT,
329};
330
Arun Sharmaf60f3592010-06-04 11:27:10 -0300331/* --sort cpu */
332
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200333static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300334sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
335{
336 return right->cpu - left->cpu;
337}
338
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300339static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
340 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300341{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300342 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300343}
344
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200345struct sort_entry sort_cpu = {
346 .se_header = "CPU",
347 .se_cmp = sort__cpu_cmp,
348 .se_snprintf = hist_entry__cpu_snprintf,
349 .se_width_idx = HISTC_CPU,
350};
351
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900352/* sort keys for branch stacks */
353
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100354static int64_t
355sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
356{
357 return _sort__dso_cmp(left->branch_info->from.map,
358 right->branch_info->from.map);
359}
360
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300361static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100362 size_t size, unsigned int width)
363{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300364 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100365 bf, size, width);
366}
367
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100368static int64_t
369sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
370{
371 return _sort__dso_cmp(left->branch_info->to.map,
372 right->branch_info->to.map);
373}
374
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300375static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100376 size_t size, unsigned int width)
377{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300378 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100379 bf, size, width);
380}
381
382static int64_t
383sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
384{
385 struct addr_map_symbol *from_l = &left->branch_info->from;
386 struct addr_map_symbol *from_r = &right->branch_info->from;
387
388 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900389 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100390
Namhyung Kim51f27d12013-02-06 14:57:15 +0900391 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100392}
393
394static int64_t
395sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
396{
397 struct addr_map_symbol *to_l = &left->branch_info->to;
398 struct addr_map_symbol *to_r = &right->branch_info->to;
399
400 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900401 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100402
Namhyung Kim51f27d12013-02-06 14:57:15 +0900403 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100404}
405
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300406static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900407 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100408{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300409 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100410 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300411 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100412
413}
414
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300415static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900416 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100417{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300418 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100419 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300420 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421
422}
423
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900424struct sort_entry sort_dso_from = {
425 .se_header = "Source Shared Object",
426 .se_cmp = sort__dso_from_cmp,
427 .se_snprintf = hist_entry__dso_from_snprintf,
428 .se_width_idx = HISTC_DSO_FROM,
429};
430
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100431struct sort_entry sort_dso_to = {
432 .se_header = "Target Shared Object",
433 .se_cmp = sort__dso_to_cmp,
434 .se_snprintf = hist_entry__dso_to_snprintf,
435 .se_width_idx = HISTC_DSO_TO,
436};
437
438struct sort_entry sort_sym_from = {
439 .se_header = "Source Symbol",
440 .se_cmp = sort__sym_from_cmp,
441 .se_snprintf = hist_entry__sym_from_snprintf,
442 .se_width_idx = HISTC_SYMBOL_FROM,
443};
444
445struct sort_entry sort_sym_to = {
446 .se_header = "Target Symbol",
447 .se_cmp = sort__sym_to_cmp,
448 .se_snprintf = hist_entry__sym_to_snprintf,
449 .se_width_idx = HISTC_SYMBOL_TO,
450};
451
452static int64_t
453sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
454{
455 const unsigned char mp = left->branch_info->flags.mispred !=
456 right->branch_info->flags.mispred;
457 const unsigned char p = left->branch_info->flags.predicted !=
458 right->branch_info->flags.predicted;
459
460 return mp || p;
461}
462
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300463static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100464 size_t size, unsigned int width){
465 static const char *out = "N/A";
466
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300467 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100468 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300469 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100470 out = "Y";
471
472 return repsep_snprintf(bf, size, "%-*s", width, out);
473}
474
Stephane Eranian98a3b322013-01-24 16:10:35 +0100475/* --sort daddr_sym */
476static int64_t
477sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
478{
479 uint64_t l = 0, r = 0;
480
481 if (left->mem_info)
482 l = left->mem_info->daddr.addr;
483 if (right->mem_info)
484 r = right->mem_info->daddr.addr;
485
486 return (int64_t)(r - l);
487}
488
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300489static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100490 size_t size, unsigned int width)
491{
492 uint64_t addr = 0;
493 struct map *map = NULL;
494 struct symbol *sym = NULL;
495
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300496 if (he->mem_info) {
497 addr = he->mem_info->daddr.addr;
498 map = he->mem_info->daddr.map;
499 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100500 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300501 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100502 width);
503}
504
505static int64_t
506sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
507{
508 struct map *map_l = NULL;
509 struct map *map_r = NULL;
510
511 if (left->mem_info)
512 map_l = left->mem_info->daddr.map;
513 if (right->mem_info)
514 map_r = right->mem_info->daddr.map;
515
516 return _sort__dso_cmp(map_l, map_r);
517}
518
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300519static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100520 size_t size, unsigned int width)
521{
522 struct map *map = NULL;
523
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300524 if (he->mem_info)
525 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100526
527 return _hist_entry__dso_snprintf(map, bf, size, width);
528}
529
530static int64_t
531sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
532{
533 union perf_mem_data_src data_src_l;
534 union perf_mem_data_src data_src_r;
535
536 if (left->mem_info)
537 data_src_l = left->mem_info->data_src;
538 else
539 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
540
541 if (right->mem_info)
542 data_src_r = right->mem_info->data_src;
543 else
544 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
545
546 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
547}
548
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300549static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100550 size_t size, unsigned int width)
551{
552 const char *out;
553 u64 mask = PERF_MEM_LOCK_NA;
554
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300555 if (he->mem_info)
556 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100557
558 if (mask & PERF_MEM_LOCK_NA)
559 out = "N/A";
560 else if (mask & PERF_MEM_LOCK_LOCKED)
561 out = "Yes";
562 else
563 out = "No";
564
565 return repsep_snprintf(bf, size, "%-*s", width, out);
566}
567
568static int64_t
569sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
570{
571 union perf_mem_data_src data_src_l;
572 union perf_mem_data_src data_src_r;
573
574 if (left->mem_info)
575 data_src_l = left->mem_info->data_src;
576 else
577 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
578
579 if (right->mem_info)
580 data_src_r = right->mem_info->data_src;
581 else
582 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
583
584 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
585}
586
587static const char * const tlb_access[] = {
588 "N/A",
589 "HIT",
590 "MISS",
591 "L1",
592 "L2",
593 "Walker",
594 "Fault",
595};
596#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
597
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300598static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100599 size_t size, unsigned int width)
600{
601 char out[64];
602 size_t sz = sizeof(out) - 1; /* -1 for null termination */
603 size_t l = 0, i;
604 u64 m = PERF_MEM_TLB_NA;
605 u64 hit, miss;
606
607 out[0] = '\0';
608
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300609 if (he->mem_info)
610 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100611
612 hit = m & PERF_MEM_TLB_HIT;
613 miss = m & PERF_MEM_TLB_MISS;
614
615 /* already taken care of */
616 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
617
618 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
619 if (!(m & 0x1))
620 continue;
621 if (l) {
622 strcat(out, " or ");
623 l += 4;
624 }
625 strncat(out, tlb_access[i], sz - l);
626 l += strlen(tlb_access[i]);
627 }
628 if (*out == '\0')
629 strcpy(out, "N/A");
630 if (hit)
631 strncat(out, " hit", sz - l);
632 if (miss)
633 strncat(out, " miss", sz - l);
634
635 return repsep_snprintf(bf, size, "%-*s", width, out);
636}
637
638static int64_t
639sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
640{
641 union perf_mem_data_src data_src_l;
642 union perf_mem_data_src data_src_r;
643
644 if (left->mem_info)
645 data_src_l = left->mem_info->data_src;
646 else
647 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
648
649 if (right->mem_info)
650 data_src_r = right->mem_info->data_src;
651 else
652 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
653
654 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
655}
656
657static const char * const mem_lvl[] = {
658 "N/A",
659 "HIT",
660 "MISS",
661 "L1",
662 "LFB",
663 "L2",
664 "L3",
665 "Local RAM",
666 "Remote RAM (1 hop)",
667 "Remote RAM (2 hops)",
668 "Remote Cache (1 hop)",
669 "Remote Cache (2 hops)",
670 "I/O",
671 "Uncached",
672};
673#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
674
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300675static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100676 size_t size, unsigned int width)
677{
678 char out[64];
679 size_t sz = sizeof(out) - 1; /* -1 for null termination */
680 size_t i, l = 0;
681 u64 m = PERF_MEM_LVL_NA;
682 u64 hit, miss;
683
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300684 if (he->mem_info)
685 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100686
687 out[0] = '\0';
688
689 hit = m & PERF_MEM_LVL_HIT;
690 miss = m & PERF_MEM_LVL_MISS;
691
692 /* already taken care of */
693 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
694
695 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
696 if (!(m & 0x1))
697 continue;
698 if (l) {
699 strcat(out, " or ");
700 l += 4;
701 }
702 strncat(out, mem_lvl[i], sz - l);
703 l += strlen(mem_lvl[i]);
704 }
705 if (*out == '\0')
706 strcpy(out, "N/A");
707 if (hit)
708 strncat(out, " hit", sz - l);
709 if (miss)
710 strncat(out, " miss", sz - l);
711
712 return repsep_snprintf(bf, size, "%-*s", width, out);
713}
714
715static int64_t
716sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
717{
718 union perf_mem_data_src data_src_l;
719 union perf_mem_data_src data_src_r;
720
721 if (left->mem_info)
722 data_src_l = left->mem_info->data_src;
723 else
724 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
725
726 if (right->mem_info)
727 data_src_r = right->mem_info->data_src;
728 else
729 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
730
731 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
732}
733
734static const char * const snoop_access[] = {
735 "N/A",
736 "None",
737 "Miss",
738 "Hit",
739 "HitM",
740};
741#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
742
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300743static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100744 size_t size, unsigned int width)
745{
746 char out[64];
747 size_t sz = sizeof(out) - 1; /* -1 for null termination */
748 size_t i, l = 0;
749 u64 m = PERF_MEM_SNOOP_NA;
750
751 out[0] = '\0';
752
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300753 if (he->mem_info)
754 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100755
756 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
757 if (!(m & 0x1))
758 continue;
759 if (l) {
760 strcat(out, " or ");
761 l += 4;
762 }
763 strncat(out, snoop_access[i], sz - l);
764 l += strlen(snoop_access[i]);
765 }
766
767 if (*out == '\0')
768 strcpy(out, "N/A");
769
770 return repsep_snprintf(bf, size, "%-*s", width, out);
771}
772
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100773struct sort_entry sort_mispredict = {
774 .se_header = "Branch Mispredicted",
775 .se_cmp = sort__mispredict_cmp,
776 .se_snprintf = hist_entry__mispredict_snprintf,
777 .se_width_idx = HISTC_MISPREDICT,
778};
779
Andi Kleen05484292013-01-24 16:10:29 +0100780static u64 he_weight(struct hist_entry *he)
781{
782 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
783}
784
785static int64_t
786sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
787{
788 return he_weight(left) - he_weight(right);
789}
790
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300791static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100792 size_t size, unsigned int width)
793{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300794 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100795}
796
797struct sort_entry sort_local_weight = {
798 .se_header = "Local Weight",
799 .se_cmp = sort__local_weight_cmp,
800 .se_snprintf = hist_entry__local_weight_snprintf,
801 .se_width_idx = HISTC_LOCAL_WEIGHT,
802};
803
804static int64_t
805sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
806{
807 return left->stat.weight - right->stat.weight;
808}
809
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300810static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100811 size_t size, unsigned int width)
812{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300813 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100814}
815
816struct sort_entry sort_global_weight = {
817 .se_header = "Weight",
818 .se_cmp = sort__global_weight_cmp,
819 .se_snprintf = hist_entry__global_weight_snprintf,
820 .se_width_idx = HISTC_GLOBAL_WEIGHT,
821};
822
Stephane Eranian98a3b322013-01-24 16:10:35 +0100823struct sort_entry sort_mem_daddr_sym = {
824 .se_header = "Data Symbol",
825 .se_cmp = sort__daddr_cmp,
826 .se_snprintf = hist_entry__daddr_snprintf,
827 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
828};
829
830struct sort_entry sort_mem_daddr_dso = {
831 .se_header = "Data Object",
832 .se_cmp = sort__dso_daddr_cmp,
833 .se_snprintf = hist_entry__dso_daddr_snprintf,
834 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
835};
836
837struct sort_entry sort_mem_locked = {
838 .se_header = "Locked",
839 .se_cmp = sort__locked_cmp,
840 .se_snprintf = hist_entry__locked_snprintf,
841 .se_width_idx = HISTC_MEM_LOCKED,
842};
843
844struct sort_entry sort_mem_tlb = {
845 .se_header = "TLB access",
846 .se_cmp = sort__tlb_cmp,
847 .se_snprintf = hist_entry__tlb_snprintf,
848 .se_width_idx = HISTC_MEM_TLB,
849};
850
851struct sort_entry sort_mem_lvl = {
852 .se_header = "Memory access",
853 .se_cmp = sort__lvl_cmp,
854 .se_snprintf = hist_entry__lvl_snprintf,
855 .se_width_idx = HISTC_MEM_LVL,
856};
857
858struct sort_entry sort_mem_snoop = {
859 .se_header = "Snoop",
860 .se_cmp = sort__snoop_cmp,
861 .se_snprintf = hist_entry__snoop_snprintf,
862 .se_width_idx = HISTC_MEM_SNOOP,
863};
864
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700865static int64_t
866sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
867{
868 return left->branch_info->flags.abort !=
869 right->branch_info->flags.abort;
870}
871
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300872static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700873 size_t size, unsigned int width)
874{
875 static const char *out = ".";
876
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300877 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700878 out = "A";
879 return repsep_snprintf(bf, size, "%-*s", width, out);
880}
881
882struct sort_entry sort_abort = {
883 .se_header = "Transaction abort",
884 .se_cmp = sort__abort_cmp,
885 .se_snprintf = hist_entry__abort_snprintf,
886 .se_width_idx = HISTC_ABORT,
887};
888
889static int64_t
890sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
891{
892 return left->branch_info->flags.in_tx !=
893 right->branch_info->flags.in_tx;
894}
895
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300896static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700897 size_t size, unsigned int width)
898{
899 static const char *out = ".";
900
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300901 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700902 out = "T";
903
904 return repsep_snprintf(bf, size, "%-*s", width, out);
905}
906
907struct sort_entry sort_in_tx = {
908 .se_header = "Branch in transaction",
909 .se_cmp = sort__in_tx_cmp,
910 .se_snprintf = hist_entry__in_tx_snprintf,
911 .se_width_idx = HISTC_IN_TX,
912};
913
Andi Kleen475eeab2013-09-20 07:40:43 -0700914static int64_t
915sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
916{
917 return left->transaction - right->transaction;
918}
919
920static inline char *add_str(char *p, const char *str)
921{
922 strcpy(p, str);
923 return p + strlen(str);
924}
925
926static struct txbit {
927 unsigned flag;
928 const char *name;
929 int skip_for_len;
930} txbits[] = {
931 { PERF_TXN_ELISION, "EL ", 0 },
932 { PERF_TXN_TRANSACTION, "TX ", 1 },
933 { PERF_TXN_SYNC, "SYNC ", 1 },
934 { PERF_TXN_ASYNC, "ASYNC ", 0 },
935 { PERF_TXN_RETRY, "RETRY ", 0 },
936 { PERF_TXN_CONFLICT, "CON ", 0 },
937 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
938 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
939 { 0, NULL, 0 }
940};
941
942int hist_entry__transaction_len(void)
943{
944 int i;
945 int len = 0;
946
947 for (i = 0; txbits[i].name; i++) {
948 if (!txbits[i].skip_for_len)
949 len += strlen(txbits[i].name);
950 }
951 len += 4; /* :XX<space> */
952 return len;
953}
954
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300955static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -0700956 size_t size, unsigned int width)
957{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300958 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -0700959 char buf[128];
960 char *p = buf;
961 int i;
962
963 buf[0] = 0;
964 for (i = 0; txbits[i].name; i++)
965 if (txbits[i].flag & t)
966 p = add_str(p, txbits[i].name);
967 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
968 p = add_str(p, "NEITHER ");
969 if (t & PERF_TXN_ABORT_MASK) {
970 sprintf(p, ":%" PRIx64,
971 (t & PERF_TXN_ABORT_MASK) >>
972 PERF_TXN_ABORT_SHIFT);
973 p += strlen(p);
974 }
975
976 return repsep_snprintf(bf, size, "%-*s", width, buf);
977}
978
979struct sort_entry sort_transaction = {
980 .se_header = "Transaction ",
981 .se_cmp = sort__transaction_cmp,
982 .se_snprintf = hist_entry__transaction_snprintf,
983 .se_width_idx = HISTC_TRANSACTION,
984};
985
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200986struct sort_dimension {
987 const char *name;
988 struct sort_entry *entry;
989 int taken;
990};
991
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100992#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
993
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900994static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100995 DIM(SORT_PID, "pid", sort_thread),
996 DIM(SORT_COMM, "comm", sort_comm),
997 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100998 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100999 DIM(SORT_PARENT, "parent", sort_parent),
1000 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001001 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001002 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1003 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001004 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001005};
1006
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001007#undef DIM
1008
1009#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1010
1011static struct sort_dimension bstack_sort_dimensions[] = {
1012 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1013 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1014 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1015 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1016 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001017 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1018 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001019};
1020
1021#undef DIM
1022
Namhyung Kimafab87b2013-04-03 21:26:11 +09001023#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1024
1025static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001026 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1027 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1028 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1029 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1030 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1031 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1032};
1033
1034#undef DIM
1035
Namhyung Kima2ce0672014-03-04 09:06:42 +09001036struct hpp_dimension {
1037 const char *name;
1038 struct perf_hpp_fmt *fmt;
1039 int taken;
1040};
1041
1042#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1043
1044static struct hpp_dimension hpp_sort_dimensions[] = {
1045 DIM(PERF_HPP__OVERHEAD, "overhead"),
1046 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1047 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1048 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1049 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1050 DIM(PERF_HPP__SAMPLES, "sample"),
1051 DIM(PERF_HPP__PERIOD, "period"),
1052};
1053
1054#undef DIM
1055
Namhyung Kim8b536992014-03-03 11:46:55 +09001056struct hpp_sort_entry {
1057 struct perf_hpp_fmt hpp;
1058 struct sort_entry *se;
1059};
1060
Namhyung Kima7d945b2014-03-04 10:46:34 +09001061bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1062{
1063 struct hpp_sort_entry *hse_a;
1064 struct hpp_sort_entry *hse_b;
1065
1066 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1067 return false;
1068
1069 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1070 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1071
1072 return hse_a->se == hse_b->se;
1073}
1074
Namhyung Kim8b536992014-03-03 11:46:55 +09001075static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1076 struct perf_evsel *evsel)
1077{
1078 struct hpp_sort_entry *hse;
1079 size_t len;
1080
1081 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1082 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1083
1084 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1085}
1086
1087static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1088 struct perf_hpp *hpp __maybe_unused,
1089 struct perf_evsel *evsel)
1090{
1091 struct hpp_sort_entry *hse;
1092
1093 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1094
1095 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1096}
1097
1098static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1099 struct hist_entry *he)
1100{
1101 struct hpp_sort_entry *hse;
1102 size_t len;
1103
1104 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1105 len = hists__col_len(he->hists, hse->se->se_width_idx);
1106
1107 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1108}
1109
Namhyung Kima7d945b2014-03-04 10:46:34 +09001110static struct hpp_sort_entry *
1111__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001112{
1113 struct hpp_sort_entry *hse;
1114
1115 hse = malloc(sizeof(*hse));
1116 if (hse == NULL) {
1117 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001118 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001119 }
1120
1121 hse->se = sd->entry;
1122 hse->hpp.header = __sort__hpp_header;
1123 hse->hpp.width = __sort__hpp_width;
1124 hse->hpp.entry = __sort__hpp_entry;
1125 hse->hpp.color = NULL;
1126
1127 hse->hpp.cmp = sd->entry->se_cmp;
1128 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1129 hse->hpp.sort = hse->hpp.collapse;
1130
1131 INIT_LIST_HEAD(&hse->hpp.list);
1132 INIT_LIST_HEAD(&hse->hpp.sort_list);
1133
Namhyung Kima7d945b2014-03-04 10:46:34 +09001134 return hse;
1135}
1136
1137bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1138{
1139 return format->header == __sort__hpp_header;
1140}
1141
1142static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1143{
1144 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1145
1146 if (hse == NULL)
1147 return -1;
1148
Namhyung Kim8b536992014-03-03 11:46:55 +09001149 perf_hpp__register_sort_field(&hse->hpp);
1150 return 0;
1151}
1152
Namhyung Kima7d945b2014-03-04 10:46:34 +09001153static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1154{
1155 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1156
1157 if (hse == NULL)
1158 return -1;
1159
1160 perf_hpp__column_register(&hse->hpp);
1161 return 0;
1162}
1163
Namhyung Kim8b536992014-03-03 11:46:55 +09001164static int __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
Namhyung Kim2f532d02013-04-03 21:26:10 +09001165{
1166 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001167 return 0;
1168
Namhyung Kima7d945b2014-03-04 10:46:34 +09001169 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001170 return -1;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001171
1172 if (sd->entry->se_collapse)
1173 sort__need_collapse = 1;
1174
1175 if (list_empty(&hist_entry__sort_list))
1176 sort__first_dimension = idx;
1177
1178 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1179 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001180
1181 return 0;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001182}
1183
Namhyung Kima2ce0672014-03-04 09:06:42 +09001184static int __hpp_dimension__add(struct hpp_dimension *hd)
1185{
1186 if (!hd->taken) {
1187 hd->taken = 1;
1188
1189 perf_hpp__register_sort_field(hd->fmt);
1190 }
1191 return 0;
1192}
1193
Namhyung Kima7d945b2014-03-04 10:46:34 +09001194static int __sort_dimension__add_output(struct sort_dimension *sd)
1195{
1196 if (sd->taken)
1197 return 0;
1198
1199 if (__sort_dimension__add_hpp_output(sd) < 0)
1200 return -1;
1201
1202 sd->taken = 1;
1203 return 0;
1204}
1205
1206static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1207{
1208 if (!hd->taken) {
1209 hd->taken = 1;
1210
1211 perf_hpp__column_register(hd->fmt);
1212 }
1213 return 0;
1214}
1215
John Kacurdd68ada2009-09-24 18:02:49 +02001216int sort_dimension__add(const char *tok)
1217{
1218 unsigned int i;
1219
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001220 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1221 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001222
John Kacurdd68ada2009-09-24 18:02:49 +02001223 if (strncasecmp(tok, sd->name, strlen(tok)))
1224 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001225
John Kacurdd68ada2009-09-24 18:02:49 +02001226 if (sd->entry == &sort_parent) {
1227 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1228 if (ret) {
1229 char err[BUFSIZ];
1230
1231 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001232 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1233 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001234 }
1235 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001236 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001237 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001238 } else if (sd->entry == &sort_dso) {
1239 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001240 }
1241
Namhyung Kim8b536992014-03-03 11:46:55 +09001242 return __sort_dimension__add(sd, i);
John Kacurdd68ada2009-09-24 18:02:49 +02001243 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001244
Namhyung Kima2ce0672014-03-04 09:06:42 +09001245 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1246 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1247
1248 if (strncasecmp(tok, hd->name, strlen(tok)))
1249 continue;
1250
1251 return __hpp_dimension__add(hd);
1252 }
1253
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001254 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1255 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1256
1257 if (strncasecmp(tok, sd->name, strlen(tok)))
1258 continue;
1259
Namhyung Kim55369fc2013-04-01 20:35:20 +09001260 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001261 return -EINVAL;
1262
1263 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1264 sort__has_sym = 1;
1265
Namhyung Kim2f532d02013-04-03 21:26:10 +09001266 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001267 return 0;
1268 }
1269
Namhyung Kimafab87b2013-04-03 21:26:11 +09001270 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1271 struct sort_dimension *sd = &memory_sort_dimensions[i];
1272
1273 if (strncasecmp(tok, sd->name, strlen(tok)))
1274 continue;
1275
1276 if (sort__mode != SORT_MODE__MEMORY)
1277 return -EINVAL;
1278
1279 if (sd->entry == &sort_mem_daddr_sym)
1280 sort__has_sym = 1;
1281
1282 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE);
1283 return 0;
1284 }
1285
John Kacurdd68ada2009-09-24 18:02:49 +02001286 return -ESRCH;
1287}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001288
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001289static const char *get_default_sort_order(void)
1290{
1291 const char *default_sort_orders[] = {
1292 default_sort_order,
1293 default_branch_sort_order,
1294 default_mem_sort_order,
1295 default_top_sort_order,
1296 default_diff_sort_order,
1297 };
1298
1299 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1300
1301 return default_sort_orders[sort__mode];
1302}
1303
Namhyung Kima7d945b2014-03-04 10:46:34 +09001304static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001305{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001306 char *tmp, *tok, *str;
1307 const char *sort_keys = sort_order;
Namhyung Kim55309982013-02-06 14:57:16 +09001308 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001309
Namhyung Kima7d945b2014-03-04 10:46:34 +09001310 if (sort_keys == NULL) {
1311 if (field_order) {
1312 /*
1313 * If user specified field order but no sort order,
1314 * we'll honor it and not add default sort orders.
1315 */
1316 return 0;
1317 }
1318
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001319 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001320 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001321
1322 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001323 if (str == NULL) {
1324 error("Not enough memory to setup sort keys");
1325 return -ENOMEM;
1326 }
1327
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001328 for (tok = strtok_r(str, ", ", &tmp);
1329 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001330 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001331 if (ret == -EINVAL) {
1332 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001333 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001334 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001335 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001336 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001337 }
1338 }
1339
1340 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001341 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001342}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001343
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001344static void sort_entry__setup_elide(struct sort_entry *se,
Namhyung Kim08e71542013-04-03 21:26:19 +09001345 struct strlist *list,
1346 const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001347{
1348 if (list && strlist__nr_entries(list) == 1) {
1349 if (fp != NULL)
1350 fprintf(fp, "# %s: %s\n", list_name,
1351 strlist__entry(list, 0)->s);
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001352 se->elide = true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001353 }
1354}
Namhyung Kim08e71542013-04-03 21:26:19 +09001355
1356void sort__setup_elide(FILE *output)
1357{
Namhyung Kim7524f632013-11-08 17:53:42 +09001358 struct sort_entry *se;
1359
Namhyung Kim08e71542013-04-03 21:26:19 +09001360 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1361 "dso", output);
1362 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1363 "comm", output);
1364 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1365 "symbol", output);
1366
1367 if (sort__mode == SORT_MODE__BRANCH) {
1368 sort_entry__setup_elide(&sort_dso_from,
1369 symbol_conf.dso_from_list,
1370 "dso_from", output);
1371 sort_entry__setup_elide(&sort_dso_to,
1372 symbol_conf.dso_to_list,
1373 "dso_to", output);
1374 sort_entry__setup_elide(&sort_sym_from,
1375 symbol_conf.sym_from_list,
1376 "sym_from", output);
1377 sort_entry__setup_elide(&sort_sym_to,
1378 symbol_conf.sym_to_list,
1379 "sym_to", output);
1380 } else if (sort__mode == SORT_MODE__MEMORY) {
1381 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1382 "symbol_daddr", output);
1383 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1384 "dso_daddr", output);
1385 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1386 "mem", output);
1387 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1388 "local_weight", output);
1389 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1390 "tlb", output);
1391 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1392 "snoop", output);
1393 }
1394
Namhyung Kim7524f632013-11-08 17:53:42 +09001395 /*
1396 * It makes no sense to elide all of sort entries.
1397 * Just revert them to show up again.
1398 */
1399 list_for_each_entry(se, &hist_entry__sort_list, list) {
1400 if (!se->elide)
1401 return;
1402 }
1403
1404 list_for_each_entry(se, &hist_entry__sort_list, list)
1405 se->elide = false;
Namhyung Kim08e71542013-04-03 21:26:19 +09001406}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001407
1408static int output_field_add(char *tok)
1409{
1410 unsigned int i;
1411
1412 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1413 struct sort_dimension *sd = &common_sort_dimensions[i];
1414
1415 if (strncasecmp(tok, sd->name, strlen(tok)))
1416 continue;
1417
1418 return __sort_dimension__add_output(sd);
1419 }
1420
1421 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1422 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1423
1424 if (strncasecmp(tok, hd->name, strlen(tok)))
1425 continue;
1426
1427 return __hpp_dimension__add_output(hd);
1428 }
1429
1430 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1431 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1432
1433 if (strncasecmp(tok, sd->name, strlen(tok)))
1434 continue;
1435
1436 return __sort_dimension__add_output(sd);
1437 }
1438
1439 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1440 struct sort_dimension *sd = &memory_sort_dimensions[i];
1441
1442 if (strncasecmp(tok, sd->name, strlen(tok)))
1443 continue;
1444
1445 return __sort_dimension__add_output(sd);
1446 }
1447
1448 return -ESRCH;
1449}
1450
1451static void reset_dimensions(void)
1452{
1453 unsigned int i;
1454
1455 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1456 common_sort_dimensions[i].taken = 0;
1457
1458 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1459 hpp_sort_dimensions[i].taken = 0;
1460
1461 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1462 bstack_sort_dimensions[i].taken = 0;
1463
1464 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1465 memory_sort_dimensions[i].taken = 0;
1466}
1467
1468static int __setup_output_field(void)
1469{
1470 char *tmp, *tok, *str;
1471 int ret = 0;
1472
1473 if (field_order == NULL)
1474 return 0;
1475
1476 reset_dimensions();
1477
1478 str = strdup(field_order);
1479 if (str == NULL) {
1480 error("Not enough memory to setup output fields");
1481 return -ENOMEM;
1482 }
1483
1484 for (tok = strtok_r(str, ", ", &tmp);
1485 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1486 ret = output_field_add(tok);
1487 if (ret == -EINVAL) {
1488 error("Invalid --fields key: `%s'", tok);
1489 break;
1490 } else if (ret == -ESRCH) {
1491 error("Unknown --fields key: `%s'", tok);
1492 break;
1493 }
1494 }
1495
1496 free(str);
1497 return ret;
1498}
1499
1500int setup_sorting(void)
1501{
1502 int err;
1503
1504 err = __setup_sorting();
1505 if (err < 0)
1506 return err;
1507
1508 if (parent_pattern != default_parent_pattern) {
1509 err = sort_dimension__add("parent");
1510 if (err < 0)
1511 return err;
1512 }
1513
1514 reset_dimensions();
1515
1516 /*
1517 * perf diff doesn't use default hpp output fields.
1518 */
1519 if (sort__mode != SORT_MODE__DIFF)
1520 perf_hpp__init();
1521
1522 err = __setup_output_field();
1523 if (err < 0)
1524 return err;
1525
1526 /* copy sort keys to output fields */
1527 perf_hpp__setup_output_field();
1528 /* and then copy output fields to sort keys */
1529 perf_hpp__append_sort_keys();
1530
1531 return 0;
1532}