blob: 1ec57dd822847cd90c562615deac6c0226a7a416 [file] [log] [blame]
Don Zickus9b32ba72014-06-01 15:38:29 +02001#include <sys/mman.h>
John Kacurdd68ada2009-09-24 18:02:49 +02002#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03003#include "hist.h"
Namhyung Kim4dfced32013-09-13 16:28:57 +09004#include "comm.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09005#include "symbol.h"
Namhyung Kim8b536992014-03-03 11:46:55 +09006#include "evsel.h"
John Kacurdd68ada2009-09-24 18:02:49 +02007
8regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03009const char default_parent_pattern[] = "^sys_|^do_page_fault";
10const char *parent_pattern = default_parent_pattern;
11const char default_sort_order[] = "comm,dso,symbol";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090012const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090017const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080018regex_t ignore_callees_regex;
19int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020020int sort__need_collapse = 0;
21int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090022int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090023int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090024enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020025
John Kacurdd68ada2009-09-24 18:02:49 +020026
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030027static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020028{
29 int n;
30 va_list ap;
31
32 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030033 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020034 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030035 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020036
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030037 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020038 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030039 if (sep == NULL)
40 break;
41 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020042 }
John Kacurdd68ada2009-09-24 18:02:49 +020043 }
44 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110045
46 if (n >= (int)size)
47 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020048 return n;
49}
50
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020051static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020052{
53 if (!l && !r)
54 return 0;
55 else if (!l)
56 return -1;
57 else
58 return 1;
59}
60
61/* --sort pid */
62
63static int64_t
64sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
65{
Adrian Hunter38051232013-07-04 16:20:31 +030066 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020067}
68
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030069static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030070 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020071{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020072 const char *comm = thread__comm_str(he->thread);
Namhyung Kimfb29a332012-12-27 18:11:40 +090073 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020074 comm ?: "", he->thread->tid);
John Kacurdd68ada2009-09-24 18:02:49 +020075}
76
Frederic Weisbecker872a8782011-06-29 03:14:52 +020077struct sort_entry sort_thread = {
78 .se_header = "Command: Pid",
79 .se_cmp = sort__thread_cmp,
80 .se_snprintf = hist_entry__thread_snprintf,
81 .se_width_idx = HISTC_THREAD,
82};
83
84/* --sort comm */
85
86static int64_t
87sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
88{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020089 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090090 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020091}
92
93static int64_t
94sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
95{
Namhyung Kim4dfced32013-09-13 16:28:57 +090096 /* Compare the addr that should be unique among comm */
97 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020098}
99
Namhyung Kim202e7a62014-03-04 11:01:41 +0900100static int64_t
101sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
102{
103 return strcmp(comm__str(right->comm), comm__str(left->comm));
104}
105
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300106static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300107 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200108{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900109 return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200110}
111
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900112struct sort_entry sort_comm = {
113 .se_header = "Command",
114 .se_cmp = sort__comm_cmp,
115 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900116 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900117 .se_snprintf = hist_entry__comm_snprintf,
118 .se_width_idx = HISTC_COMM,
119};
120
121/* --sort dso */
122
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100123static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200124{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100125 struct dso *dso_l = map_l ? map_l->dso : NULL;
126 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300127 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200128
129 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900130 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200131
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300132 if (verbose) {
133 dso_name_l = dso_l->long_name;
134 dso_name_r = dso_r->long_name;
135 } else {
136 dso_name_l = dso_l->short_name;
137 dso_name_r = dso_r->short_name;
138 }
139
140 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200141}
142
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100143static int64_t
144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200145{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900146 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100147}
148
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149static int _hist_entry__dso_snprintf(struct map *map, char *bf,
150 size_t size, unsigned int width)
151{
152 if (map && map->dso) {
153 const char *dso_name = !verbose ? map->dso->short_name :
154 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300155 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300156 }
John Kacurdd68ada2009-09-24 18:02:49 +0200157
Ian Munsie1437a302010-12-06 13:37:04 +1100158 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200159}
160
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300161static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100162 size_t size, unsigned int width)
163{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300164 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100165}
166
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900167struct sort_entry sort_dso = {
168 .se_header = "Shared Object",
169 .se_cmp = sort__dso_cmp,
170 .se_snprintf = hist_entry__dso_snprintf,
171 .se_width_idx = HISTC_DSO,
172};
173
174/* --sort symbol */
175
Namhyung Kim2037be52013-12-18 14:21:09 +0900176static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
177{
178 return (int64_t)(right_ip - left_ip);
179}
180
Namhyung Kim51f27d12013-02-06 14:57:15 +0900181static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900182{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900183 u64 ip_l, ip_r;
184
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900185 if (!sym_l || !sym_r)
186 return cmp_null(sym_l, sym_r);
187
188 if (sym_l == sym_r)
189 return 0;
190
191 ip_l = sym_l->start;
192 ip_r = sym_r->start;
193
194 return (int64_t)(ip_r - ip_l);
195}
196
197static int64_t
198sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
199{
Namhyung Kim09600e02013-10-15 11:01:56 +0900200 int64_t ret;
201
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900202 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900203 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204
Namhyung Kim09600e02013-10-15 11:01:56 +0900205 /*
206 * comparing symbol address alone is not enough since it's a
207 * relative address within a dso.
208 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900209 if (!sort__has_dso) {
210 ret = sort__dso_cmp(left, right);
211 if (ret != 0)
212 return ret;
213 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900214
Namhyung Kim51f27d12013-02-06 14:57:15 +0900215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900216}
217
Namhyung Kim202e7a62014-03-04 11:01:41 +0900218static int64_t
219sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220{
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
223
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
225}
226
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100227static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
228 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900229 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100230{
231 size_t ret = 0;
232
233 if (verbose) {
234 char o = map ? dso__symtab_origin(map->dso) : '!';
235 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900236 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100237 }
238
239 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100240 if (sym && map) {
241 if (map->type == MAP__VARIABLE) {
242 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
243 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100244 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100245 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
246 width - ret, "");
247 } else {
248 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
249 width - ret,
250 sym->name);
251 }
252 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100253 size_t len = BITS_PER_LONG / 4;
254 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
255 len, ip);
256 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
257 width - ret, "");
258 }
259
260 return ret;
261}
262
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300263static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900264 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100265{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300266 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
267 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100268}
John Kacurdd68ada2009-09-24 18:02:49 +0200269
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200270struct sort_entry sort_sym = {
271 .se_header = "Symbol",
272 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900273 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200274 .se_snprintf = hist_entry__sym_snprintf,
275 .se_width_idx = HISTC_SYMBOL,
276};
John Kacurdd68ada2009-09-24 18:02:49 +0200277
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300278/* --sort srcline */
279
280static int64_t
281sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
282{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900283 if (!left->srcline) {
284 if (!left->ms.map)
285 left->srcline = SRCLINE_UNKNOWN;
286 else {
287 struct map *map = left->ms.map;
288 left->srcline = get_srcline(map->dso,
289 map__rip_2objdump(map, left->ip));
290 }
291 }
292 if (!right->srcline) {
293 if (!right->ms.map)
294 right->srcline = SRCLINE_UNKNOWN;
295 else {
296 struct map *map = right->ms.map;
297 right->srcline = get_srcline(map->dso,
298 map__rip_2objdump(map, right->ip));
299 }
300 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900301 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300302}
303
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300304static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300305 size_t size,
306 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300307{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300308 return repsep_snprintf(bf, size, "%s", he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300309}
310
311struct sort_entry sort_srcline = {
312 .se_header = "Source:Line",
313 .se_cmp = sort__srcline_cmp,
314 .se_snprintf = hist_entry__srcline_snprintf,
315 .se_width_idx = HISTC_SRCLINE,
316};
317
John Kacurdd68ada2009-09-24 18:02:49 +0200318/* --sort parent */
319
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200320static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200321sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
322{
323 struct symbol *sym_l = left->parent;
324 struct symbol *sym_r = right->parent;
325
326 if (!sym_l || !sym_r)
327 return cmp_null(sym_l, sym_r);
328
Namhyung Kim202e7a62014-03-04 11:01:41 +0900329 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200330}
331
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300332static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300333 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200334{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300335 return repsep_snprintf(bf, size, "%-*s", width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300336 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200337}
338
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200339struct sort_entry sort_parent = {
340 .se_header = "Parent symbol",
341 .se_cmp = sort__parent_cmp,
342 .se_snprintf = hist_entry__parent_snprintf,
343 .se_width_idx = HISTC_PARENT,
344};
345
Arun Sharmaf60f3592010-06-04 11:27:10 -0300346/* --sort cpu */
347
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200348static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300349sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
350{
351 return right->cpu - left->cpu;
352}
353
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300354static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
355 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300356{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300357 return repsep_snprintf(bf, size, "%*d", width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300358}
359
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200360struct sort_entry sort_cpu = {
361 .se_header = "CPU",
362 .se_cmp = sort__cpu_cmp,
363 .se_snprintf = hist_entry__cpu_snprintf,
364 .se_width_idx = HISTC_CPU,
365};
366
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900367/* sort keys for branch stacks */
368
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100369static int64_t
370sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
371{
372 return _sort__dso_cmp(left->branch_info->from.map,
373 right->branch_info->from.map);
374}
375
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300376static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100377 size_t size, unsigned int width)
378{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300379 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100380 bf, size, width);
381}
382
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100383static int64_t
384sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 return _sort__dso_cmp(left->branch_info->to.map,
387 right->branch_info->to.map);
388}
389
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300390static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100391 size_t size, unsigned int width)
392{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300393 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100394 bf, size, width);
395}
396
397static int64_t
398sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
399{
400 struct addr_map_symbol *from_l = &left->branch_info->from;
401 struct addr_map_symbol *from_r = &right->branch_info->from;
402
403 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900404 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100405
Namhyung Kim51f27d12013-02-06 14:57:15 +0900406 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100407}
408
409static int64_t
410sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
411{
412 struct addr_map_symbol *to_l = &left->branch_info->to;
413 struct addr_map_symbol *to_r = &right->branch_info->to;
414
415 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900416 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100417
Namhyung Kim51f27d12013-02-06 14:57:15 +0900418 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100419}
420
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300421static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900422 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100423{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300424 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100425 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300426 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427
428}
429
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300430static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900431 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100432{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300433 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100434 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300435 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100436
437}
438
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900439struct sort_entry sort_dso_from = {
440 .se_header = "Source Shared Object",
441 .se_cmp = sort__dso_from_cmp,
442 .se_snprintf = hist_entry__dso_from_snprintf,
443 .se_width_idx = HISTC_DSO_FROM,
444};
445
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100446struct sort_entry sort_dso_to = {
447 .se_header = "Target Shared Object",
448 .se_cmp = sort__dso_to_cmp,
449 .se_snprintf = hist_entry__dso_to_snprintf,
450 .se_width_idx = HISTC_DSO_TO,
451};
452
453struct sort_entry sort_sym_from = {
454 .se_header = "Source Symbol",
455 .se_cmp = sort__sym_from_cmp,
456 .se_snprintf = hist_entry__sym_from_snprintf,
457 .se_width_idx = HISTC_SYMBOL_FROM,
458};
459
460struct sort_entry sort_sym_to = {
461 .se_header = "Target Symbol",
462 .se_cmp = sort__sym_to_cmp,
463 .se_snprintf = hist_entry__sym_to_snprintf,
464 .se_width_idx = HISTC_SYMBOL_TO,
465};
466
467static int64_t
468sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
469{
470 const unsigned char mp = left->branch_info->flags.mispred !=
471 right->branch_info->flags.mispred;
472 const unsigned char p = left->branch_info->flags.predicted !=
473 right->branch_info->flags.predicted;
474
475 return mp || p;
476}
477
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300478static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100479 size_t size, unsigned int width){
480 static const char *out = "N/A";
481
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300482 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100483 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300484 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100485 out = "Y";
486
487 return repsep_snprintf(bf, size, "%-*s", width, out);
488}
489
Stephane Eranian98a3b322013-01-24 16:10:35 +0100490/* --sort daddr_sym */
491static int64_t
492sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
493{
494 uint64_t l = 0, r = 0;
495
496 if (left->mem_info)
497 l = left->mem_info->daddr.addr;
498 if (right->mem_info)
499 r = right->mem_info->daddr.addr;
500
501 return (int64_t)(r - l);
502}
503
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300504static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100505 size_t size, unsigned int width)
506{
507 uint64_t addr = 0;
508 struct map *map = NULL;
509 struct symbol *sym = NULL;
510
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300511 if (he->mem_info) {
512 addr = he->mem_info->daddr.addr;
513 map = he->mem_info->daddr.map;
514 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100515 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300516 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100517 width);
518}
519
520static int64_t
521sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
522{
523 struct map *map_l = NULL;
524 struct map *map_r = NULL;
525
526 if (left->mem_info)
527 map_l = left->mem_info->daddr.map;
528 if (right->mem_info)
529 map_r = right->mem_info->daddr.map;
530
531 return _sort__dso_cmp(map_l, map_r);
532}
533
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300534static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100535 size_t size, unsigned int width)
536{
537 struct map *map = NULL;
538
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300539 if (he->mem_info)
540 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100541
542 return _hist_entry__dso_snprintf(map, bf, size, width);
543}
544
545static int64_t
546sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
547{
548 union perf_mem_data_src data_src_l;
549 union perf_mem_data_src data_src_r;
550
551 if (left->mem_info)
552 data_src_l = left->mem_info->data_src;
553 else
554 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
555
556 if (right->mem_info)
557 data_src_r = right->mem_info->data_src;
558 else
559 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
560
561 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
562}
563
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300564static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100565 size_t size, unsigned int width)
566{
567 const char *out;
568 u64 mask = PERF_MEM_LOCK_NA;
569
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300570 if (he->mem_info)
571 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100572
573 if (mask & PERF_MEM_LOCK_NA)
574 out = "N/A";
575 else if (mask & PERF_MEM_LOCK_LOCKED)
576 out = "Yes";
577 else
578 out = "No";
579
580 return repsep_snprintf(bf, size, "%-*s", width, out);
581}
582
583static int64_t
584sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
585{
586 union perf_mem_data_src data_src_l;
587 union perf_mem_data_src data_src_r;
588
589 if (left->mem_info)
590 data_src_l = left->mem_info->data_src;
591 else
592 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
593
594 if (right->mem_info)
595 data_src_r = right->mem_info->data_src;
596 else
597 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
598
599 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
600}
601
602static const char * const tlb_access[] = {
603 "N/A",
604 "HIT",
605 "MISS",
606 "L1",
607 "L2",
608 "Walker",
609 "Fault",
610};
611#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
612
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300613static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100614 size_t size, unsigned int width)
615{
616 char out[64];
617 size_t sz = sizeof(out) - 1; /* -1 for null termination */
618 size_t l = 0, i;
619 u64 m = PERF_MEM_TLB_NA;
620 u64 hit, miss;
621
622 out[0] = '\0';
623
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300624 if (he->mem_info)
625 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100626
627 hit = m & PERF_MEM_TLB_HIT;
628 miss = m & PERF_MEM_TLB_MISS;
629
630 /* already taken care of */
631 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
632
633 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
634 if (!(m & 0x1))
635 continue;
636 if (l) {
637 strcat(out, " or ");
638 l += 4;
639 }
640 strncat(out, tlb_access[i], sz - l);
641 l += strlen(tlb_access[i]);
642 }
643 if (*out == '\0')
644 strcpy(out, "N/A");
645 if (hit)
646 strncat(out, " hit", sz - l);
647 if (miss)
648 strncat(out, " miss", sz - l);
649
650 return repsep_snprintf(bf, size, "%-*s", width, out);
651}
652
653static int64_t
654sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
655{
656 union perf_mem_data_src data_src_l;
657 union perf_mem_data_src data_src_r;
658
659 if (left->mem_info)
660 data_src_l = left->mem_info->data_src;
661 else
662 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
663
664 if (right->mem_info)
665 data_src_r = right->mem_info->data_src;
666 else
667 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
668
669 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
670}
671
672static const char * const mem_lvl[] = {
673 "N/A",
674 "HIT",
675 "MISS",
676 "L1",
677 "LFB",
678 "L2",
679 "L3",
680 "Local RAM",
681 "Remote RAM (1 hop)",
682 "Remote RAM (2 hops)",
683 "Remote Cache (1 hop)",
684 "Remote Cache (2 hops)",
685 "I/O",
686 "Uncached",
687};
688#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
689
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300690static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100691 size_t size, unsigned int width)
692{
693 char out[64];
694 size_t sz = sizeof(out) - 1; /* -1 for null termination */
695 size_t i, l = 0;
696 u64 m = PERF_MEM_LVL_NA;
697 u64 hit, miss;
698
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300699 if (he->mem_info)
700 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100701
702 out[0] = '\0';
703
704 hit = m & PERF_MEM_LVL_HIT;
705 miss = m & PERF_MEM_LVL_MISS;
706
707 /* already taken care of */
708 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
709
710 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
711 if (!(m & 0x1))
712 continue;
713 if (l) {
714 strcat(out, " or ");
715 l += 4;
716 }
717 strncat(out, mem_lvl[i], sz - l);
718 l += strlen(mem_lvl[i]);
719 }
720 if (*out == '\0')
721 strcpy(out, "N/A");
722 if (hit)
723 strncat(out, " hit", sz - l);
724 if (miss)
725 strncat(out, " miss", sz - l);
726
727 return repsep_snprintf(bf, size, "%-*s", width, out);
728}
729
730static int64_t
731sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
732{
733 union perf_mem_data_src data_src_l;
734 union perf_mem_data_src data_src_r;
735
736 if (left->mem_info)
737 data_src_l = left->mem_info->data_src;
738 else
739 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
740
741 if (right->mem_info)
742 data_src_r = right->mem_info->data_src;
743 else
744 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
745
746 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
747}
748
749static const char * const snoop_access[] = {
750 "N/A",
751 "None",
752 "Miss",
753 "Hit",
754 "HitM",
755};
756#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
757
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300758static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100759 size_t size, unsigned int width)
760{
761 char out[64];
762 size_t sz = sizeof(out) - 1; /* -1 for null termination */
763 size_t i, l = 0;
764 u64 m = PERF_MEM_SNOOP_NA;
765
766 out[0] = '\0';
767
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300768 if (he->mem_info)
769 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100770
771 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
772 if (!(m & 0x1))
773 continue;
774 if (l) {
775 strcat(out, " or ");
776 l += 4;
777 }
778 strncat(out, snoop_access[i], sz - l);
779 l += strlen(snoop_access[i]);
780 }
781
782 if (*out == '\0')
783 strcpy(out, "N/A");
784
785 return repsep_snprintf(bf, size, "%-*s", width, out);
786}
787
Don Zickus9b32ba72014-06-01 15:38:29 +0200788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100886struct sort_entry sort_mispredict = {
887 .se_header = "Branch Mispredicted",
888 .se_cmp = sort__mispredict_cmp,
889 .se_snprintf = hist_entry__mispredict_snprintf,
890 .se_width_idx = HISTC_MISPREDICT,
891};
892
Andi Kleen05484292013-01-24 16:10:29 +0100893static u64 he_weight(struct hist_entry *he)
894{
895 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
896}
897
898static int64_t
899sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
900{
901 return he_weight(left) - he_weight(right);
902}
903
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300904static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100905 size_t size, unsigned int width)
906{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300907 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100908}
909
910struct sort_entry sort_local_weight = {
911 .se_header = "Local Weight",
912 .se_cmp = sort__local_weight_cmp,
913 .se_snprintf = hist_entry__local_weight_snprintf,
914 .se_width_idx = HISTC_LOCAL_WEIGHT,
915};
916
917static int64_t
918sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
919{
920 return left->stat.weight - right->stat.weight;
921}
922
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300923static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100924 size_t size, unsigned int width)
925{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300926 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100927}
928
929struct sort_entry sort_global_weight = {
930 .se_header = "Weight",
931 .se_cmp = sort__global_weight_cmp,
932 .se_snprintf = hist_entry__global_weight_snprintf,
933 .se_width_idx = HISTC_GLOBAL_WEIGHT,
934};
935
Stephane Eranian98a3b322013-01-24 16:10:35 +0100936struct sort_entry sort_mem_daddr_sym = {
937 .se_header = "Data Symbol",
938 .se_cmp = sort__daddr_cmp,
939 .se_snprintf = hist_entry__daddr_snprintf,
940 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
941};
942
943struct sort_entry sort_mem_daddr_dso = {
944 .se_header = "Data Object",
945 .se_cmp = sort__dso_daddr_cmp,
946 .se_snprintf = hist_entry__dso_daddr_snprintf,
947 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
948};
949
950struct sort_entry sort_mem_locked = {
951 .se_header = "Locked",
952 .se_cmp = sort__locked_cmp,
953 .se_snprintf = hist_entry__locked_snprintf,
954 .se_width_idx = HISTC_MEM_LOCKED,
955};
956
957struct sort_entry sort_mem_tlb = {
958 .se_header = "TLB access",
959 .se_cmp = sort__tlb_cmp,
960 .se_snprintf = hist_entry__tlb_snprintf,
961 .se_width_idx = HISTC_MEM_TLB,
962};
963
964struct sort_entry sort_mem_lvl = {
965 .se_header = "Memory access",
966 .se_cmp = sort__lvl_cmp,
967 .se_snprintf = hist_entry__lvl_snprintf,
968 .se_width_idx = HISTC_MEM_LVL,
969};
970
971struct sort_entry sort_mem_snoop = {
972 .se_header = "Snoop",
973 .se_cmp = sort__snoop_cmp,
974 .se_snprintf = hist_entry__snoop_snprintf,
975 .se_width_idx = HISTC_MEM_SNOOP,
976};
977
Don Zickus9b32ba72014-06-01 15:38:29 +0200978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700985static int64_t
986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
987{
988 return left->branch_info->flags.abort !=
989 right->branch_info->flags.abort;
990}
991
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300992static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700993 size_t size, unsigned int width)
994{
995 static const char *out = ".";
996
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300997 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700998 out = "A";
999 return repsep_snprintf(bf, size, "%-*s", width, out);
1000}
1001
1002struct sort_entry sort_abort = {
1003 .se_header = "Transaction abort",
1004 .se_cmp = sort__abort_cmp,
1005 .se_snprintf = hist_entry__abort_snprintf,
1006 .se_width_idx = HISTC_ABORT,
1007};
1008
1009static int64_t
1010sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1011{
1012 return left->branch_info->flags.in_tx !=
1013 right->branch_info->flags.in_tx;
1014}
1015
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001016static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001017 size_t size, unsigned int width)
1018{
1019 static const char *out = ".";
1020
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001021 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001022 out = "T";
1023
1024 return repsep_snprintf(bf, size, "%-*s", width, out);
1025}
1026
1027struct sort_entry sort_in_tx = {
1028 .se_header = "Branch in transaction",
1029 .se_cmp = sort__in_tx_cmp,
1030 .se_snprintf = hist_entry__in_tx_snprintf,
1031 .se_width_idx = HISTC_IN_TX,
1032};
1033
Andi Kleen475eeab2013-09-20 07:40:43 -07001034static int64_t
1035sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1036{
1037 return left->transaction - right->transaction;
1038}
1039
1040static inline char *add_str(char *p, const char *str)
1041{
1042 strcpy(p, str);
1043 return p + strlen(str);
1044}
1045
1046static struct txbit {
1047 unsigned flag;
1048 const char *name;
1049 int skip_for_len;
1050} txbits[] = {
1051 { PERF_TXN_ELISION, "EL ", 0 },
1052 { PERF_TXN_TRANSACTION, "TX ", 1 },
1053 { PERF_TXN_SYNC, "SYNC ", 1 },
1054 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1055 { PERF_TXN_RETRY, "RETRY ", 0 },
1056 { PERF_TXN_CONFLICT, "CON ", 0 },
1057 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1058 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1059 { 0, NULL, 0 }
1060};
1061
1062int hist_entry__transaction_len(void)
1063{
1064 int i;
1065 int len = 0;
1066
1067 for (i = 0; txbits[i].name; i++) {
1068 if (!txbits[i].skip_for_len)
1069 len += strlen(txbits[i].name);
1070 }
1071 len += 4; /* :XX<space> */
1072 return len;
1073}
1074
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001075static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001076 size_t size, unsigned int width)
1077{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001078 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001079 char buf[128];
1080 char *p = buf;
1081 int i;
1082
1083 buf[0] = 0;
1084 for (i = 0; txbits[i].name; i++)
1085 if (txbits[i].flag & t)
1086 p = add_str(p, txbits[i].name);
1087 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1088 p = add_str(p, "NEITHER ");
1089 if (t & PERF_TXN_ABORT_MASK) {
1090 sprintf(p, ":%" PRIx64,
1091 (t & PERF_TXN_ABORT_MASK) >>
1092 PERF_TXN_ABORT_SHIFT);
1093 p += strlen(p);
1094 }
1095
1096 return repsep_snprintf(bf, size, "%-*s", width, buf);
1097}
1098
1099struct sort_entry sort_transaction = {
1100 .se_header = "Transaction ",
1101 .se_cmp = sort__transaction_cmp,
1102 .se_snprintf = hist_entry__transaction_snprintf,
1103 .se_width_idx = HISTC_TRANSACTION,
1104};
1105
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001106struct sort_dimension {
1107 const char *name;
1108 struct sort_entry *entry;
1109 int taken;
1110};
1111
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001112#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1113
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001114static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001115 DIM(SORT_PID, "pid", sort_thread),
1116 DIM(SORT_COMM, "comm", sort_comm),
1117 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001118 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001119 DIM(SORT_PARENT, "parent", sort_parent),
1120 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001121 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001122 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1123 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001124 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001125};
1126
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001127#undef DIM
1128
1129#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1130
1131static struct sort_dimension bstack_sort_dimensions[] = {
1132 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1133 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1134 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1135 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1136 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001137 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1138 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001139};
1140
1141#undef DIM
1142
Namhyung Kimafab87b2013-04-03 21:26:11 +09001143#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1144
1145static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001146 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1147 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1148 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001153};
1154
1155#undef DIM
1156
Namhyung Kima2ce0672014-03-04 09:06:42 +09001157struct hpp_dimension {
1158 const char *name;
1159 struct perf_hpp_fmt *fmt;
1160 int taken;
1161};
1162
1163#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1164
1165static struct hpp_dimension hpp_sort_dimensions[] = {
1166 DIM(PERF_HPP__OVERHEAD, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001172 DIM(PERF_HPP__SAMPLES, "sample"),
1173 DIM(PERF_HPP__PERIOD, "period"),
1174};
1175
1176#undef DIM
1177
Namhyung Kim8b536992014-03-03 11:46:55 +09001178struct hpp_sort_entry {
1179 struct perf_hpp_fmt hpp;
1180 struct sort_entry *se;
1181};
1182
Namhyung Kima7d945b2014-03-04 10:46:34 +09001183bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1184{
1185 struct hpp_sort_entry *hse_a;
1186 struct hpp_sort_entry *hse_b;
1187
1188 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1189 return false;
1190
1191 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1192 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1193
1194 return hse_a->se == hse_b->se;
1195}
1196
Namhyung Kim678a5002014-03-20 11:18:54 +09001197void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1198{
1199 struct hpp_sort_entry *hse;
1200
1201 if (!perf_hpp__is_sort_entry(fmt))
1202 return;
1203
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx,
1206 strlen(hse->se->se_header));
1207}
1208
Namhyung Kim8b536992014-03-03 11:46:55 +09001209static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel)
1211{
1212 struct hpp_sort_entry *hse;
1213 size_t len;
1214
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1219}
1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1222 struct perf_hpp *hpp __maybe_unused,
1223 struct perf_evsel *evsel)
1224{
1225 struct hpp_sort_entry *hse;
1226
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1228
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1230}
1231
1232static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he)
1234{
1235 struct hpp_sort_entry *hse;
1236 size_t len;
1237
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx);
1240
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1242}
1243
Namhyung Kima7d945b2014-03-04 10:46:34 +09001244static struct hpp_sort_entry *
1245__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001246{
1247 struct hpp_sort_entry *hse;
1248
1249 hse = malloc(sizeof(*hse));
1250 if (hse == NULL) {
1251 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001252 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001253 }
1254
1255 hse->se = sd->entry;
1256 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry;
1259 hse->hpp.color = NULL;
1260
1261 hse->hpp.cmp = sd->entry->se_cmp;
1262 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001263 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001264
1265 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001267 hse->hpp.elide = false;
Namhyung Kim8b536992014-03-03 11:46:55 +09001268
Namhyung Kima7d945b2014-03-04 10:46:34 +09001269 return hse;
1270}
1271
1272bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1273{
1274 return format->header == __sort__hpp_header;
1275}
1276
1277static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1278{
1279 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1280
1281 if (hse == NULL)
1282 return -1;
1283
Namhyung Kim8b536992014-03-03 11:46:55 +09001284 perf_hpp__register_sort_field(&hse->hpp);
1285 return 0;
1286}
1287
Namhyung Kima7d945b2014-03-04 10:46:34 +09001288static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1289{
1290 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1291
1292 if (hse == NULL)
1293 return -1;
1294
1295 perf_hpp__column_register(&hse->hpp);
1296 return 0;
1297}
1298
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001299static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001300{
1301 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001302 return 0;
1303
Namhyung Kima7d945b2014-03-04 10:46:34 +09001304 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001305 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001306
1307 if (sd->entry->se_collapse)
1308 sort__need_collapse = 1;
1309
Namhyung Kim2f532d092013-04-03 21:26:10 +09001310 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001311
1312 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001313}
1314
Namhyung Kima2ce0672014-03-04 09:06:42 +09001315static int __hpp_dimension__add(struct hpp_dimension *hd)
1316{
1317 if (!hd->taken) {
1318 hd->taken = 1;
1319
1320 perf_hpp__register_sort_field(hd->fmt);
1321 }
1322 return 0;
1323}
1324
Namhyung Kima7d945b2014-03-04 10:46:34 +09001325static int __sort_dimension__add_output(struct sort_dimension *sd)
1326{
1327 if (sd->taken)
1328 return 0;
1329
1330 if (__sort_dimension__add_hpp_output(sd) < 0)
1331 return -1;
1332
1333 sd->taken = 1;
1334 return 0;
1335}
1336
1337static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1338{
1339 if (!hd->taken) {
1340 hd->taken = 1;
1341
1342 perf_hpp__column_register(hd->fmt);
1343 }
1344 return 0;
1345}
1346
John Kacurdd68ada2009-09-24 18:02:49 +02001347int sort_dimension__add(const char *tok)
1348{
1349 unsigned int i;
1350
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001351 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1352 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001353
John Kacurdd68ada2009-09-24 18:02:49 +02001354 if (strncasecmp(tok, sd->name, strlen(tok)))
1355 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001356
John Kacurdd68ada2009-09-24 18:02:49 +02001357 if (sd->entry == &sort_parent) {
1358 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1359 if (ret) {
1360 char err[BUFSIZ];
1361
1362 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001363 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1364 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001365 }
1366 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001367 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001368 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001369 } else if (sd->entry == &sort_dso) {
1370 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001371 }
1372
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001373 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001374 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001375
Namhyung Kima2ce0672014-03-04 09:06:42 +09001376 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1377 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1378
1379 if (strncasecmp(tok, hd->name, strlen(tok)))
1380 continue;
1381
1382 return __hpp_dimension__add(hd);
1383 }
1384
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001385 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1386 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1387
1388 if (strncasecmp(tok, sd->name, strlen(tok)))
1389 continue;
1390
Namhyung Kim55369fc2013-04-01 20:35:20 +09001391 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001392 return -EINVAL;
1393
1394 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1395 sort__has_sym = 1;
1396
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001397 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001398 return 0;
1399 }
1400
Namhyung Kimafab87b2013-04-03 21:26:11 +09001401 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1402 struct sort_dimension *sd = &memory_sort_dimensions[i];
1403
1404 if (strncasecmp(tok, sd->name, strlen(tok)))
1405 continue;
1406
1407 if (sort__mode != SORT_MODE__MEMORY)
1408 return -EINVAL;
1409
1410 if (sd->entry == &sort_mem_daddr_sym)
1411 sort__has_sym = 1;
1412
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001413 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001414 return 0;
1415 }
1416
John Kacurdd68ada2009-09-24 18:02:49 +02001417 return -ESRCH;
1418}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001419
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001420static const char *get_default_sort_order(void)
1421{
1422 const char *default_sort_orders[] = {
1423 default_sort_order,
1424 default_branch_sort_order,
1425 default_mem_sort_order,
1426 default_top_sort_order,
1427 default_diff_sort_order,
1428 };
1429
1430 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1431
1432 return default_sort_orders[sort__mode];
1433}
1434
Namhyung Kima7d945b2014-03-04 10:46:34 +09001435static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001436{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001437 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order;
Namhyung Kim55309982013-02-06 14:57:16 +09001439 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001440
Namhyung Kima7d945b2014-03-04 10:46:34 +09001441 if (sort_keys == NULL) {
1442 if (field_order) {
1443 /*
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1446 */
1447 return 0;
1448 }
1449
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001450 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001451 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001452
1453 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001454 if (str == NULL) {
1455 error("Not enough memory to setup sort keys");
1456 return -ENOMEM;
1457 }
1458
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001459 for (tok = strtok_r(str, ", ", &tmp);
1460 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001461 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001462 if (ret == -EINVAL) {
1463 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001464 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001465 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001466 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001467 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001468 }
1469 }
1470
1471 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001472 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001473}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001474
Jiri Olsaf2998422014-05-23 17:15:47 +02001475void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001476{
Jiri Olsaf2998422014-05-23 17:15:47 +02001477 struct perf_hpp_fmt *fmt;
1478 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001479
Jiri Olsaf2998422014-05-23 17:15:47 +02001480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1483
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001489 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001490}
1491
Jiri Olsaf2998422014-05-23 17:15:47 +02001492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001493{
1494 if (list && strlist__nr_entries(list) == 1) {
1495 if (fp != NULL)
1496 fprintf(fp, "# %s: %s\n", list_name,
1497 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001498 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001499 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1514 }
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001533}
Namhyung Kim08e71542013-04-03 21:26:19 +09001534
1535void sort__setup_elide(FILE *output)
1536{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001537 struct perf_hpp_fmt *fmt;
1538 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001539
Jiri Olsaf2998422014-05-23 17:15:47 +02001540 perf_hpp__for_each_format(fmt) {
1541 if (!perf_hpp__is_sort_entry(fmt))
1542 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001543
Jiri Olsaf2998422014-05-23 17:15:47 +02001544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001546 }
1547
Namhyung Kim7524f632013-11-08 17:53:42 +09001548 /*
1549 * It makes no sense to elide all of sort entries.
1550 * Just revert them to show up again.
1551 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001552 perf_hpp__for_each_format(fmt) {
1553 if (!perf_hpp__is_sort_entry(fmt))
1554 continue;
1555
Jiri Olsaf2998422014-05-23 17:15:47 +02001556 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001557 return;
1558 }
1559
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001560 perf_hpp__for_each_format(fmt) {
1561 if (!perf_hpp__is_sort_entry(fmt))
1562 continue;
1563
Jiri Olsaf2998422014-05-23 17:15:47 +02001564 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001565 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001566}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001567
1568static int output_field_add(char *tok)
1569{
1570 unsigned int i;
1571
1572 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1573 struct sort_dimension *sd = &common_sort_dimensions[i];
1574
1575 if (strncasecmp(tok, sd->name, strlen(tok)))
1576 continue;
1577
1578 return __sort_dimension__add_output(sd);
1579 }
1580
1581 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1582 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1583
1584 if (strncasecmp(tok, hd->name, strlen(tok)))
1585 continue;
1586
1587 return __hpp_dimension__add_output(hd);
1588 }
1589
1590 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1591 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1592
1593 if (strncasecmp(tok, sd->name, strlen(tok)))
1594 continue;
1595
1596 return __sort_dimension__add_output(sd);
1597 }
1598
1599 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1600 struct sort_dimension *sd = &memory_sort_dimensions[i];
1601
1602 if (strncasecmp(tok, sd->name, strlen(tok)))
1603 continue;
1604
1605 return __sort_dimension__add_output(sd);
1606 }
1607
1608 return -ESRCH;
1609}
1610
1611static void reset_dimensions(void)
1612{
1613 unsigned int i;
1614
1615 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1616 common_sort_dimensions[i].taken = 0;
1617
1618 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1619 hpp_sort_dimensions[i].taken = 0;
1620
1621 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1622 bstack_sort_dimensions[i].taken = 0;
1623
1624 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1625 memory_sort_dimensions[i].taken = 0;
1626}
1627
1628static int __setup_output_field(void)
1629{
1630 char *tmp, *tok, *str;
1631 int ret = 0;
1632
1633 if (field_order == NULL)
1634 return 0;
1635
1636 reset_dimensions();
1637
1638 str = strdup(field_order);
1639 if (str == NULL) {
1640 error("Not enough memory to setup output fields");
1641 return -ENOMEM;
1642 }
1643
1644 for (tok = strtok_r(str, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok);
1647 if (ret == -EINVAL) {
1648 error("Invalid --fields key: `%s'", tok);
1649 break;
1650 } else if (ret == -ESRCH) {
1651 error("Unknown --fields key: `%s'", tok);
1652 break;
1653 }
1654 }
1655
1656 free(str);
1657 return ret;
1658}
1659
1660int setup_sorting(void)
1661{
1662 int err;
1663
1664 err = __setup_sorting();
1665 if (err < 0)
1666 return err;
1667
1668 if (parent_pattern != default_parent_pattern) {
1669 err = sort_dimension__add("parent");
1670 if (err < 0)
1671 return err;
1672 }
1673
1674 reset_dimensions();
1675
1676 /*
1677 * perf diff doesn't use default hpp output fields.
1678 */
1679 if (sort__mode != SORT_MODE__DIFF)
1680 perf_hpp__init();
1681
1682 err = __setup_output_field();
1683 if (err < 0)
1684 return err;
1685
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1690
1691 return 0;
1692}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001693
1694void reset_output_field(void)
1695{
1696 sort__need_collapse = 0;
1697 sort__has_parent = 0;
1698 sort__has_sym = 0;
1699 sort__has_dso = 0;
1700
Namhyung Kimd69b2962014-05-23 10:59:01 +09001701 field_order = NULL;
1702 sort_order = NULL;
1703
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001704 reset_dimensions();
1705 perf_hpp__reset_output_field();
1706}