blob: fc4ff2a966160ae1e62b670a978baf27166219bc [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
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200407 if (!left->branch_info || !right->branch_info)
408 return cmp_null(left->branch_info, right->branch_info);
409
410 from_l = &left->branch_info->from;
411 from_r = &right->branch_info->from;
412
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100413 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900414 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100415
Namhyung Kim51f27d12013-02-06 14:57:15 +0900416 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100417}
418
419static int64_t
420sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
421{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200422 struct addr_map_symbol *to_l, *to_r;
423
424 if (!left->branch_info || !right->branch_info)
425 return cmp_null(left->branch_info, right->branch_info);
426
427 to_l = &left->branch_info->to;
428 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429
430 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900431 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100432
Namhyung Kim51f27d12013-02-06 14:57:15 +0900433 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100434}
435
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300436static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900437 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100438{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200439 if (he->branch_info) {
440 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100441
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200442 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
443 he->level, bf, size, width);
444 }
445
446 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100447}
448
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300449static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900450 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100451{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200452 if (he->branch_info) {
453 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100454
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200455 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
456 he->level, bf, size, width);
457 }
458
459 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100460}
461
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900462struct sort_entry sort_dso_from = {
463 .se_header = "Source Shared Object",
464 .se_cmp = sort__dso_from_cmp,
465 .se_snprintf = hist_entry__dso_from_snprintf,
466 .se_width_idx = HISTC_DSO_FROM,
467};
468
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100469struct sort_entry sort_dso_to = {
470 .se_header = "Target Shared Object",
471 .se_cmp = sort__dso_to_cmp,
472 .se_snprintf = hist_entry__dso_to_snprintf,
473 .se_width_idx = HISTC_DSO_TO,
474};
475
476struct sort_entry sort_sym_from = {
477 .se_header = "Source Symbol",
478 .se_cmp = sort__sym_from_cmp,
479 .se_snprintf = hist_entry__sym_from_snprintf,
480 .se_width_idx = HISTC_SYMBOL_FROM,
481};
482
483struct sort_entry sort_sym_to = {
484 .se_header = "Target Symbol",
485 .se_cmp = sort__sym_to_cmp,
486 .se_snprintf = hist_entry__sym_to_snprintf,
487 .se_width_idx = HISTC_SYMBOL_TO,
488};
489
490static int64_t
491sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
492{
Jiri Olsa428560e2014-10-16 16:07:03 +0200493 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100494
Jiri Olsa428560e2014-10-16 16:07:03 +0200495 if (!left->branch_info || !right->branch_info)
496 return cmp_null(left->branch_info, right->branch_info);
497
498 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
499 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100500 return mp || p;
501}
502
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300503static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100504 size_t size, unsigned int width){
505 static const char *out = "N/A";
506
Jiri Olsa428560e2014-10-16 16:07:03 +0200507 if (he->branch_info) {
508 if (he->branch_info->flags.predicted)
509 out = "N";
510 else if (he->branch_info->flags.mispred)
511 out = "Y";
512 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100513
Namhyung Kim5b591662014-07-31 14:47:38 +0900514 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100515}
516
Stephane Eranian98a3b322013-01-24 16:10:35 +0100517/* --sort daddr_sym */
518static int64_t
519sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
520{
521 uint64_t l = 0, r = 0;
522
523 if (left->mem_info)
524 l = left->mem_info->daddr.addr;
525 if (right->mem_info)
526 r = right->mem_info->daddr.addr;
527
528 return (int64_t)(r - l);
529}
530
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300531static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100532 size_t size, unsigned int width)
533{
534 uint64_t addr = 0;
535 struct map *map = NULL;
536 struct symbol *sym = NULL;
537
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300538 if (he->mem_info) {
539 addr = he->mem_info->daddr.addr;
540 map = he->mem_info->daddr.map;
541 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100542 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100544 width);
545}
546
547static int64_t
548sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
549{
550 struct map *map_l = NULL;
551 struct map *map_r = NULL;
552
553 if (left->mem_info)
554 map_l = left->mem_info->daddr.map;
555 if (right->mem_info)
556 map_r = right->mem_info->daddr.map;
557
558 return _sort__dso_cmp(map_l, map_r);
559}
560
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300561static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100562 size_t size, unsigned int width)
563{
564 struct map *map = NULL;
565
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300566 if (he->mem_info)
567 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100568
569 return _hist_entry__dso_snprintf(map, bf, size, width);
570}
571
572static int64_t
573sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
574{
575 union perf_mem_data_src data_src_l;
576 union perf_mem_data_src data_src_r;
577
578 if (left->mem_info)
579 data_src_l = left->mem_info->data_src;
580 else
581 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
582
583 if (right->mem_info)
584 data_src_r = right->mem_info->data_src;
585 else
586 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
587
588 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
589}
590
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300591static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100592 size_t size, unsigned int width)
593{
594 const char *out;
595 u64 mask = PERF_MEM_LOCK_NA;
596
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300597 if (he->mem_info)
598 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100599
600 if (mask & PERF_MEM_LOCK_NA)
601 out = "N/A";
602 else if (mask & PERF_MEM_LOCK_LOCKED)
603 out = "Yes";
604 else
605 out = "No";
606
607 return repsep_snprintf(bf, size, "%-*s", width, out);
608}
609
610static int64_t
611sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
612{
613 union perf_mem_data_src data_src_l;
614 union perf_mem_data_src data_src_r;
615
616 if (left->mem_info)
617 data_src_l = left->mem_info->data_src;
618 else
619 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
620
621 if (right->mem_info)
622 data_src_r = right->mem_info->data_src;
623 else
624 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
625
626 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
627}
628
629static const char * const tlb_access[] = {
630 "N/A",
631 "HIT",
632 "MISS",
633 "L1",
634 "L2",
635 "Walker",
636 "Fault",
637};
638#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
639
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300640static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100641 size_t size, unsigned int width)
642{
643 char out[64];
644 size_t sz = sizeof(out) - 1; /* -1 for null termination */
645 size_t l = 0, i;
646 u64 m = PERF_MEM_TLB_NA;
647 u64 hit, miss;
648
649 out[0] = '\0';
650
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300651 if (he->mem_info)
652 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100653
654 hit = m & PERF_MEM_TLB_HIT;
655 miss = m & PERF_MEM_TLB_MISS;
656
657 /* already taken care of */
658 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
659
660 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
661 if (!(m & 0x1))
662 continue;
663 if (l) {
664 strcat(out, " or ");
665 l += 4;
666 }
667 strncat(out, tlb_access[i], sz - l);
668 l += strlen(tlb_access[i]);
669 }
670 if (*out == '\0')
671 strcpy(out, "N/A");
672 if (hit)
673 strncat(out, " hit", sz - l);
674 if (miss)
675 strncat(out, " miss", sz - l);
676
677 return repsep_snprintf(bf, size, "%-*s", width, out);
678}
679
680static int64_t
681sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
682{
683 union perf_mem_data_src data_src_l;
684 union perf_mem_data_src data_src_r;
685
686 if (left->mem_info)
687 data_src_l = left->mem_info->data_src;
688 else
689 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
690
691 if (right->mem_info)
692 data_src_r = right->mem_info->data_src;
693 else
694 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
695
696 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
697}
698
699static const char * const mem_lvl[] = {
700 "N/A",
701 "HIT",
702 "MISS",
703 "L1",
704 "LFB",
705 "L2",
706 "L3",
707 "Local RAM",
708 "Remote RAM (1 hop)",
709 "Remote RAM (2 hops)",
710 "Remote Cache (1 hop)",
711 "Remote Cache (2 hops)",
712 "I/O",
713 "Uncached",
714};
715#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
716
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300717static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100718 size_t size, unsigned int width)
719{
720 char out[64];
721 size_t sz = sizeof(out) - 1; /* -1 for null termination */
722 size_t i, l = 0;
723 u64 m = PERF_MEM_LVL_NA;
724 u64 hit, miss;
725
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300726 if (he->mem_info)
727 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100728
729 out[0] = '\0';
730
731 hit = m & PERF_MEM_LVL_HIT;
732 miss = m & PERF_MEM_LVL_MISS;
733
734 /* already taken care of */
735 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
736
737 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
738 if (!(m & 0x1))
739 continue;
740 if (l) {
741 strcat(out, " or ");
742 l += 4;
743 }
744 strncat(out, mem_lvl[i], sz - l);
745 l += strlen(mem_lvl[i]);
746 }
747 if (*out == '\0')
748 strcpy(out, "N/A");
749 if (hit)
750 strncat(out, " hit", sz - l);
751 if (miss)
752 strncat(out, " miss", sz - l);
753
754 return repsep_snprintf(bf, size, "%-*s", width, out);
755}
756
757static int64_t
758sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
759{
760 union perf_mem_data_src data_src_l;
761 union perf_mem_data_src data_src_r;
762
763 if (left->mem_info)
764 data_src_l = left->mem_info->data_src;
765 else
766 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
767
768 if (right->mem_info)
769 data_src_r = right->mem_info->data_src;
770 else
771 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
772
773 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
774}
775
776static const char * const snoop_access[] = {
777 "N/A",
778 "None",
779 "Miss",
780 "Hit",
781 "HitM",
782};
783#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
784
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300785static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100786 size_t size, unsigned int width)
787{
788 char out[64];
789 size_t sz = sizeof(out) - 1; /* -1 for null termination */
790 size_t i, l = 0;
791 u64 m = PERF_MEM_SNOOP_NA;
792
793 out[0] = '\0';
794
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300795 if (he->mem_info)
796 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100797
798 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
799 if (!(m & 0x1))
800 continue;
801 if (l) {
802 strcat(out, " or ");
803 l += 4;
804 }
805 strncat(out, snoop_access[i], sz - l);
806 l += strlen(snoop_access[i]);
807 }
808
809 if (*out == '\0')
810 strcpy(out, "N/A");
811
812 return repsep_snprintf(bf, size, "%-*s", width, out);
813}
814
Don Zickus9b32ba72014-06-01 15:38:29 +0200815static inline u64 cl_address(u64 address)
816{
817 /* return the cacheline of the address */
818 return (address & ~(cacheline_size - 1));
819}
820
821static int64_t
822sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
823{
824 u64 l, r;
825 struct map *l_map, *r_map;
826
827 if (!left->mem_info) return -1;
828 if (!right->mem_info) return 1;
829
830 /* group event types together */
831 if (left->cpumode > right->cpumode) return -1;
832 if (left->cpumode < right->cpumode) return 1;
833
834 l_map = left->mem_info->daddr.map;
835 r_map = right->mem_info->daddr.map;
836
837 /* if both are NULL, jump to sort on al_addr instead */
838 if (!l_map && !r_map)
839 goto addr;
840
841 if (!l_map) return -1;
842 if (!r_map) return 1;
843
844 if (l_map->maj > r_map->maj) return -1;
845 if (l_map->maj < r_map->maj) return 1;
846
847 if (l_map->min > r_map->min) return -1;
848 if (l_map->min < r_map->min) return 1;
849
850 if (l_map->ino > r_map->ino) return -1;
851 if (l_map->ino < r_map->ino) return 1;
852
853 if (l_map->ino_generation > r_map->ino_generation) return -1;
854 if (l_map->ino_generation < r_map->ino_generation) return 1;
855
856 /*
857 * Addresses with no major/minor numbers are assumed to be
858 * anonymous in userspace. Sort those on pid then address.
859 *
860 * The kernel and non-zero major/minor mapped areas are
861 * assumed to be unity mapped. Sort those on address.
862 */
863
864 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
865 (!(l_map->flags & MAP_SHARED)) &&
866 !l_map->maj && !l_map->min && !l_map->ino &&
867 !l_map->ino_generation) {
868 /* userspace anonymous */
869
870 if (left->thread->pid_ > right->thread->pid_) return -1;
871 if (left->thread->pid_ < right->thread->pid_) return 1;
872 }
873
874addr:
875 /* al_addr does all the right addr - start + offset calculations */
876 l = cl_address(left->mem_info->daddr.al_addr);
877 r = cl_address(right->mem_info->daddr.al_addr);
878
879 if (l > r) return -1;
880 if (l < r) return 1;
881
882 return 0;
883}
884
885static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
886 size_t size, unsigned int width)
887{
888
889 uint64_t addr = 0;
890 struct map *map = NULL;
891 struct symbol *sym = NULL;
892 char level = he->level;
893
894 if (he->mem_info) {
895 addr = cl_address(he->mem_info->daddr.al_addr);
896 map = he->mem_info->daddr.map;
897 sym = he->mem_info->daddr.sym;
898
899 /* print [s] for shared data mmaps */
900 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
901 map && (map->type == MAP__VARIABLE) &&
902 (map->flags & MAP_SHARED) &&
903 (map->maj || map->min || map->ino ||
904 map->ino_generation))
905 level = 's';
906 else if (!map)
907 level = 'X';
908 }
909 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
910 width);
911}
912
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100913struct sort_entry sort_mispredict = {
914 .se_header = "Branch Mispredicted",
915 .se_cmp = sort__mispredict_cmp,
916 .se_snprintf = hist_entry__mispredict_snprintf,
917 .se_width_idx = HISTC_MISPREDICT,
918};
919
Andi Kleen05484292013-01-24 16:10:29 +0100920static u64 he_weight(struct hist_entry *he)
921{
922 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
923}
924
925static int64_t
926sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
927{
928 return he_weight(left) - he_weight(right);
929}
930
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300931static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100932 size_t size, unsigned int width)
933{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300934 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100935}
936
937struct sort_entry sort_local_weight = {
938 .se_header = "Local Weight",
939 .se_cmp = sort__local_weight_cmp,
940 .se_snprintf = hist_entry__local_weight_snprintf,
941 .se_width_idx = HISTC_LOCAL_WEIGHT,
942};
943
944static int64_t
945sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
946{
947 return left->stat.weight - right->stat.weight;
948}
949
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300950static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100951 size_t size, unsigned int width)
952{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300953 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100954}
955
956struct sort_entry sort_global_weight = {
957 .se_header = "Weight",
958 .se_cmp = sort__global_weight_cmp,
959 .se_snprintf = hist_entry__global_weight_snprintf,
960 .se_width_idx = HISTC_GLOBAL_WEIGHT,
961};
962
Stephane Eranian98a3b322013-01-24 16:10:35 +0100963struct sort_entry sort_mem_daddr_sym = {
964 .se_header = "Data Symbol",
965 .se_cmp = sort__daddr_cmp,
966 .se_snprintf = hist_entry__daddr_snprintf,
967 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
968};
969
970struct sort_entry sort_mem_daddr_dso = {
971 .se_header = "Data Object",
972 .se_cmp = sort__dso_daddr_cmp,
973 .se_snprintf = hist_entry__dso_daddr_snprintf,
974 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
975};
976
977struct sort_entry sort_mem_locked = {
978 .se_header = "Locked",
979 .se_cmp = sort__locked_cmp,
980 .se_snprintf = hist_entry__locked_snprintf,
981 .se_width_idx = HISTC_MEM_LOCKED,
982};
983
984struct sort_entry sort_mem_tlb = {
985 .se_header = "TLB access",
986 .se_cmp = sort__tlb_cmp,
987 .se_snprintf = hist_entry__tlb_snprintf,
988 .se_width_idx = HISTC_MEM_TLB,
989};
990
991struct sort_entry sort_mem_lvl = {
992 .se_header = "Memory access",
993 .se_cmp = sort__lvl_cmp,
994 .se_snprintf = hist_entry__lvl_snprintf,
995 .se_width_idx = HISTC_MEM_LVL,
996};
997
998struct sort_entry sort_mem_snoop = {
999 .se_header = "Snoop",
1000 .se_cmp = sort__snoop_cmp,
1001 .se_snprintf = hist_entry__snoop_snprintf,
1002 .se_width_idx = HISTC_MEM_SNOOP,
1003};
1004
Don Zickus9b32ba72014-06-01 15:38:29 +02001005struct sort_entry sort_mem_dcacheline = {
1006 .se_header = "Data Cacheline",
1007 .se_cmp = sort__dcacheline_cmp,
1008 .se_snprintf = hist_entry__dcacheline_snprintf,
1009 .se_width_idx = HISTC_MEM_DCACHELINE,
1010};
1011
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001012static int64_t
1013sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1014{
Jiri Olsa49f47442014-10-16 16:07:01 +02001015 if (!left->branch_info || !right->branch_info)
1016 return cmp_null(left->branch_info, right->branch_info);
1017
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001018 return left->branch_info->flags.abort !=
1019 right->branch_info->flags.abort;
1020}
1021
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001022static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001023 size_t size, unsigned int width)
1024{
Jiri Olsa49f47442014-10-16 16:07:01 +02001025 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001026
Jiri Olsa49f47442014-10-16 16:07:01 +02001027 if (he->branch_info) {
1028 if (he->branch_info->flags.abort)
1029 out = "A";
1030 else
1031 out = ".";
1032 }
1033
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001034 return repsep_snprintf(bf, size, "%-*s", width, out);
1035}
1036
1037struct sort_entry sort_abort = {
1038 .se_header = "Transaction abort",
1039 .se_cmp = sort__abort_cmp,
1040 .se_snprintf = hist_entry__abort_snprintf,
1041 .se_width_idx = HISTC_ABORT,
1042};
1043
1044static int64_t
1045sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1046{
Jiri Olsa0199d242014-10-16 16:07:02 +02001047 if (!left->branch_info || !right->branch_info)
1048 return cmp_null(left->branch_info, right->branch_info);
1049
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001050 return left->branch_info->flags.in_tx !=
1051 right->branch_info->flags.in_tx;
1052}
1053
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001054static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001055 size_t size, unsigned int width)
1056{
Jiri Olsa0199d242014-10-16 16:07:02 +02001057 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001058
Jiri Olsa0199d242014-10-16 16:07:02 +02001059 if (he->branch_info) {
1060 if (he->branch_info->flags.in_tx)
1061 out = "T";
1062 else
1063 out = ".";
1064 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001065
1066 return repsep_snprintf(bf, size, "%-*s", width, out);
1067}
1068
1069struct sort_entry sort_in_tx = {
1070 .se_header = "Branch in transaction",
1071 .se_cmp = sort__in_tx_cmp,
1072 .se_snprintf = hist_entry__in_tx_snprintf,
1073 .se_width_idx = HISTC_IN_TX,
1074};
1075
Andi Kleen475eeab2013-09-20 07:40:43 -07001076static int64_t
1077sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1078{
1079 return left->transaction - right->transaction;
1080}
1081
1082static inline char *add_str(char *p, const char *str)
1083{
1084 strcpy(p, str);
1085 return p + strlen(str);
1086}
1087
1088static struct txbit {
1089 unsigned flag;
1090 const char *name;
1091 int skip_for_len;
1092} txbits[] = {
1093 { PERF_TXN_ELISION, "EL ", 0 },
1094 { PERF_TXN_TRANSACTION, "TX ", 1 },
1095 { PERF_TXN_SYNC, "SYNC ", 1 },
1096 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1097 { PERF_TXN_RETRY, "RETRY ", 0 },
1098 { PERF_TXN_CONFLICT, "CON ", 0 },
1099 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1100 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1101 { 0, NULL, 0 }
1102};
1103
1104int hist_entry__transaction_len(void)
1105{
1106 int i;
1107 int len = 0;
1108
1109 for (i = 0; txbits[i].name; i++) {
1110 if (!txbits[i].skip_for_len)
1111 len += strlen(txbits[i].name);
1112 }
1113 len += 4; /* :XX<space> */
1114 return len;
1115}
1116
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001117static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001118 size_t size, unsigned int width)
1119{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001120 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001121 char buf[128];
1122 char *p = buf;
1123 int i;
1124
1125 buf[0] = 0;
1126 for (i = 0; txbits[i].name; i++)
1127 if (txbits[i].flag & t)
1128 p = add_str(p, txbits[i].name);
1129 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1130 p = add_str(p, "NEITHER ");
1131 if (t & PERF_TXN_ABORT_MASK) {
1132 sprintf(p, ":%" PRIx64,
1133 (t & PERF_TXN_ABORT_MASK) >>
1134 PERF_TXN_ABORT_SHIFT);
1135 p += strlen(p);
1136 }
1137
1138 return repsep_snprintf(bf, size, "%-*s", width, buf);
1139}
1140
1141struct sort_entry sort_transaction = {
1142 .se_header = "Transaction ",
1143 .se_cmp = sort__transaction_cmp,
1144 .se_snprintf = hist_entry__transaction_snprintf,
1145 .se_width_idx = HISTC_TRANSACTION,
1146};
1147
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001148struct sort_dimension {
1149 const char *name;
1150 struct sort_entry *entry;
1151 int taken;
1152};
1153
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001154#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1155
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001156static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001157 DIM(SORT_PID, "pid", sort_thread),
1158 DIM(SORT_COMM, "comm", sort_comm),
1159 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001160 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001161 DIM(SORT_PARENT, "parent", sort_parent),
1162 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001163 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001164 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1165 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001166 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001167};
1168
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001169#undef DIM
1170
1171#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1172
1173static struct sort_dimension bstack_sort_dimensions[] = {
1174 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1175 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1176 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1177 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1178 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001179 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1180 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001181};
1182
1183#undef DIM
1184
Namhyung Kimafab87b2013-04-03 21:26:11 +09001185#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1186
1187static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001188 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1189 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1190 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1191 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1192 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1193 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001194 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001195};
1196
1197#undef DIM
1198
Namhyung Kima2ce0672014-03-04 09:06:42 +09001199struct hpp_dimension {
1200 const char *name;
1201 struct perf_hpp_fmt *fmt;
1202 int taken;
1203};
1204
1205#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1206
1207static struct hpp_dimension hpp_sort_dimensions[] = {
1208 DIM(PERF_HPP__OVERHEAD, "overhead"),
1209 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1210 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1211 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1212 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001213 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001214 DIM(PERF_HPP__SAMPLES, "sample"),
1215 DIM(PERF_HPP__PERIOD, "period"),
1216};
1217
1218#undef DIM
1219
Namhyung Kim8b536992014-03-03 11:46:55 +09001220struct hpp_sort_entry {
1221 struct perf_hpp_fmt hpp;
1222 struct sort_entry *se;
1223};
1224
Namhyung Kima7d945b2014-03-04 10:46:34 +09001225bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1226{
1227 struct hpp_sort_entry *hse_a;
1228 struct hpp_sort_entry *hse_b;
1229
1230 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1231 return false;
1232
1233 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1234 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1235
1236 return hse_a->se == hse_b->se;
1237}
1238
Namhyung Kime0d66c72014-07-31 14:47:37 +09001239void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001240{
1241 struct hpp_sort_entry *hse;
1242
1243 if (!perf_hpp__is_sort_entry(fmt))
1244 return;
1245
1246 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001247 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001248}
1249
Namhyung Kim8b536992014-03-03 11:46:55 +09001250static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1251 struct perf_evsel *evsel)
1252{
1253 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001254 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001255
1256 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001257
Namhyung Kim5b591662014-07-31 14:47:38 +09001258 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001259 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001260
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001261 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001262}
1263
1264static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1265 struct perf_hpp *hpp __maybe_unused,
1266 struct perf_evsel *evsel)
1267{
1268 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001269 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001270
1271 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1272
Namhyung Kim5b591662014-07-31 14:47:38 +09001273 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001274 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001275
1276 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001277}
1278
1279static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1280 struct hist_entry *he)
1281{
1282 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001283 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001284
1285 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001286
1287 if (!len)
1288 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001289
1290 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1291}
1292
Namhyung Kima7d945b2014-03-04 10:46:34 +09001293static struct hpp_sort_entry *
1294__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001295{
1296 struct hpp_sort_entry *hse;
1297
1298 hse = malloc(sizeof(*hse));
1299 if (hse == NULL) {
1300 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001301 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001302 }
1303
1304 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001305 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001306 hse->hpp.header = __sort__hpp_header;
1307 hse->hpp.width = __sort__hpp_width;
1308 hse->hpp.entry = __sort__hpp_entry;
1309 hse->hpp.color = NULL;
1310
1311 hse->hpp.cmp = sd->entry->se_cmp;
1312 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001313 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001314
1315 INIT_LIST_HEAD(&hse->hpp.list);
1316 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001317 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001318 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001319 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001320
Namhyung Kima7d945b2014-03-04 10:46:34 +09001321 return hse;
1322}
1323
1324bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1325{
1326 return format->header == __sort__hpp_header;
1327}
1328
1329static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1330{
1331 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1332
1333 if (hse == NULL)
1334 return -1;
1335
Namhyung Kim8b536992014-03-03 11:46:55 +09001336 perf_hpp__register_sort_field(&hse->hpp);
1337 return 0;
1338}
1339
Namhyung Kima7d945b2014-03-04 10:46:34 +09001340static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1341{
1342 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1343
1344 if (hse == NULL)
1345 return -1;
1346
1347 perf_hpp__column_register(&hse->hpp);
1348 return 0;
1349}
1350
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001351static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001352{
1353 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001354 return 0;
1355
Namhyung Kima7d945b2014-03-04 10:46:34 +09001356 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001357 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001358
1359 if (sd->entry->se_collapse)
1360 sort__need_collapse = 1;
1361
Namhyung Kim2f532d092013-04-03 21:26:10 +09001362 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001363
1364 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001365}
1366
Namhyung Kima2ce0672014-03-04 09:06:42 +09001367static int __hpp_dimension__add(struct hpp_dimension *hd)
1368{
1369 if (!hd->taken) {
1370 hd->taken = 1;
1371
1372 perf_hpp__register_sort_field(hd->fmt);
1373 }
1374 return 0;
1375}
1376
Namhyung Kima7d945b2014-03-04 10:46:34 +09001377static int __sort_dimension__add_output(struct sort_dimension *sd)
1378{
1379 if (sd->taken)
1380 return 0;
1381
1382 if (__sort_dimension__add_hpp_output(sd) < 0)
1383 return -1;
1384
1385 sd->taken = 1;
1386 return 0;
1387}
1388
1389static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1390{
1391 if (!hd->taken) {
1392 hd->taken = 1;
1393
1394 perf_hpp__column_register(hd->fmt);
1395 }
1396 return 0;
1397}
1398
John Kacurdd68ada2009-09-24 18:02:49 +02001399int sort_dimension__add(const char *tok)
1400{
1401 unsigned int i;
1402
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001403 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1404 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001405
John Kacurdd68ada2009-09-24 18:02:49 +02001406 if (strncasecmp(tok, sd->name, strlen(tok)))
1407 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001408
John Kacurdd68ada2009-09-24 18:02:49 +02001409 if (sd->entry == &sort_parent) {
1410 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1411 if (ret) {
1412 char err[BUFSIZ];
1413
1414 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001415 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1416 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001417 }
1418 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001419 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001420 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001421 } else if (sd->entry == &sort_dso) {
1422 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001423 }
1424
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001425 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001426 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001427
Namhyung Kima2ce0672014-03-04 09:06:42 +09001428 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1429 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1430
1431 if (strncasecmp(tok, hd->name, strlen(tok)))
1432 continue;
1433
1434 return __hpp_dimension__add(hd);
1435 }
1436
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001437 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1438 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1439
1440 if (strncasecmp(tok, sd->name, strlen(tok)))
1441 continue;
1442
Namhyung Kim55369fc2013-04-01 20:35:20 +09001443 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001444 return -EINVAL;
1445
1446 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1447 sort__has_sym = 1;
1448
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001449 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001450 return 0;
1451 }
1452
Namhyung Kimafab87b2013-04-03 21:26:11 +09001453 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1454 struct sort_dimension *sd = &memory_sort_dimensions[i];
1455
1456 if (strncasecmp(tok, sd->name, strlen(tok)))
1457 continue;
1458
1459 if (sort__mode != SORT_MODE__MEMORY)
1460 return -EINVAL;
1461
1462 if (sd->entry == &sort_mem_daddr_sym)
1463 sort__has_sym = 1;
1464
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001465 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001466 return 0;
1467 }
1468
John Kacurdd68ada2009-09-24 18:02:49 +02001469 return -ESRCH;
1470}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001471
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001472static const char *get_default_sort_order(void)
1473{
1474 const char *default_sort_orders[] = {
1475 default_sort_order,
1476 default_branch_sort_order,
1477 default_mem_sort_order,
1478 default_top_sort_order,
1479 default_diff_sort_order,
1480 };
1481
1482 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1483
1484 return default_sort_orders[sort__mode];
1485}
1486
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001487static int setup_sort_order(void)
1488{
1489 char *new_sort_order;
1490
1491 /*
1492 * Append '+'-prefixed sort order to the default sort
1493 * order string.
1494 */
1495 if (!sort_order || is_strict_order(sort_order))
1496 return 0;
1497
1498 if (sort_order[1] == '\0') {
1499 error("Invalid --sort key: `+'");
1500 return -EINVAL;
1501 }
1502
1503 /*
1504 * We allocate new sort_order string, but we never free it,
1505 * because it's checked over the rest of the code.
1506 */
1507 if (asprintf(&new_sort_order, "%s,%s",
1508 get_default_sort_order(), sort_order + 1) < 0) {
1509 error("Not enough memory to set up --sort");
1510 return -ENOMEM;
1511 }
1512
1513 sort_order = new_sort_order;
1514 return 0;
1515}
1516
Namhyung Kima7d945b2014-03-04 10:46:34 +09001517static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001518{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001519 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001520 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001521 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001522
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001523 ret = setup_sort_order();
1524 if (ret)
1525 return ret;
1526
1527 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001528 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001529 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001530 /*
1531 * If user specified field order but no sort order,
1532 * we'll honor it and not add default sort orders.
1533 */
1534 return 0;
1535 }
1536
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001537 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001538 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001539
1540 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001541 if (str == NULL) {
1542 error("Not enough memory to setup sort keys");
1543 return -ENOMEM;
1544 }
1545
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001546 for (tok = strtok_r(str, ", ", &tmp);
1547 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001548 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001549 if (ret == -EINVAL) {
1550 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001551 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001552 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001553 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001554 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001555 }
1556 }
1557
1558 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001559 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001560}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001561
Jiri Olsaf2998422014-05-23 17:15:47 +02001562void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001563{
Jiri Olsaf2998422014-05-23 17:15:47 +02001564 struct perf_hpp_fmt *fmt;
1565 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001566
Jiri Olsaf2998422014-05-23 17:15:47 +02001567 perf_hpp__for_each_format(fmt) {
1568 if (!perf_hpp__is_sort_entry(fmt))
1569 continue;
1570
1571 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1572 if (hse->se->se_width_idx == idx) {
1573 fmt->elide = elide;
1574 break;
1575 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001576 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001577}
1578
Jiri Olsaf2998422014-05-23 17:15:47 +02001579static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001580{
1581 if (list && strlist__nr_entries(list) == 1) {
1582 if (fp != NULL)
1583 fprintf(fp, "# %s: %s\n", list_name,
1584 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001585 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001586 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001587 return false;
1588}
1589
1590static bool get_elide(int idx, FILE *output)
1591{
1592 switch (idx) {
1593 case HISTC_SYMBOL:
1594 return __get_elide(symbol_conf.sym_list, "symbol", output);
1595 case HISTC_DSO:
1596 return __get_elide(symbol_conf.dso_list, "dso", output);
1597 case HISTC_COMM:
1598 return __get_elide(symbol_conf.comm_list, "comm", output);
1599 default:
1600 break;
1601 }
1602
1603 if (sort__mode != SORT_MODE__BRANCH)
1604 return false;
1605
1606 switch (idx) {
1607 case HISTC_SYMBOL_FROM:
1608 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1609 case HISTC_SYMBOL_TO:
1610 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1611 case HISTC_DSO_FROM:
1612 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1613 case HISTC_DSO_TO:
1614 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1615 default:
1616 break;
1617 }
1618
1619 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001620}
Namhyung Kim08e71542013-04-03 21:26:19 +09001621
1622void sort__setup_elide(FILE *output)
1623{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001624 struct perf_hpp_fmt *fmt;
1625 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001626
Jiri Olsaf2998422014-05-23 17:15:47 +02001627 perf_hpp__for_each_format(fmt) {
1628 if (!perf_hpp__is_sort_entry(fmt))
1629 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001630
Jiri Olsaf2998422014-05-23 17:15:47 +02001631 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1632 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001633 }
1634
Namhyung Kim7524f632013-11-08 17:53:42 +09001635 /*
1636 * It makes no sense to elide all of sort entries.
1637 * Just revert them to show up again.
1638 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001639 perf_hpp__for_each_format(fmt) {
1640 if (!perf_hpp__is_sort_entry(fmt))
1641 continue;
1642
Jiri Olsaf2998422014-05-23 17:15:47 +02001643 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001644 return;
1645 }
1646
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001647 perf_hpp__for_each_format(fmt) {
1648 if (!perf_hpp__is_sort_entry(fmt))
1649 continue;
1650
Jiri Olsaf2998422014-05-23 17:15:47 +02001651 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001652 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001653}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001654
1655static int output_field_add(char *tok)
1656{
1657 unsigned int i;
1658
1659 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1660 struct sort_dimension *sd = &common_sort_dimensions[i];
1661
1662 if (strncasecmp(tok, sd->name, strlen(tok)))
1663 continue;
1664
1665 return __sort_dimension__add_output(sd);
1666 }
1667
1668 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1669 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1670
1671 if (strncasecmp(tok, hd->name, strlen(tok)))
1672 continue;
1673
1674 return __hpp_dimension__add_output(hd);
1675 }
1676
1677 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1678 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1679
1680 if (strncasecmp(tok, sd->name, strlen(tok)))
1681 continue;
1682
1683 return __sort_dimension__add_output(sd);
1684 }
1685
1686 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1687 struct sort_dimension *sd = &memory_sort_dimensions[i];
1688
1689 if (strncasecmp(tok, sd->name, strlen(tok)))
1690 continue;
1691
1692 return __sort_dimension__add_output(sd);
1693 }
1694
1695 return -ESRCH;
1696}
1697
1698static void reset_dimensions(void)
1699{
1700 unsigned int i;
1701
1702 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1703 common_sort_dimensions[i].taken = 0;
1704
1705 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1706 hpp_sort_dimensions[i].taken = 0;
1707
1708 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1709 bstack_sort_dimensions[i].taken = 0;
1710
1711 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1712 memory_sort_dimensions[i].taken = 0;
1713}
1714
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001715bool is_strict_order(const char *order)
1716{
1717 return order && (*order != '+');
1718}
1719
Namhyung Kima7d945b2014-03-04 10:46:34 +09001720static int __setup_output_field(void)
1721{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001722 char *tmp, *tok, *str, *strp;
1723 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001724
1725 if (field_order == NULL)
1726 return 0;
1727
1728 reset_dimensions();
1729
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001730 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001731 if (str == NULL) {
1732 error("Not enough memory to setup output fields");
1733 return -ENOMEM;
1734 }
1735
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001736 if (!is_strict_order(field_order))
1737 strp++;
1738
1739 if (!strlen(strp)) {
1740 error("Invalid --fields key: `+'");
1741 goto out;
1742 }
1743
1744 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001745 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1746 ret = output_field_add(tok);
1747 if (ret == -EINVAL) {
1748 error("Invalid --fields key: `%s'", tok);
1749 break;
1750 } else if (ret == -ESRCH) {
1751 error("Unknown --fields key: `%s'", tok);
1752 break;
1753 }
1754 }
1755
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001756out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001757 free(str);
1758 return ret;
1759}
1760
1761int setup_sorting(void)
1762{
1763 int err;
1764
1765 err = __setup_sorting();
1766 if (err < 0)
1767 return err;
1768
1769 if (parent_pattern != default_parent_pattern) {
1770 err = sort_dimension__add("parent");
1771 if (err < 0)
1772 return err;
1773 }
1774
1775 reset_dimensions();
1776
1777 /*
1778 * perf diff doesn't use default hpp output fields.
1779 */
1780 if (sort__mode != SORT_MODE__DIFF)
1781 perf_hpp__init();
1782
1783 err = __setup_output_field();
1784 if (err < 0)
1785 return err;
1786
1787 /* copy sort keys to output fields */
1788 perf_hpp__setup_output_field();
1789 /* and then copy output fields to sort keys */
1790 perf_hpp__append_sort_keys();
1791
1792 return 0;
1793}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001794
1795void reset_output_field(void)
1796{
1797 sort__need_collapse = 0;
1798 sort__has_parent = 0;
1799 sort__has_sym = 0;
1800 sort__has_dso = 0;
1801
Namhyung Kimd69b2962014-05-23 10:59:01 +09001802 field_order = NULL;
1803 sort_order = NULL;
1804
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001805 reset_dimensions();
1806 perf_hpp__reset_output_field();
1807}