blob: 289df9d1e65ae277f585f384db91eaa402f5b405 [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 Kim5b591662014-07-31 14:47:38 +090073
74 width = max(7U, width) - 6;
75 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020077}
78
Frederic Weisbecker872a8782011-06-29 03:14:52 +020079struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090080 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020081 .se_cmp = sort__thread_cmp,
82 .se_snprintf = hist_entry__thread_snprintf,
83 .se_width_idx = HISTC_THREAD,
84};
85
86/* --sort comm */
87
88static int64_t
89sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
90{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020091 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090092 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020093}
94
95static int64_t
96sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97{
Namhyung Kim4dfced32013-09-13 16:28:57 +090098 /* Compare the addr that should be unique among comm */
99 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200100}
101
Namhyung Kim202e7a62014-03-04 11:01:41 +0900102static int64_t
103sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104{
105 return strcmp(comm__str(right->comm), comm__str(left->comm));
106}
107
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300108static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300109 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200110{
Namhyung Kim5b591662014-07-31 14:47:38 +0900111 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200112}
113
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900114struct sort_entry sort_comm = {
115 .se_header = "Command",
116 .se_cmp = sort__comm_cmp,
117 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900118 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900119 .se_snprintf = hist_entry__comm_snprintf,
120 .se_width_idx = HISTC_COMM,
121};
122
123/* --sort dso */
124
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100125static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200126{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100127 struct dso *dso_l = map_l ? map_l->dso : NULL;
128 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300129 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200130
131 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900132 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200133
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300134 if (verbose) {
135 dso_name_l = dso_l->long_name;
136 dso_name_r = dso_r->long_name;
137 } else {
138 dso_name_l = dso_l->short_name;
139 dso_name_r = dso_r->short_name;
140 }
141
142 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200143}
144
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100145static int64_t
146sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200147{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900148 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149}
150
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100151static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 size_t size, unsigned int width)
153{
154 if (map && map->dso) {
155 const char *dso_name = !verbose ? map->dso->short_name :
156 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900157 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300158 }
John Kacurdd68ada2009-09-24 18:02:49 +0200159
Namhyung Kim5b591662014-07-31 14:47:38 +0900160 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200161}
162
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300163static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164 size_t size, unsigned int width)
165{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300166 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100167}
168
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900169struct sort_entry sort_dso = {
170 .se_header = "Shared Object",
171 .se_cmp = sort__dso_cmp,
172 .se_snprintf = hist_entry__dso_snprintf,
173 .se_width_idx = HISTC_DSO,
174};
175
176/* --sort symbol */
177
Namhyung Kim2037be52013-12-18 14:21:09 +0900178static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179{
180 return (int64_t)(right_ip - left_ip);
181}
182
Namhyung Kim51f27d12013-02-06 14:57:15 +0900183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900184{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900185 u64 ip_l, ip_r;
186
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187 if (!sym_l || !sym_r)
188 return cmp_null(sym_l, sym_r);
189
190 if (sym_l == sym_r)
191 return 0;
192
193 ip_l = sym_l->start;
194 ip_r = sym_r->start;
195
196 return (int64_t)(ip_r - ip_l);
197}
198
199static int64_t
200sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
201{
Namhyung Kim09600e02013-10-15 11:01:56 +0900202 int64_t ret;
203
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900205 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Namhyung Kim09600e02013-10-15 11:01:56 +0900207 /*
208 * comparing symbol address alone is not enough since it's a
209 * relative address within a dso.
210 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900211 if (!sort__has_dso) {
212 ret = sort__dso_cmp(left, right);
213 if (ret != 0)
214 return ret;
215 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900216
Namhyung Kim51f27d12013-02-06 14:57:15 +0900217 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900218}
219
Namhyung Kim202e7a62014-03-04 11:01:41 +0900220static int64_t
221sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
222{
223 if (!left->ms.sym || !right->ms.sym)
224 return cmp_null(left->ms.sym, right->ms.sym);
225
226 return strcmp(right->ms.sym->name, left->ms.sym->name);
227}
228
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
230 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900231 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100232{
233 size_t ret = 0;
234
235 if (verbose) {
236 char o = map ? dso__symtab_origin(map->dso) : '!';
237 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900238 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239 }
240
241 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100242 if (sym && map) {
243 if (map->type == MAP__VARIABLE) {
244 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
245 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100246 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100247 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
248 width - ret, "");
249 } else {
250 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
251 width - ret,
252 sym->name);
253 }
254 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100255 size_t len = BITS_PER_LONG / 4;
256 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
257 len, ip);
258 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259 width - ret, "");
260 }
261
Namhyung Kim5b591662014-07-31 14:47:38 +0900262 if (ret > width)
263 bf[width] = '\0';
264
265 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100266}
267
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300268static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900269 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300271 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
272 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100273}
John Kacurdd68ada2009-09-24 18:02:49 +0200274
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200275struct sort_entry sort_sym = {
276 .se_header = "Symbol",
277 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900278 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200279 .se_snprintf = hist_entry__sym_snprintf,
280 .se_width_idx = HISTC_SYMBOL,
281};
John Kacurdd68ada2009-09-24 18:02:49 +0200282
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300283/* --sort srcline */
284
285static int64_t
286sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
287{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900288 if (!left->srcline) {
289 if (!left->ms.map)
290 left->srcline = SRCLINE_UNKNOWN;
291 else {
292 struct map *map = left->ms.map;
293 left->srcline = get_srcline(map->dso,
294 map__rip_2objdump(map, left->ip));
295 }
296 }
297 if (!right->srcline) {
298 if (!right->ms.map)
299 right->srcline = SRCLINE_UNKNOWN;
300 else {
301 struct map *map = right->ms.map;
302 right->srcline = get_srcline(map->dso,
303 map__rip_2objdump(map, right->ip));
304 }
305 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900306 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300307}
308
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300309static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900310 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300311{
Namhyung Kim5b591662014-07-31 14:47:38 +0900312 return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313}
314
315struct sort_entry sort_srcline = {
316 .se_header = "Source:Line",
317 .se_cmp = sort__srcline_cmp,
318 .se_snprintf = hist_entry__srcline_snprintf,
319 .se_width_idx = HISTC_SRCLINE,
320};
321
John Kacurdd68ada2009-09-24 18:02:49 +0200322/* --sort parent */
323
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200324static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200325sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
326{
327 struct symbol *sym_l = left->parent;
328 struct symbol *sym_r = right->parent;
329
330 if (!sym_l || !sym_r)
331 return cmp_null(sym_l, sym_r);
332
Namhyung Kim202e7a62014-03-04 11:01:41 +0900333 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200334}
335
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300336static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300337 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200338{
Namhyung Kim5b591662014-07-31 14:47:38 +0900339 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300340 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200341}
342
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200343struct sort_entry sort_parent = {
344 .se_header = "Parent symbol",
345 .se_cmp = sort__parent_cmp,
346 .se_snprintf = hist_entry__parent_snprintf,
347 .se_width_idx = HISTC_PARENT,
348};
349
Arun Sharmaf60f3592010-06-04 11:27:10 -0300350/* --sort cpu */
351
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200352static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300353sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354{
355 return right->cpu - left->cpu;
356}
357
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300358static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
359 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300360{
Namhyung Kim5b591662014-07-31 14:47:38 +0900361 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300362}
363
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200364struct sort_entry sort_cpu = {
365 .se_header = "CPU",
366 .se_cmp = sort__cpu_cmp,
367 .se_snprintf = hist_entry__cpu_snprintf,
368 .se_width_idx = HISTC_CPU,
369};
370
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900371/* sort keys for branch stacks */
372
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100373static int64_t
374sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
375{
376 return _sort__dso_cmp(left->branch_info->from.map,
377 right->branch_info->from.map);
378}
379
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300380static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100381 size_t size, unsigned int width)
382{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300383 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100384 bf, size, width);
385}
386
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100387static int64_t
388sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
389{
390 return _sort__dso_cmp(left->branch_info->to.map,
391 right->branch_info->to.map);
392}
393
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300394static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100395 size_t size, unsigned int width)
396{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100398 bf, size, width);
399}
400
401static int64_t
402sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
403{
404 struct addr_map_symbol *from_l = &left->branch_info->from;
405 struct addr_map_symbol *from_r = &right->branch_info->from;
406
407 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900408 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409
Namhyung Kim51f27d12013-02-06 14:57:15 +0900410 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411}
412
413static int64_t
414sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
415{
416 struct addr_map_symbol *to_l = &left->branch_info->to;
417 struct addr_map_symbol *to_r = &right->branch_info->to;
418
419 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900420 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421
Namhyung Kim51f27d12013-02-06 14:57:15 +0900422 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100423}
424
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300425static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900426 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300428 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300430 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100431
432}
433
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300434static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900435 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100436{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300437 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100438 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300439 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100440
441}
442
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900443struct sort_entry sort_dso_from = {
444 .se_header = "Source Shared Object",
445 .se_cmp = sort__dso_from_cmp,
446 .se_snprintf = hist_entry__dso_from_snprintf,
447 .se_width_idx = HISTC_DSO_FROM,
448};
449
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450struct sort_entry sort_dso_to = {
451 .se_header = "Target Shared Object",
452 .se_cmp = sort__dso_to_cmp,
453 .se_snprintf = hist_entry__dso_to_snprintf,
454 .se_width_idx = HISTC_DSO_TO,
455};
456
457struct sort_entry sort_sym_from = {
458 .se_header = "Source Symbol",
459 .se_cmp = sort__sym_from_cmp,
460 .se_snprintf = hist_entry__sym_from_snprintf,
461 .se_width_idx = HISTC_SYMBOL_FROM,
462};
463
464struct sort_entry sort_sym_to = {
465 .se_header = "Target Symbol",
466 .se_cmp = sort__sym_to_cmp,
467 .se_snprintf = hist_entry__sym_to_snprintf,
468 .se_width_idx = HISTC_SYMBOL_TO,
469};
470
471static int64_t
472sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
473{
474 const unsigned char mp = left->branch_info->flags.mispred !=
475 right->branch_info->flags.mispred;
476 const unsigned char p = left->branch_info->flags.predicted !=
477 right->branch_info->flags.predicted;
478
479 return mp || p;
480}
481
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300482static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100483 size_t size, unsigned int width){
484 static const char *out = "N/A";
485
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300486 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100487 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300488 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100489 out = "Y";
490
Namhyung Kim5b591662014-07-31 14:47:38 +0900491 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100492}
493
Stephane Eranian98a3b322013-01-24 16:10:35 +0100494/* --sort daddr_sym */
495static int64_t
496sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
497{
498 uint64_t l = 0, r = 0;
499
500 if (left->mem_info)
501 l = left->mem_info->daddr.addr;
502 if (right->mem_info)
503 r = right->mem_info->daddr.addr;
504
505 return (int64_t)(r - l);
506}
507
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300508static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100509 size_t size, unsigned int width)
510{
511 uint64_t addr = 0;
512 struct map *map = NULL;
513 struct symbol *sym = NULL;
514
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300515 if (he->mem_info) {
516 addr = he->mem_info->daddr.addr;
517 map = he->mem_info->daddr.map;
518 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100519 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300520 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100521 width);
522}
523
524static int64_t
525sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
526{
527 struct map *map_l = NULL;
528 struct map *map_r = NULL;
529
530 if (left->mem_info)
531 map_l = left->mem_info->daddr.map;
532 if (right->mem_info)
533 map_r = right->mem_info->daddr.map;
534
535 return _sort__dso_cmp(map_l, map_r);
536}
537
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300538static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100539 size_t size, unsigned int width)
540{
541 struct map *map = NULL;
542
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543 if (he->mem_info)
544 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100545
546 return _hist_entry__dso_snprintf(map, bf, size, width);
547}
548
549static int64_t
550sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
551{
552 union perf_mem_data_src data_src_l;
553 union perf_mem_data_src data_src_r;
554
555 if (left->mem_info)
556 data_src_l = left->mem_info->data_src;
557 else
558 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
559
560 if (right->mem_info)
561 data_src_r = right->mem_info->data_src;
562 else
563 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
564
565 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
566}
567
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300568static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100569 size_t size, unsigned int width)
570{
571 const char *out;
572 u64 mask = PERF_MEM_LOCK_NA;
573
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300574 if (he->mem_info)
575 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100576
577 if (mask & PERF_MEM_LOCK_NA)
578 out = "N/A";
579 else if (mask & PERF_MEM_LOCK_LOCKED)
580 out = "Yes";
581 else
582 out = "No";
583
584 return repsep_snprintf(bf, size, "%-*s", width, out);
585}
586
587static int64_t
588sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
589{
590 union perf_mem_data_src data_src_l;
591 union perf_mem_data_src data_src_r;
592
593 if (left->mem_info)
594 data_src_l = left->mem_info->data_src;
595 else
596 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
597
598 if (right->mem_info)
599 data_src_r = right->mem_info->data_src;
600 else
601 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
602
603 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
604}
605
606static const char * const tlb_access[] = {
607 "N/A",
608 "HIT",
609 "MISS",
610 "L1",
611 "L2",
612 "Walker",
613 "Fault",
614};
615#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
616
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300617static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100618 size_t size, unsigned int width)
619{
620 char out[64];
621 size_t sz = sizeof(out) - 1; /* -1 for null termination */
622 size_t l = 0, i;
623 u64 m = PERF_MEM_TLB_NA;
624 u64 hit, miss;
625
626 out[0] = '\0';
627
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300628 if (he->mem_info)
629 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100630
631 hit = m & PERF_MEM_TLB_HIT;
632 miss = m & PERF_MEM_TLB_MISS;
633
634 /* already taken care of */
635 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
636
637 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
638 if (!(m & 0x1))
639 continue;
640 if (l) {
641 strcat(out, " or ");
642 l += 4;
643 }
644 strncat(out, tlb_access[i], sz - l);
645 l += strlen(tlb_access[i]);
646 }
647 if (*out == '\0')
648 strcpy(out, "N/A");
649 if (hit)
650 strncat(out, " hit", sz - l);
651 if (miss)
652 strncat(out, " miss", sz - l);
653
654 return repsep_snprintf(bf, size, "%-*s", width, out);
655}
656
657static int64_t
658sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
659{
660 union perf_mem_data_src data_src_l;
661 union perf_mem_data_src data_src_r;
662
663 if (left->mem_info)
664 data_src_l = left->mem_info->data_src;
665 else
666 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
667
668 if (right->mem_info)
669 data_src_r = right->mem_info->data_src;
670 else
671 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
672
673 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
674}
675
676static const char * const mem_lvl[] = {
677 "N/A",
678 "HIT",
679 "MISS",
680 "L1",
681 "LFB",
682 "L2",
683 "L3",
684 "Local RAM",
685 "Remote RAM (1 hop)",
686 "Remote RAM (2 hops)",
687 "Remote Cache (1 hop)",
688 "Remote Cache (2 hops)",
689 "I/O",
690 "Uncached",
691};
692#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
693
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300694static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100695 size_t size, unsigned int width)
696{
697 char out[64];
698 size_t sz = sizeof(out) - 1; /* -1 for null termination */
699 size_t i, l = 0;
700 u64 m = PERF_MEM_LVL_NA;
701 u64 hit, miss;
702
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300703 if (he->mem_info)
704 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100705
706 out[0] = '\0';
707
708 hit = m & PERF_MEM_LVL_HIT;
709 miss = m & PERF_MEM_LVL_MISS;
710
711 /* already taken care of */
712 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
713
714 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
715 if (!(m & 0x1))
716 continue;
717 if (l) {
718 strcat(out, " or ");
719 l += 4;
720 }
721 strncat(out, mem_lvl[i], sz - l);
722 l += strlen(mem_lvl[i]);
723 }
724 if (*out == '\0')
725 strcpy(out, "N/A");
726 if (hit)
727 strncat(out, " hit", sz - l);
728 if (miss)
729 strncat(out, " miss", sz - l);
730
731 return repsep_snprintf(bf, size, "%-*s", width, out);
732}
733
734static int64_t
735sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
736{
737 union perf_mem_data_src data_src_l;
738 union perf_mem_data_src data_src_r;
739
740 if (left->mem_info)
741 data_src_l = left->mem_info->data_src;
742 else
743 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
744
745 if (right->mem_info)
746 data_src_r = right->mem_info->data_src;
747 else
748 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
749
750 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
751}
752
753static const char * const snoop_access[] = {
754 "N/A",
755 "None",
756 "Miss",
757 "Hit",
758 "HitM",
759};
760#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
761
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300762static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100763 size_t size, unsigned int width)
764{
765 char out[64];
766 size_t sz = sizeof(out) - 1; /* -1 for null termination */
767 size_t i, l = 0;
768 u64 m = PERF_MEM_SNOOP_NA;
769
770 out[0] = '\0';
771
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300772 if (he->mem_info)
773 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100774
775 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
776 if (!(m & 0x1))
777 continue;
778 if (l) {
779 strcat(out, " or ");
780 l += 4;
781 }
782 strncat(out, snoop_access[i], sz - l);
783 l += strlen(snoop_access[i]);
784 }
785
786 if (*out == '\0')
787 strcpy(out, "N/A");
788
789 return repsep_snprintf(bf, size, "%-*s", width, out);
790}
791
Don Zickus9b32ba72014-06-01 15:38:29 +0200792static inline u64 cl_address(u64 address)
793{
794 /* return the cacheline of the address */
795 return (address & ~(cacheline_size - 1));
796}
797
798static int64_t
799sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
800{
801 u64 l, r;
802 struct map *l_map, *r_map;
803
804 if (!left->mem_info) return -1;
805 if (!right->mem_info) return 1;
806
807 /* group event types together */
808 if (left->cpumode > right->cpumode) return -1;
809 if (left->cpumode < right->cpumode) return 1;
810
811 l_map = left->mem_info->daddr.map;
812 r_map = right->mem_info->daddr.map;
813
814 /* if both are NULL, jump to sort on al_addr instead */
815 if (!l_map && !r_map)
816 goto addr;
817
818 if (!l_map) return -1;
819 if (!r_map) return 1;
820
821 if (l_map->maj > r_map->maj) return -1;
822 if (l_map->maj < r_map->maj) return 1;
823
824 if (l_map->min > r_map->min) return -1;
825 if (l_map->min < r_map->min) return 1;
826
827 if (l_map->ino > r_map->ino) return -1;
828 if (l_map->ino < r_map->ino) return 1;
829
830 if (l_map->ino_generation > r_map->ino_generation) return -1;
831 if (l_map->ino_generation < r_map->ino_generation) return 1;
832
833 /*
834 * Addresses with no major/minor numbers are assumed to be
835 * anonymous in userspace. Sort those on pid then address.
836 *
837 * The kernel and non-zero major/minor mapped areas are
838 * assumed to be unity mapped. Sort those on address.
839 */
840
841 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
842 (!(l_map->flags & MAP_SHARED)) &&
843 !l_map->maj && !l_map->min && !l_map->ino &&
844 !l_map->ino_generation) {
845 /* userspace anonymous */
846
847 if (left->thread->pid_ > right->thread->pid_) return -1;
848 if (left->thread->pid_ < right->thread->pid_) return 1;
849 }
850
851addr:
852 /* al_addr does all the right addr - start + offset calculations */
853 l = cl_address(left->mem_info->daddr.al_addr);
854 r = cl_address(right->mem_info->daddr.al_addr);
855
856 if (l > r) return -1;
857 if (l < r) return 1;
858
859 return 0;
860}
861
862static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
863 size_t size, unsigned int width)
864{
865
866 uint64_t addr = 0;
867 struct map *map = NULL;
868 struct symbol *sym = NULL;
869 char level = he->level;
870
871 if (he->mem_info) {
872 addr = cl_address(he->mem_info->daddr.al_addr);
873 map = he->mem_info->daddr.map;
874 sym = he->mem_info->daddr.sym;
875
876 /* print [s] for shared data mmaps */
877 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
878 map && (map->type == MAP__VARIABLE) &&
879 (map->flags & MAP_SHARED) &&
880 (map->maj || map->min || map->ino ||
881 map->ino_generation))
882 level = 's';
883 else if (!map)
884 level = 'X';
885 }
886 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
887 width);
888}
889
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100890struct sort_entry sort_mispredict = {
891 .se_header = "Branch Mispredicted",
892 .se_cmp = sort__mispredict_cmp,
893 .se_snprintf = hist_entry__mispredict_snprintf,
894 .se_width_idx = HISTC_MISPREDICT,
895};
896
Andi Kleen05484292013-01-24 16:10:29 +0100897static u64 he_weight(struct hist_entry *he)
898{
899 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
900}
901
902static int64_t
903sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
904{
905 return he_weight(left) - he_weight(right);
906}
907
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300908static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100909 size_t size, unsigned int width)
910{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300911 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100912}
913
914struct sort_entry sort_local_weight = {
915 .se_header = "Local Weight",
916 .se_cmp = sort__local_weight_cmp,
917 .se_snprintf = hist_entry__local_weight_snprintf,
918 .se_width_idx = HISTC_LOCAL_WEIGHT,
919};
920
921static int64_t
922sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
923{
924 return left->stat.weight - right->stat.weight;
925}
926
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300927static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100928 size_t size, unsigned int width)
929{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300930 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100931}
932
933struct sort_entry sort_global_weight = {
934 .se_header = "Weight",
935 .se_cmp = sort__global_weight_cmp,
936 .se_snprintf = hist_entry__global_weight_snprintf,
937 .se_width_idx = HISTC_GLOBAL_WEIGHT,
938};
939
Stephane Eranian98a3b322013-01-24 16:10:35 +0100940struct sort_entry sort_mem_daddr_sym = {
941 .se_header = "Data Symbol",
942 .se_cmp = sort__daddr_cmp,
943 .se_snprintf = hist_entry__daddr_snprintf,
944 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
945};
946
947struct sort_entry sort_mem_daddr_dso = {
948 .se_header = "Data Object",
949 .se_cmp = sort__dso_daddr_cmp,
950 .se_snprintf = hist_entry__dso_daddr_snprintf,
951 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
952};
953
954struct sort_entry sort_mem_locked = {
955 .se_header = "Locked",
956 .se_cmp = sort__locked_cmp,
957 .se_snprintf = hist_entry__locked_snprintf,
958 .se_width_idx = HISTC_MEM_LOCKED,
959};
960
961struct sort_entry sort_mem_tlb = {
962 .se_header = "TLB access",
963 .se_cmp = sort__tlb_cmp,
964 .se_snprintf = hist_entry__tlb_snprintf,
965 .se_width_idx = HISTC_MEM_TLB,
966};
967
968struct sort_entry sort_mem_lvl = {
969 .se_header = "Memory access",
970 .se_cmp = sort__lvl_cmp,
971 .se_snprintf = hist_entry__lvl_snprintf,
972 .se_width_idx = HISTC_MEM_LVL,
973};
974
975struct sort_entry sort_mem_snoop = {
976 .se_header = "Snoop",
977 .se_cmp = sort__snoop_cmp,
978 .se_snprintf = hist_entry__snoop_snprintf,
979 .se_width_idx = HISTC_MEM_SNOOP,
980};
981
Don Zickus9b32ba72014-06-01 15:38:29 +0200982struct sort_entry sort_mem_dcacheline = {
983 .se_header = "Data Cacheline",
984 .se_cmp = sort__dcacheline_cmp,
985 .se_snprintf = hist_entry__dcacheline_snprintf,
986 .se_width_idx = HISTC_MEM_DCACHELINE,
987};
988
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700989static int64_t
990sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
991{
992 return left->branch_info->flags.abort !=
993 right->branch_info->flags.abort;
994}
995
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300996static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700997 size_t size, unsigned int width)
998{
999 static const char *out = ".";
1000
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001001 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001002 out = "A";
1003 return repsep_snprintf(bf, size, "%-*s", width, out);
1004}
1005
1006struct sort_entry sort_abort = {
1007 .se_header = "Transaction abort",
1008 .se_cmp = sort__abort_cmp,
1009 .se_snprintf = hist_entry__abort_snprintf,
1010 .se_width_idx = HISTC_ABORT,
1011};
1012
1013static int64_t
1014sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1015{
1016 return left->branch_info->flags.in_tx !=
1017 right->branch_info->flags.in_tx;
1018}
1019
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001020static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001021 size_t size, unsigned int width)
1022{
1023 static const char *out = ".";
1024
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001025 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001026 out = "T";
1027
1028 return repsep_snprintf(bf, size, "%-*s", width, out);
1029}
1030
1031struct sort_entry sort_in_tx = {
1032 .se_header = "Branch in transaction",
1033 .se_cmp = sort__in_tx_cmp,
1034 .se_snprintf = hist_entry__in_tx_snprintf,
1035 .se_width_idx = HISTC_IN_TX,
1036};
1037
Andi Kleen475eeab2013-09-20 07:40:43 -07001038static int64_t
1039sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1040{
1041 return left->transaction - right->transaction;
1042}
1043
1044static inline char *add_str(char *p, const char *str)
1045{
1046 strcpy(p, str);
1047 return p + strlen(str);
1048}
1049
1050static struct txbit {
1051 unsigned flag;
1052 const char *name;
1053 int skip_for_len;
1054} txbits[] = {
1055 { PERF_TXN_ELISION, "EL ", 0 },
1056 { PERF_TXN_TRANSACTION, "TX ", 1 },
1057 { PERF_TXN_SYNC, "SYNC ", 1 },
1058 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1059 { PERF_TXN_RETRY, "RETRY ", 0 },
1060 { PERF_TXN_CONFLICT, "CON ", 0 },
1061 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1062 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1063 { 0, NULL, 0 }
1064};
1065
1066int hist_entry__transaction_len(void)
1067{
1068 int i;
1069 int len = 0;
1070
1071 for (i = 0; txbits[i].name; i++) {
1072 if (!txbits[i].skip_for_len)
1073 len += strlen(txbits[i].name);
1074 }
1075 len += 4; /* :XX<space> */
1076 return len;
1077}
1078
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001079static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001080 size_t size, unsigned int width)
1081{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001082 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001083 char buf[128];
1084 char *p = buf;
1085 int i;
1086
1087 buf[0] = 0;
1088 for (i = 0; txbits[i].name; i++)
1089 if (txbits[i].flag & t)
1090 p = add_str(p, txbits[i].name);
1091 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1092 p = add_str(p, "NEITHER ");
1093 if (t & PERF_TXN_ABORT_MASK) {
1094 sprintf(p, ":%" PRIx64,
1095 (t & PERF_TXN_ABORT_MASK) >>
1096 PERF_TXN_ABORT_SHIFT);
1097 p += strlen(p);
1098 }
1099
1100 return repsep_snprintf(bf, size, "%-*s", width, buf);
1101}
1102
1103struct sort_entry sort_transaction = {
1104 .se_header = "Transaction ",
1105 .se_cmp = sort__transaction_cmp,
1106 .se_snprintf = hist_entry__transaction_snprintf,
1107 .se_width_idx = HISTC_TRANSACTION,
1108};
1109
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001110struct sort_dimension {
1111 const char *name;
1112 struct sort_entry *entry;
1113 int taken;
1114};
1115
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001116#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1117
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001118static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001119 DIM(SORT_PID, "pid", sort_thread),
1120 DIM(SORT_COMM, "comm", sort_comm),
1121 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001122 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001123 DIM(SORT_PARENT, "parent", sort_parent),
1124 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001125 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001126 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1127 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001128 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001129};
1130
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001131#undef DIM
1132
1133#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1134
1135static struct sort_dimension bstack_sort_dimensions[] = {
1136 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1137 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1138 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1139 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1140 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001141 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1142 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001143};
1144
1145#undef DIM
1146
Namhyung Kimafab87b2013-04-03 21:26:11 +09001147#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1148
1149static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001150 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1151 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1152 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1153 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1154 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1155 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001156 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001157};
1158
1159#undef DIM
1160
Namhyung Kima2ce0672014-03-04 09:06:42 +09001161struct hpp_dimension {
1162 const char *name;
1163 struct perf_hpp_fmt *fmt;
1164 int taken;
1165};
1166
1167#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1168
1169static struct hpp_dimension hpp_sort_dimensions[] = {
1170 DIM(PERF_HPP__OVERHEAD, "overhead"),
1171 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1172 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1173 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1174 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001175 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001176 DIM(PERF_HPP__SAMPLES, "sample"),
1177 DIM(PERF_HPP__PERIOD, "period"),
1178};
1179
1180#undef DIM
1181
Namhyung Kim8b536992014-03-03 11:46:55 +09001182struct hpp_sort_entry {
1183 struct perf_hpp_fmt hpp;
1184 struct sort_entry *se;
1185};
1186
Namhyung Kima7d945b2014-03-04 10:46:34 +09001187bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1188{
1189 struct hpp_sort_entry *hse_a;
1190 struct hpp_sort_entry *hse_b;
1191
1192 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1193 return false;
1194
1195 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1196 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1197
1198 return hse_a->se == hse_b->se;
1199}
1200
Namhyung Kime0d66c72014-07-31 14:47:37 +09001201void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001202{
1203 struct hpp_sort_entry *hse;
1204
1205 if (!perf_hpp__is_sort_entry(fmt))
1206 return;
1207
1208 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001209 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001210}
1211
Namhyung Kim8b536992014-03-03 11:46:55 +09001212static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1213 struct perf_evsel *evsel)
1214{
1215 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001216 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001217
1218 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001219
Namhyung Kim5b591662014-07-31 14:47:38 +09001220 if (!len)
1221 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1222
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001223 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001224}
1225
1226static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1227 struct perf_hpp *hpp __maybe_unused,
1228 struct perf_evsel *evsel)
1229{
1230 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001231 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001232
1233 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1234
Namhyung Kim5b591662014-07-31 14:47:38 +09001235 if (!len)
1236 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1237
1238 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001239}
1240
1241static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1242 struct hist_entry *he)
1243{
1244 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001245 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001246
1247 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001248
1249 if (!len)
1250 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001251
1252 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1253}
1254
Namhyung Kima7d945b2014-03-04 10:46:34 +09001255static struct hpp_sort_entry *
1256__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001257{
1258 struct hpp_sort_entry *hse;
1259
1260 hse = malloc(sizeof(*hse));
1261 if (hse == NULL) {
1262 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001263 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001264 }
1265
1266 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001267 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001268 hse->hpp.header = __sort__hpp_header;
1269 hse->hpp.width = __sort__hpp_width;
1270 hse->hpp.entry = __sort__hpp_entry;
1271 hse->hpp.color = NULL;
1272
1273 hse->hpp.cmp = sd->entry->se_cmp;
1274 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001275 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001276
1277 INIT_LIST_HEAD(&hse->hpp.list);
1278 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001279 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001280 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001281 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001282
Namhyung Kima7d945b2014-03-04 10:46:34 +09001283 return hse;
1284}
1285
1286bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1287{
1288 return format->header == __sort__hpp_header;
1289}
1290
1291static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1292{
1293 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1294
1295 if (hse == NULL)
1296 return -1;
1297
Namhyung Kim8b536992014-03-03 11:46:55 +09001298 perf_hpp__register_sort_field(&hse->hpp);
1299 return 0;
1300}
1301
Namhyung Kima7d945b2014-03-04 10:46:34 +09001302static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1303{
1304 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1305
1306 if (hse == NULL)
1307 return -1;
1308
1309 perf_hpp__column_register(&hse->hpp);
1310 return 0;
1311}
1312
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001313static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001314{
1315 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001316 return 0;
1317
Namhyung Kima7d945b2014-03-04 10:46:34 +09001318 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001319 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001320
1321 if (sd->entry->se_collapse)
1322 sort__need_collapse = 1;
1323
Namhyung Kim2f532d092013-04-03 21:26:10 +09001324 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001325
1326 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001327}
1328
Namhyung Kima2ce0672014-03-04 09:06:42 +09001329static int __hpp_dimension__add(struct hpp_dimension *hd)
1330{
1331 if (!hd->taken) {
1332 hd->taken = 1;
1333
1334 perf_hpp__register_sort_field(hd->fmt);
1335 }
1336 return 0;
1337}
1338
Namhyung Kima7d945b2014-03-04 10:46:34 +09001339static int __sort_dimension__add_output(struct sort_dimension *sd)
1340{
1341 if (sd->taken)
1342 return 0;
1343
1344 if (__sort_dimension__add_hpp_output(sd) < 0)
1345 return -1;
1346
1347 sd->taken = 1;
1348 return 0;
1349}
1350
1351static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1352{
1353 if (!hd->taken) {
1354 hd->taken = 1;
1355
1356 perf_hpp__column_register(hd->fmt);
1357 }
1358 return 0;
1359}
1360
John Kacurdd68ada2009-09-24 18:02:49 +02001361int sort_dimension__add(const char *tok)
1362{
1363 unsigned int i;
1364
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001365 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1366 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001367
John Kacurdd68ada2009-09-24 18:02:49 +02001368 if (strncasecmp(tok, sd->name, strlen(tok)))
1369 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001370
John Kacurdd68ada2009-09-24 18:02:49 +02001371 if (sd->entry == &sort_parent) {
1372 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1373 if (ret) {
1374 char err[BUFSIZ];
1375
1376 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001377 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1378 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001379 }
1380 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001381 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001382 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001383 } else if (sd->entry == &sort_dso) {
1384 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001385 }
1386
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001387 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001388 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001389
Namhyung Kima2ce0672014-03-04 09:06:42 +09001390 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1391 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1392
1393 if (strncasecmp(tok, hd->name, strlen(tok)))
1394 continue;
1395
1396 return __hpp_dimension__add(hd);
1397 }
1398
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001399 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1400 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1401
1402 if (strncasecmp(tok, sd->name, strlen(tok)))
1403 continue;
1404
Namhyung Kim55369fc2013-04-01 20:35:20 +09001405 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001406 return -EINVAL;
1407
1408 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1409 sort__has_sym = 1;
1410
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001411 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001412 return 0;
1413 }
1414
Namhyung Kimafab87b2013-04-03 21:26:11 +09001415 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1416 struct sort_dimension *sd = &memory_sort_dimensions[i];
1417
1418 if (strncasecmp(tok, sd->name, strlen(tok)))
1419 continue;
1420
1421 if (sort__mode != SORT_MODE__MEMORY)
1422 return -EINVAL;
1423
1424 if (sd->entry == &sort_mem_daddr_sym)
1425 sort__has_sym = 1;
1426
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001427 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001428 return 0;
1429 }
1430
John Kacurdd68ada2009-09-24 18:02:49 +02001431 return -ESRCH;
1432}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001433
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001434static const char *get_default_sort_order(void)
1435{
1436 const char *default_sort_orders[] = {
1437 default_sort_order,
1438 default_branch_sort_order,
1439 default_mem_sort_order,
1440 default_top_sort_order,
1441 default_diff_sort_order,
1442 };
1443
1444 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1445
1446 return default_sort_orders[sort__mode];
1447}
1448
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001449static int setup_sort_order(void)
1450{
1451 char *new_sort_order;
1452
1453 /*
1454 * Append '+'-prefixed sort order to the default sort
1455 * order string.
1456 */
1457 if (!sort_order || is_strict_order(sort_order))
1458 return 0;
1459
1460 if (sort_order[1] == '\0') {
1461 error("Invalid --sort key: `+'");
1462 return -EINVAL;
1463 }
1464
1465 /*
1466 * We allocate new sort_order string, but we never free it,
1467 * because it's checked over the rest of the code.
1468 */
1469 if (asprintf(&new_sort_order, "%s,%s",
1470 get_default_sort_order(), sort_order + 1) < 0) {
1471 error("Not enough memory to set up --sort");
1472 return -ENOMEM;
1473 }
1474
1475 sort_order = new_sort_order;
1476 return 0;
1477}
1478
Namhyung Kima7d945b2014-03-04 10:46:34 +09001479static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001480{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001481 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001482 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001483 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001484
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001485 ret = setup_sort_order();
1486 if (ret)
1487 return ret;
1488
1489 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001490 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001491 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001492 /*
1493 * If user specified field order but no sort order,
1494 * we'll honor it and not add default sort orders.
1495 */
1496 return 0;
1497 }
1498
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001499 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001500 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001501
1502 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001503 if (str == NULL) {
1504 error("Not enough memory to setup sort keys");
1505 return -ENOMEM;
1506 }
1507
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001508 for (tok = strtok_r(str, ", ", &tmp);
1509 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001510 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001511 if (ret == -EINVAL) {
1512 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001513 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001514 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001515 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001516 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001517 }
1518 }
1519
1520 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001521 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001522}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001523
Jiri Olsaf2998422014-05-23 17:15:47 +02001524void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001525{
Jiri Olsaf2998422014-05-23 17:15:47 +02001526 struct perf_hpp_fmt *fmt;
1527 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001528
Jiri Olsaf2998422014-05-23 17:15:47 +02001529 perf_hpp__for_each_format(fmt) {
1530 if (!perf_hpp__is_sort_entry(fmt))
1531 continue;
1532
1533 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1534 if (hse->se->se_width_idx == idx) {
1535 fmt->elide = elide;
1536 break;
1537 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001538 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001539}
1540
Jiri Olsaf2998422014-05-23 17:15:47 +02001541static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001542{
1543 if (list && strlist__nr_entries(list) == 1) {
1544 if (fp != NULL)
1545 fprintf(fp, "# %s: %s\n", list_name,
1546 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001547 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001548 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001549 return false;
1550}
1551
1552static bool get_elide(int idx, FILE *output)
1553{
1554 switch (idx) {
1555 case HISTC_SYMBOL:
1556 return __get_elide(symbol_conf.sym_list, "symbol", output);
1557 case HISTC_DSO:
1558 return __get_elide(symbol_conf.dso_list, "dso", output);
1559 case HISTC_COMM:
1560 return __get_elide(symbol_conf.comm_list, "comm", output);
1561 default:
1562 break;
1563 }
1564
1565 if (sort__mode != SORT_MODE__BRANCH)
1566 return false;
1567
1568 switch (idx) {
1569 case HISTC_SYMBOL_FROM:
1570 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1571 case HISTC_SYMBOL_TO:
1572 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1573 case HISTC_DSO_FROM:
1574 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1575 case HISTC_DSO_TO:
1576 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1577 default:
1578 break;
1579 }
1580
1581 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001582}
Namhyung Kim08e71542013-04-03 21:26:19 +09001583
1584void sort__setup_elide(FILE *output)
1585{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001586 struct perf_hpp_fmt *fmt;
1587 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001588
Jiri Olsaf2998422014-05-23 17:15:47 +02001589 perf_hpp__for_each_format(fmt) {
1590 if (!perf_hpp__is_sort_entry(fmt))
1591 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001592
Jiri Olsaf2998422014-05-23 17:15:47 +02001593 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1594 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001595 }
1596
Namhyung Kim7524f632013-11-08 17:53:42 +09001597 /*
1598 * It makes no sense to elide all of sort entries.
1599 * Just revert them to show up again.
1600 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001601 perf_hpp__for_each_format(fmt) {
1602 if (!perf_hpp__is_sort_entry(fmt))
1603 continue;
1604
Jiri Olsaf2998422014-05-23 17:15:47 +02001605 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001606 return;
1607 }
1608
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001609 perf_hpp__for_each_format(fmt) {
1610 if (!perf_hpp__is_sort_entry(fmt))
1611 continue;
1612
Jiri Olsaf2998422014-05-23 17:15:47 +02001613 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001614 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001615}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001616
1617static int output_field_add(char *tok)
1618{
1619 unsigned int i;
1620
1621 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1622 struct sort_dimension *sd = &common_sort_dimensions[i];
1623
1624 if (strncasecmp(tok, sd->name, strlen(tok)))
1625 continue;
1626
1627 return __sort_dimension__add_output(sd);
1628 }
1629
1630 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1631 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1632
1633 if (strncasecmp(tok, hd->name, strlen(tok)))
1634 continue;
1635
1636 return __hpp_dimension__add_output(hd);
1637 }
1638
1639 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1640 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1641
1642 if (strncasecmp(tok, sd->name, strlen(tok)))
1643 continue;
1644
1645 return __sort_dimension__add_output(sd);
1646 }
1647
1648 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1649 struct sort_dimension *sd = &memory_sort_dimensions[i];
1650
1651 if (strncasecmp(tok, sd->name, strlen(tok)))
1652 continue;
1653
1654 return __sort_dimension__add_output(sd);
1655 }
1656
1657 return -ESRCH;
1658}
1659
1660static void reset_dimensions(void)
1661{
1662 unsigned int i;
1663
1664 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1665 common_sort_dimensions[i].taken = 0;
1666
1667 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1668 hpp_sort_dimensions[i].taken = 0;
1669
1670 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1671 bstack_sort_dimensions[i].taken = 0;
1672
1673 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1674 memory_sort_dimensions[i].taken = 0;
1675}
1676
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001677bool is_strict_order(const char *order)
1678{
1679 return order && (*order != '+');
1680}
1681
Namhyung Kima7d945b2014-03-04 10:46:34 +09001682static int __setup_output_field(void)
1683{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001684 char *tmp, *tok, *str, *strp;
1685 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001686
1687 if (field_order == NULL)
1688 return 0;
1689
1690 reset_dimensions();
1691
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001692 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001693 if (str == NULL) {
1694 error("Not enough memory to setup output fields");
1695 return -ENOMEM;
1696 }
1697
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001698 if (!is_strict_order(field_order))
1699 strp++;
1700
1701 if (!strlen(strp)) {
1702 error("Invalid --fields key: `+'");
1703 goto out;
1704 }
1705
1706 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001707 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1708 ret = output_field_add(tok);
1709 if (ret == -EINVAL) {
1710 error("Invalid --fields key: `%s'", tok);
1711 break;
1712 } else if (ret == -ESRCH) {
1713 error("Unknown --fields key: `%s'", tok);
1714 break;
1715 }
1716 }
1717
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001718out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001719 free(str);
1720 return ret;
1721}
1722
1723int setup_sorting(void)
1724{
1725 int err;
1726
1727 err = __setup_sorting();
1728 if (err < 0)
1729 return err;
1730
1731 if (parent_pattern != default_parent_pattern) {
1732 err = sort_dimension__add("parent");
1733 if (err < 0)
1734 return err;
1735 }
1736
1737 reset_dimensions();
1738
1739 /*
1740 * perf diff doesn't use default hpp output fields.
1741 */
1742 if (sort__mode != SORT_MODE__DIFF)
1743 perf_hpp__init();
1744
1745 err = __setup_output_field();
1746 if (err < 0)
1747 return err;
1748
1749 /* copy sort keys to output fields */
1750 perf_hpp__setup_output_field();
1751 /* and then copy output fields to sort keys */
1752 perf_hpp__append_sort_keys();
1753
1754 return 0;
1755}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001756
1757void reset_output_field(void)
1758{
1759 sort__need_collapse = 0;
1760 sort__has_parent = 0;
1761 sort__has_sym = 0;
1762 sort__has_dso = 0;
1763
Namhyung Kimd69b2962014-05-23 10:59:01 +09001764 field_order = NULL;
1765 sort_order = NULL;
1766
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001767 reset_dimensions();
1768 perf_hpp__reset_output_field();
1769}