blob: 82241fe54e4bdb396ad6f9fc501ffd4ca769daac [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{
Jiri Olsa49f47442014-10-16 16:07:01 +0200992 if (!left->branch_info || !right->branch_info)
993 return cmp_null(left->branch_info, right->branch_info);
994
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700995 return left->branch_info->flags.abort !=
996 right->branch_info->flags.abort;
997}
998
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300999static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001000 size_t size, unsigned int width)
1001{
Jiri Olsa49f47442014-10-16 16:07:01 +02001002 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001003
Jiri Olsa49f47442014-10-16 16:07:01 +02001004 if (he->branch_info) {
1005 if (he->branch_info->flags.abort)
1006 out = "A";
1007 else
1008 out = ".";
1009 }
1010
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001011 return repsep_snprintf(bf, size, "%-*s", width, out);
1012}
1013
1014struct sort_entry sort_abort = {
1015 .se_header = "Transaction abort",
1016 .se_cmp = sort__abort_cmp,
1017 .se_snprintf = hist_entry__abort_snprintf,
1018 .se_width_idx = HISTC_ABORT,
1019};
1020
1021static int64_t
1022sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1023{
1024 return left->branch_info->flags.in_tx !=
1025 right->branch_info->flags.in_tx;
1026}
1027
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001028static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001029 size_t size, unsigned int width)
1030{
1031 static const char *out = ".";
1032
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001033 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001034 out = "T";
1035
1036 return repsep_snprintf(bf, size, "%-*s", width, out);
1037}
1038
1039struct sort_entry sort_in_tx = {
1040 .se_header = "Branch in transaction",
1041 .se_cmp = sort__in_tx_cmp,
1042 .se_snprintf = hist_entry__in_tx_snprintf,
1043 .se_width_idx = HISTC_IN_TX,
1044};
1045
Andi Kleen475eeab2013-09-20 07:40:43 -07001046static int64_t
1047sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1048{
1049 return left->transaction - right->transaction;
1050}
1051
1052static inline char *add_str(char *p, const char *str)
1053{
1054 strcpy(p, str);
1055 return p + strlen(str);
1056}
1057
1058static struct txbit {
1059 unsigned flag;
1060 const char *name;
1061 int skip_for_len;
1062} txbits[] = {
1063 { PERF_TXN_ELISION, "EL ", 0 },
1064 { PERF_TXN_TRANSACTION, "TX ", 1 },
1065 { PERF_TXN_SYNC, "SYNC ", 1 },
1066 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1067 { PERF_TXN_RETRY, "RETRY ", 0 },
1068 { PERF_TXN_CONFLICT, "CON ", 0 },
1069 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1070 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1071 { 0, NULL, 0 }
1072};
1073
1074int hist_entry__transaction_len(void)
1075{
1076 int i;
1077 int len = 0;
1078
1079 for (i = 0; txbits[i].name; i++) {
1080 if (!txbits[i].skip_for_len)
1081 len += strlen(txbits[i].name);
1082 }
1083 len += 4; /* :XX<space> */
1084 return len;
1085}
1086
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001087static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001088 size_t size, unsigned int width)
1089{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001090 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001091 char buf[128];
1092 char *p = buf;
1093 int i;
1094
1095 buf[0] = 0;
1096 for (i = 0; txbits[i].name; i++)
1097 if (txbits[i].flag & t)
1098 p = add_str(p, txbits[i].name);
1099 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1100 p = add_str(p, "NEITHER ");
1101 if (t & PERF_TXN_ABORT_MASK) {
1102 sprintf(p, ":%" PRIx64,
1103 (t & PERF_TXN_ABORT_MASK) >>
1104 PERF_TXN_ABORT_SHIFT);
1105 p += strlen(p);
1106 }
1107
1108 return repsep_snprintf(bf, size, "%-*s", width, buf);
1109}
1110
1111struct sort_entry sort_transaction = {
1112 .se_header = "Transaction ",
1113 .se_cmp = sort__transaction_cmp,
1114 .se_snprintf = hist_entry__transaction_snprintf,
1115 .se_width_idx = HISTC_TRANSACTION,
1116};
1117
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001118struct sort_dimension {
1119 const char *name;
1120 struct sort_entry *entry;
1121 int taken;
1122};
1123
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001124#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1125
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001126static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001127 DIM(SORT_PID, "pid", sort_thread),
1128 DIM(SORT_COMM, "comm", sort_comm),
1129 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001130 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001131 DIM(SORT_PARENT, "parent", sort_parent),
1132 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001133 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001134 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1135 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001136 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001137};
1138
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001139#undef DIM
1140
1141#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1142
1143static struct sort_dimension bstack_sort_dimensions[] = {
1144 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1145 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1146 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1147 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1148 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001149 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1150 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001151};
1152
1153#undef DIM
1154
Namhyung Kimafab87b2013-04-03 21:26:11 +09001155#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1156
1157static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001158 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1159 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1160 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1161 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1162 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1163 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001164 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001165};
1166
1167#undef DIM
1168
Namhyung Kima2ce0672014-03-04 09:06:42 +09001169struct hpp_dimension {
1170 const char *name;
1171 struct perf_hpp_fmt *fmt;
1172 int taken;
1173};
1174
1175#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1176
1177static struct hpp_dimension hpp_sort_dimensions[] = {
1178 DIM(PERF_HPP__OVERHEAD, "overhead"),
1179 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1180 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1181 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1182 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001183 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001184 DIM(PERF_HPP__SAMPLES, "sample"),
1185 DIM(PERF_HPP__PERIOD, "period"),
1186};
1187
1188#undef DIM
1189
Namhyung Kim8b536992014-03-03 11:46:55 +09001190struct hpp_sort_entry {
1191 struct perf_hpp_fmt hpp;
1192 struct sort_entry *se;
1193};
1194
Namhyung Kima7d945b2014-03-04 10:46:34 +09001195bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1196{
1197 struct hpp_sort_entry *hse_a;
1198 struct hpp_sort_entry *hse_b;
1199
1200 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1201 return false;
1202
1203 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1204 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1205
1206 return hse_a->se == hse_b->se;
1207}
1208
Namhyung Kime0d66c72014-07-31 14:47:37 +09001209void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001210{
1211 struct hpp_sort_entry *hse;
1212
1213 if (!perf_hpp__is_sort_entry(fmt))
1214 return;
1215
1216 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001217 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001218}
1219
Namhyung Kim8b536992014-03-03 11:46:55 +09001220static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1221 struct perf_evsel *evsel)
1222{
1223 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001224 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001225
1226 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001227
Namhyung Kim5b591662014-07-31 14:47:38 +09001228 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001229 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001230
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001231 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001232}
1233
1234static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1235 struct perf_hpp *hpp __maybe_unused,
1236 struct perf_evsel *evsel)
1237{
1238 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001239 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001240
1241 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1242
Namhyung Kim5b591662014-07-31 14:47:38 +09001243 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001244 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001245
1246 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001247}
1248
1249static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1250 struct hist_entry *he)
1251{
1252 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001253 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001254
1255 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001256
1257 if (!len)
1258 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001259
1260 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1261}
1262
Namhyung Kima7d945b2014-03-04 10:46:34 +09001263static struct hpp_sort_entry *
1264__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001265{
1266 struct hpp_sort_entry *hse;
1267
1268 hse = malloc(sizeof(*hse));
1269 if (hse == NULL) {
1270 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001271 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001272 }
1273
1274 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001275 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001276 hse->hpp.header = __sort__hpp_header;
1277 hse->hpp.width = __sort__hpp_width;
1278 hse->hpp.entry = __sort__hpp_entry;
1279 hse->hpp.color = NULL;
1280
1281 hse->hpp.cmp = sd->entry->se_cmp;
1282 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001283 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001284
1285 INIT_LIST_HEAD(&hse->hpp.list);
1286 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001287 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001288 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001289 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001290
Namhyung Kima7d945b2014-03-04 10:46:34 +09001291 return hse;
1292}
1293
1294bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1295{
1296 return format->header == __sort__hpp_header;
1297}
1298
1299static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1300{
1301 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1302
1303 if (hse == NULL)
1304 return -1;
1305
Namhyung Kim8b536992014-03-03 11:46:55 +09001306 perf_hpp__register_sort_field(&hse->hpp);
1307 return 0;
1308}
1309
Namhyung Kima7d945b2014-03-04 10:46:34 +09001310static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1311{
1312 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1313
1314 if (hse == NULL)
1315 return -1;
1316
1317 perf_hpp__column_register(&hse->hpp);
1318 return 0;
1319}
1320
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001321static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001322{
1323 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001324 return 0;
1325
Namhyung Kima7d945b2014-03-04 10:46:34 +09001326 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001327 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001328
1329 if (sd->entry->se_collapse)
1330 sort__need_collapse = 1;
1331
Namhyung Kim2f532d092013-04-03 21:26:10 +09001332 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001333
1334 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001335}
1336
Namhyung Kima2ce0672014-03-04 09:06:42 +09001337static int __hpp_dimension__add(struct hpp_dimension *hd)
1338{
1339 if (!hd->taken) {
1340 hd->taken = 1;
1341
1342 perf_hpp__register_sort_field(hd->fmt);
1343 }
1344 return 0;
1345}
1346
Namhyung Kima7d945b2014-03-04 10:46:34 +09001347static int __sort_dimension__add_output(struct sort_dimension *sd)
1348{
1349 if (sd->taken)
1350 return 0;
1351
1352 if (__sort_dimension__add_hpp_output(sd) < 0)
1353 return -1;
1354
1355 sd->taken = 1;
1356 return 0;
1357}
1358
1359static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1360{
1361 if (!hd->taken) {
1362 hd->taken = 1;
1363
1364 perf_hpp__column_register(hd->fmt);
1365 }
1366 return 0;
1367}
1368
John Kacurdd68ada2009-09-24 18:02:49 +02001369int sort_dimension__add(const char *tok)
1370{
1371 unsigned int i;
1372
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001373 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1374 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001375
John Kacurdd68ada2009-09-24 18:02:49 +02001376 if (strncasecmp(tok, sd->name, strlen(tok)))
1377 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001378
John Kacurdd68ada2009-09-24 18:02:49 +02001379 if (sd->entry == &sort_parent) {
1380 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1381 if (ret) {
1382 char err[BUFSIZ];
1383
1384 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001385 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1386 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001387 }
1388 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001389 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001390 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001391 } else if (sd->entry == &sort_dso) {
1392 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001393 }
1394
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001395 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001396 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001397
Namhyung Kima2ce0672014-03-04 09:06:42 +09001398 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1399 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1400
1401 if (strncasecmp(tok, hd->name, strlen(tok)))
1402 continue;
1403
1404 return __hpp_dimension__add(hd);
1405 }
1406
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001407 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1408 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1409
1410 if (strncasecmp(tok, sd->name, strlen(tok)))
1411 continue;
1412
Namhyung Kim55369fc2013-04-01 20:35:20 +09001413 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001414 return -EINVAL;
1415
1416 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1417 sort__has_sym = 1;
1418
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001419 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001420 return 0;
1421 }
1422
Namhyung Kimafab87b2013-04-03 21:26:11 +09001423 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1424 struct sort_dimension *sd = &memory_sort_dimensions[i];
1425
1426 if (strncasecmp(tok, sd->name, strlen(tok)))
1427 continue;
1428
1429 if (sort__mode != SORT_MODE__MEMORY)
1430 return -EINVAL;
1431
1432 if (sd->entry == &sort_mem_daddr_sym)
1433 sort__has_sym = 1;
1434
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001435 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001436 return 0;
1437 }
1438
John Kacurdd68ada2009-09-24 18:02:49 +02001439 return -ESRCH;
1440}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001441
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001442static const char *get_default_sort_order(void)
1443{
1444 const char *default_sort_orders[] = {
1445 default_sort_order,
1446 default_branch_sort_order,
1447 default_mem_sort_order,
1448 default_top_sort_order,
1449 default_diff_sort_order,
1450 };
1451
1452 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1453
1454 return default_sort_orders[sort__mode];
1455}
1456
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001457static int setup_sort_order(void)
1458{
1459 char *new_sort_order;
1460
1461 /*
1462 * Append '+'-prefixed sort order to the default sort
1463 * order string.
1464 */
1465 if (!sort_order || is_strict_order(sort_order))
1466 return 0;
1467
1468 if (sort_order[1] == '\0') {
1469 error("Invalid --sort key: `+'");
1470 return -EINVAL;
1471 }
1472
1473 /*
1474 * We allocate new sort_order string, but we never free it,
1475 * because it's checked over the rest of the code.
1476 */
1477 if (asprintf(&new_sort_order, "%s,%s",
1478 get_default_sort_order(), sort_order + 1) < 0) {
1479 error("Not enough memory to set up --sort");
1480 return -ENOMEM;
1481 }
1482
1483 sort_order = new_sort_order;
1484 return 0;
1485}
1486
Namhyung Kima7d945b2014-03-04 10:46:34 +09001487static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001488{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001489 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001490 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001491 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001492
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001493 ret = setup_sort_order();
1494 if (ret)
1495 return ret;
1496
1497 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001498 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001499 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001500 /*
1501 * If user specified field order but no sort order,
1502 * we'll honor it and not add default sort orders.
1503 */
1504 return 0;
1505 }
1506
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001507 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001508 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001509
1510 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001511 if (str == NULL) {
1512 error("Not enough memory to setup sort keys");
1513 return -ENOMEM;
1514 }
1515
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001516 for (tok = strtok_r(str, ", ", &tmp);
1517 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001518 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001519 if (ret == -EINVAL) {
1520 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001521 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001522 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001523 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001524 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001525 }
1526 }
1527
1528 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001529 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001530}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001531
Jiri Olsaf2998422014-05-23 17:15:47 +02001532void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001533{
Jiri Olsaf2998422014-05-23 17:15:47 +02001534 struct perf_hpp_fmt *fmt;
1535 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001536
Jiri Olsaf2998422014-05-23 17:15:47 +02001537 perf_hpp__for_each_format(fmt) {
1538 if (!perf_hpp__is_sort_entry(fmt))
1539 continue;
1540
1541 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1542 if (hse->se->se_width_idx == idx) {
1543 fmt->elide = elide;
1544 break;
1545 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001546 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001547}
1548
Jiri Olsaf2998422014-05-23 17:15:47 +02001549static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001550{
1551 if (list && strlist__nr_entries(list) == 1) {
1552 if (fp != NULL)
1553 fprintf(fp, "# %s: %s\n", list_name,
1554 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001555 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001556 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001557 return false;
1558}
1559
1560static bool get_elide(int idx, FILE *output)
1561{
1562 switch (idx) {
1563 case HISTC_SYMBOL:
1564 return __get_elide(symbol_conf.sym_list, "symbol", output);
1565 case HISTC_DSO:
1566 return __get_elide(symbol_conf.dso_list, "dso", output);
1567 case HISTC_COMM:
1568 return __get_elide(symbol_conf.comm_list, "comm", output);
1569 default:
1570 break;
1571 }
1572
1573 if (sort__mode != SORT_MODE__BRANCH)
1574 return false;
1575
1576 switch (idx) {
1577 case HISTC_SYMBOL_FROM:
1578 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1579 case HISTC_SYMBOL_TO:
1580 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1581 case HISTC_DSO_FROM:
1582 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1583 case HISTC_DSO_TO:
1584 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1585 default:
1586 break;
1587 }
1588
1589 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001590}
Namhyung Kim08e71542013-04-03 21:26:19 +09001591
1592void sort__setup_elide(FILE *output)
1593{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001594 struct perf_hpp_fmt *fmt;
1595 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001596
Jiri Olsaf2998422014-05-23 17:15:47 +02001597 perf_hpp__for_each_format(fmt) {
1598 if (!perf_hpp__is_sort_entry(fmt))
1599 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001600
Jiri Olsaf2998422014-05-23 17:15:47 +02001601 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1602 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001603 }
1604
Namhyung Kim7524f632013-11-08 17:53:42 +09001605 /*
1606 * It makes no sense to elide all of sort entries.
1607 * Just revert them to show up again.
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 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001614 return;
1615 }
1616
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001617 perf_hpp__for_each_format(fmt) {
1618 if (!perf_hpp__is_sort_entry(fmt))
1619 continue;
1620
Jiri Olsaf2998422014-05-23 17:15:47 +02001621 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001622 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001623}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001624
1625static int output_field_add(char *tok)
1626{
1627 unsigned int i;
1628
1629 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1630 struct sort_dimension *sd = &common_sort_dimensions[i];
1631
1632 if (strncasecmp(tok, sd->name, strlen(tok)))
1633 continue;
1634
1635 return __sort_dimension__add_output(sd);
1636 }
1637
1638 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1639 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1640
1641 if (strncasecmp(tok, hd->name, strlen(tok)))
1642 continue;
1643
1644 return __hpp_dimension__add_output(hd);
1645 }
1646
1647 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1648 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1649
1650 if (strncasecmp(tok, sd->name, strlen(tok)))
1651 continue;
1652
1653 return __sort_dimension__add_output(sd);
1654 }
1655
1656 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1657 struct sort_dimension *sd = &memory_sort_dimensions[i];
1658
1659 if (strncasecmp(tok, sd->name, strlen(tok)))
1660 continue;
1661
1662 return __sort_dimension__add_output(sd);
1663 }
1664
1665 return -ESRCH;
1666}
1667
1668static void reset_dimensions(void)
1669{
1670 unsigned int i;
1671
1672 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1673 common_sort_dimensions[i].taken = 0;
1674
1675 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1676 hpp_sort_dimensions[i].taken = 0;
1677
1678 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1679 bstack_sort_dimensions[i].taken = 0;
1680
1681 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1682 memory_sort_dimensions[i].taken = 0;
1683}
1684
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001685bool is_strict_order(const char *order)
1686{
1687 return order && (*order != '+');
1688}
1689
Namhyung Kima7d945b2014-03-04 10:46:34 +09001690static int __setup_output_field(void)
1691{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001692 char *tmp, *tok, *str, *strp;
1693 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001694
1695 if (field_order == NULL)
1696 return 0;
1697
1698 reset_dimensions();
1699
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001700 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001701 if (str == NULL) {
1702 error("Not enough memory to setup output fields");
1703 return -ENOMEM;
1704 }
1705
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001706 if (!is_strict_order(field_order))
1707 strp++;
1708
1709 if (!strlen(strp)) {
1710 error("Invalid --fields key: `+'");
1711 goto out;
1712 }
1713
1714 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001715 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1716 ret = output_field_add(tok);
1717 if (ret == -EINVAL) {
1718 error("Invalid --fields key: `%s'", tok);
1719 break;
1720 } else if (ret == -ESRCH) {
1721 error("Unknown --fields key: `%s'", tok);
1722 break;
1723 }
1724 }
1725
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001726out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001727 free(str);
1728 return ret;
1729}
1730
1731int setup_sorting(void)
1732{
1733 int err;
1734
1735 err = __setup_sorting();
1736 if (err < 0)
1737 return err;
1738
1739 if (parent_pattern != default_parent_pattern) {
1740 err = sort_dimension__add("parent");
1741 if (err < 0)
1742 return err;
1743 }
1744
1745 reset_dimensions();
1746
1747 /*
1748 * perf diff doesn't use default hpp output fields.
1749 */
1750 if (sort__mode != SORT_MODE__DIFF)
1751 perf_hpp__init();
1752
1753 err = __setup_output_field();
1754 if (err < 0)
1755 return err;
1756
1757 /* copy sort keys to output fields */
1758 perf_hpp__setup_output_field();
1759 /* and then copy output fields to sort keys */
1760 perf_hpp__append_sort_keys();
1761
1762 return 0;
1763}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001764
1765void reset_output_field(void)
1766{
1767 sort__need_collapse = 0;
1768 sort__has_parent = 0;
1769 sort__has_sym = 0;
1770 sort__has_dso = 0;
1771
Namhyung Kimd69b2962014-05-23 10:59:01 +09001772 field_order = NULL;
1773 sort_order = NULL;
1774
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001775 reset_dimensions();
1776 perf_hpp__reset_output_field();
1777}