blob: 0c68af83e7dd23c2f6908ef4c59588a2f9d2c27c [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{
Jiri Olsa428560e2014-10-16 16:07:03 +0200474 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100475
Jiri Olsa428560e2014-10-16 16:07:03 +0200476 if (!left->branch_info || !right->branch_info)
477 return cmp_null(left->branch_info, right->branch_info);
478
479 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
480 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100481 return mp || p;
482}
483
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300484static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100485 size_t size, unsigned int width){
486 static const char *out = "N/A";
487
Jiri Olsa428560e2014-10-16 16:07:03 +0200488 if (he->branch_info) {
489 if (he->branch_info->flags.predicted)
490 out = "N";
491 else if (he->branch_info->flags.mispred)
492 out = "Y";
493 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100494
Namhyung Kim5b591662014-07-31 14:47:38 +0900495 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100496}
497
Stephane Eranian98a3b322013-01-24 16:10:35 +0100498/* --sort daddr_sym */
499static int64_t
500sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
501{
502 uint64_t l = 0, r = 0;
503
504 if (left->mem_info)
505 l = left->mem_info->daddr.addr;
506 if (right->mem_info)
507 r = right->mem_info->daddr.addr;
508
509 return (int64_t)(r - l);
510}
511
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300512static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100513 size_t size, unsigned int width)
514{
515 uint64_t addr = 0;
516 struct map *map = NULL;
517 struct symbol *sym = NULL;
518
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300519 if (he->mem_info) {
520 addr = he->mem_info->daddr.addr;
521 map = he->mem_info->daddr.map;
522 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100523 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300524 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100525 width);
526}
527
528static int64_t
529sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
530{
531 struct map *map_l = NULL;
532 struct map *map_r = NULL;
533
534 if (left->mem_info)
535 map_l = left->mem_info->daddr.map;
536 if (right->mem_info)
537 map_r = right->mem_info->daddr.map;
538
539 return _sort__dso_cmp(map_l, map_r);
540}
541
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300542static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100543 size_t size, unsigned int width)
544{
545 struct map *map = NULL;
546
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300547 if (he->mem_info)
548 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100549
550 return _hist_entry__dso_snprintf(map, bf, size, width);
551}
552
553static int64_t
554sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
555{
556 union perf_mem_data_src data_src_l;
557 union perf_mem_data_src data_src_r;
558
559 if (left->mem_info)
560 data_src_l = left->mem_info->data_src;
561 else
562 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
563
564 if (right->mem_info)
565 data_src_r = right->mem_info->data_src;
566 else
567 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
568
569 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
570}
571
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300572static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100573 size_t size, unsigned int width)
574{
575 const char *out;
576 u64 mask = PERF_MEM_LOCK_NA;
577
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300578 if (he->mem_info)
579 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100580
581 if (mask & PERF_MEM_LOCK_NA)
582 out = "N/A";
583 else if (mask & PERF_MEM_LOCK_LOCKED)
584 out = "Yes";
585 else
586 out = "No";
587
588 return repsep_snprintf(bf, size, "%-*s", width, out);
589}
590
591static int64_t
592sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
593{
594 union perf_mem_data_src data_src_l;
595 union perf_mem_data_src data_src_r;
596
597 if (left->mem_info)
598 data_src_l = left->mem_info->data_src;
599 else
600 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
601
602 if (right->mem_info)
603 data_src_r = right->mem_info->data_src;
604 else
605 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
606
607 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
608}
609
610static const char * const tlb_access[] = {
611 "N/A",
612 "HIT",
613 "MISS",
614 "L1",
615 "L2",
616 "Walker",
617 "Fault",
618};
619#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
620
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300621static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100622 size_t size, unsigned int width)
623{
624 char out[64];
625 size_t sz = sizeof(out) - 1; /* -1 for null termination */
626 size_t l = 0, i;
627 u64 m = PERF_MEM_TLB_NA;
628 u64 hit, miss;
629
630 out[0] = '\0';
631
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300632 if (he->mem_info)
633 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100634
635 hit = m & PERF_MEM_TLB_HIT;
636 miss = m & PERF_MEM_TLB_MISS;
637
638 /* already taken care of */
639 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
640
641 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
642 if (!(m & 0x1))
643 continue;
644 if (l) {
645 strcat(out, " or ");
646 l += 4;
647 }
648 strncat(out, tlb_access[i], sz - l);
649 l += strlen(tlb_access[i]);
650 }
651 if (*out == '\0')
652 strcpy(out, "N/A");
653 if (hit)
654 strncat(out, " hit", sz - l);
655 if (miss)
656 strncat(out, " miss", sz - l);
657
658 return repsep_snprintf(bf, size, "%-*s", width, out);
659}
660
661static int64_t
662sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
663{
664 union perf_mem_data_src data_src_l;
665 union perf_mem_data_src data_src_r;
666
667 if (left->mem_info)
668 data_src_l = left->mem_info->data_src;
669 else
670 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
671
672 if (right->mem_info)
673 data_src_r = right->mem_info->data_src;
674 else
675 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
676
677 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
678}
679
680static const char * const mem_lvl[] = {
681 "N/A",
682 "HIT",
683 "MISS",
684 "L1",
685 "LFB",
686 "L2",
687 "L3",
688 "Local RAM",
689 "Remote RAM (1 hop)",
690 "Remote RAM (2 hops)",
691 "Remote Cache (1 hop)",
692 "Remote Cache (2 hops)",
693 "I/O",
694 "Uncached",
695};
696#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
697
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300698static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100699 size_t size, unsigned int width)
700{
701 char out[64];
702 size_t sz = sizeof(out) - 1; /* -1 for null termination */
703 size_t i, l = 0;
704 u64 m = PERF_MEM_LVL_NA;
705 u64 hit, miss;
706
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300707 if (he->mem_info)
708 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100709
710 out[0] = '\0';
711
712 hit = m & PERF_MEM_LVL_HIT;
713 miss = m & PERF_MEM_LVL_MISS;
714
715 /* already taken care of */
716 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
717
718 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
719 if (!(m & 0x1))
720 continue;
721 if (l) {
722 strcat(out, " or ");
723 l += 4;
724 }
725 strncat(out, mem_lvl[i], sz - l);
726 l += strlen(mem_lvl[i]);
727 }
728 if (*out == '\0')
729 strcpy(out, "N/A");
730 if (hit)
731 strncat(out, " hit", sz - l);
732 if (miss)
733 strncat(out, " miss", sz - l);
734
735 return repsep_snprintf(bf, size, "%-*s", width, out);
736}
737
738static int64_t
739sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
740{
741 union perf_mem_data_src data_src_l;
742 union perf_mem_data_src data_src_r;
743
744 if (left->mem_info)
745 data_src_l = left->mem_info->data_src;
746 else
747 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
748
749 if (right->mem_info)
750 data_src_r = right->mem_info->data_src;
751 else
752 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
753
754 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
755}
756
757static const char * const snoop_access[] = {
758 "N/A",
759 "None",
760 "Miss",
761 "Hit",
762 "HitM",
763};
764#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
765
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300766static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100767 size_t size, unsigned int width)
768{
769 char out[64];
770 size_t sz = sizeof(out) - 1; /* -1 for null termination */
771 size_t i, l = 0;
772 u64 m = PERF_MEM_SNOOP_NA;
773
774 out[0] = '\0';
775
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300776 if (he->mem_info)
777 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100778
779 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
780 if (!(m & 0x1))
781 continue;
782 if (l) {
783 strcat(out, " or ");
784 l += 4;
785 }
786 strncat(out, snoop_access[i], sz - l);
787 l += strlen(snoop_access[i]);
788 }
789
790 if (*out == '\0')
791 strcpy(out, "N/A");
792
793 return repsep_snprintf(bf, size, "%-*s", width, out);
794}
795
Don Zickus9b32ba72014-06-01 15:38:29 +0200796static inline u64 cl_address(u64 address)
797{
798 /* return the cacheline of the address */
799 return (address & ~(cacheline_size - 1));
800}
801
802static int64_t
803sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
804{
805 u64 l, r;
806 struct map *l_map, *r_map;
807
808 if (!left->mem_info) return -1;
809 if (!right->mem_info) return 1;
810
811 /* group event types together */
812 if (left->cpumode > right->cpumode) return -1;
813 if (left->cpumode < right->cpumode) return 1;
814
815 l_map = left->mem_info->daddr.map;
816 r_map = right->mem_info->daddr.map;
817
818 /* if both are NULL, jump to sort on al_addr instead */
819 if (!l_map && !r_map)
820 goto addr;
821
822 if (!l_map) return -1;
823 if (!r_map) return 1;
824
825 if (l_map->maj > r_map->maj) return -1;
826 if (l_map->maj < r_map->maj) return 1;
827
828 if (l_map->min > r_map->min) return -1;
829 if (l_map->min < r_map->min) return 1;
830
831 if (l_map->ino > r_map->ino) return -1;
832 if (l_map->ino < r_map->ino) return 1;
833
834 if (l_map->ino_generation > r_map->ino_generation) return -1;
835 if (l_map->ino_generation < r_map->ino_generation) return 1;
836
837 /*
838 * Addresses with no major/minor numbers are assumed to be
839 * anonymous in userspace. Sort those on pid then address.
840 *
841 * The kernel and non-zero major/minor mapped areas are
842 * assumed to be unity mapped. Sort those on address.
843 */
844
845 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
846 (!(l_map->flags & MAP_SHARED)) &&
847 !l_map->maj && !l_map->min && !l_map->ino &&
848 !l_map->ino_generation) {
849 /* userspace anonymous */
850
851 if (left->thread->pid_ > right->thread->pid_) return -1;
852 if (left->thread->pid_ < right->thread->pid_) return 1;
853 }
854
855addr:
856 /* al_addr does all the right addr - start + offset calculations */
857 l = cl_address(left->mem_info->daddr.al_addr);
858 r = cl_address(right->mem_info->daddr.al_addr);
859
860 if (l > r) return -1;
861 if (l < r) return 1;
862
863 return 0;
864}
865
866static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
867 size_t size, unsigned int width)
868{
869
870 uint64_t addr = 0;
871 struct map *map = NULL;
872 struct symbol *sym = NULL;
873 char level = he->level;
874
875 if (he->mem_info) {
876 addr = cl_address(he->mem_info->daddr.al_addr);
877 map = he->mem_info->daddr.map;
878 sym = he->mem_info->daddr.sym;
879
880 /* print [s] for shared data mmaps */
881 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
882 map && (map->type == MAP__VARIABLE) &&
883 (map->flags & MAP_SHARED) &&
884 (map->maj || map->min || map->ino ||
885 map->ino_generation))
886 level = 's';
887 else if (!map)
888 level = 'X';
889 }
890 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
891 width);
892}
893
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100894struct sort_entry sort_mispredict = {
895 .se_header = "Branch Mispredicted",
896 .se_cmp = sort__mispredict_cmp,
897 .se_snprintf = hist_entry__mispredict_snprintf,
898 .se_width_idx = HISTC_MISPREDICT,
899};
900
Andi Kleen05484292013-01-24 16:10:29 +0100901static u64 he_weight(struct hist_entry *he)
902{
903 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
904}
905
906static int64_t
907sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
908{
909 return he_weight(left) - he_weight(right);
910}
911
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300912static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100913 size_t size, unsigned int width)
914{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300915 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100916}
917
918struct sort_entry sort_local_weight = {
919 .se_header = "Local Weight",
920 .se_cmp = sort__local_weight_cmp,
921 .se_snprintf = hist_entry__local_weight_snprintf,
922 .se_width_idx = HISTC_LOCAL_WEIGHT,
923};
924
925static int64_t
926sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
927{
928 return left->stat.weight - right->stat.weight;
929}
930
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300931static int hist_entry__global_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->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100935}
936
937struct sort_entry sort_global_weight = {
938 .se_header = "Weight",
939 .se_cmp = sort__global_weight_cmp,
940 .se_snprintf = hist_entry__global_weight_snprintf,
941 .se_width_idx = HISTC_GLOBAL_WEIGHT,
942};
943
Stephane Eranian98a3b322013-01-24 16:10:35 +0100944struct sort_entry sort_mem_daddr_sym = {
945 .se_header = "Data Symbol",
946 .se_cmp = sort__daddr_cmp,
947 .se_snprintf = hist_entry__daddr_snprintf,
948 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
949};
950
951struct sort_entry sort_mem_daddr_dso = {
952 .se_header = "Data Object",
953 .se_cmp = sort__dso_daddr_cmp,
954 .se_snprintf = hist_entry__dso_daddr_snprintf,
955 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
956};
957
958struct sort_entry sort_mem_locked = {
959 .se_header = "Locked",
960 .se_cmp = sort__locked_cmp,
961 .se_snprintf = hist_entry__locked_snprintf,
962 .se_width_idx = HISTC_MEM_LOCKED,
963};
964
965struct sort_entry sort_mem_tlb = {
966 .se_header = "TLB access",
967 .se_cmp = sort__tlb_cmp,
968 .se_snprintf = hist_entry__tlb_snprintf,
969 .se_width_idx = HISTC_MEM_TLB,
970};
971
972struct sort_entry sort_mem_lvl = {
973 .se_header = "Memory access",
974 .se_cmp = sort__lvl_cmp,
975 .se_snprintf = hist_entry__lvl_snprintf,
976 .se_width_idx = HISTC_MEM_LVL,
977};
978
979struct sort_entry sort_mem_snoop = {
980 .se_header = "Snoop",
981 .se_cmp = sort__snoop_cmp,
982 .se_snprintf = hist_entry__snoop_snprintf,
983 .se_width_idx = HISTC_MEM_SNOOP,
984};
985
Don Zickus9b32ba72014-06-01 15:38:29 +0200986struct sort_entry sort_mem_dcacheline = {
987 .se_header = "Data Cacheline",
988 .se_cmp = sort__dcacheline_cmp,
989 .se_snprintf = hist_entry__dcacheline_snprintf,
990 .se_width_idx = HISTC_MEM_DCACHELINE,
991};
992
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700993static int64_t
994sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
995{
Jiri Olsa49f47442014-10-16 16:07:01 +0200996 if (!left->branch_info || !right->branch_info)
997 return cmp_null(left->branch_info, right->branch_info);
998
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700999 return left->branch_info->flags.abort !=
1000 right->branch_info->flags.abort;
1001}
1002
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001003static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001004 size_t size, unsigned int width)
1005{
Jiri Olsa49f47442014-10-16 16:07:01 +02001006 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001007
Jiri Olsa49f47442014-10-16 16:07:01 +02001008 if (he->branch_info) {
1009 if (he->branch_info->flags.abort)
1010 out = "A";
1011 else
1012 out = ".";
1013 }
1014
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001015 return repsep_snprintf(bf, size, "%-*s", width, out);
1016}
1017
1018struct sort_entry sort_abort = {
1019 .se_header = "Transaction abort",
1020 .se_cmp = sort__abort_cmp,
1021 .se_snprintf = hist_entry__abort_snprintf,
1022 .se_width_idx = HISTC_ABORT,
1023};
1024
1025static int64_t
1026sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1027{
Jiri Olsa0199d242014-10-16 16:07:02 +02001028 if (!left->branch_info || !right->branch_info)
1029 return cmp_null(left->branch_info, right->branch_info);
1030
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001031 return left->branch_info->flags.in_tx !=
1032 right->branch_info->flags.in_tx;
1033}
1034
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001035static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001036 size_t size, unsigned int width)
1037{
Jiri Olsa0199d242014-10-16 16:07:02 +02001038 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001039
Jiri Olsa0199d242014-10-16 16:07:02 +02001040 if (he->branch_info) {
1041 if (he->branch_info->flags.in_tx)
1042 out = "T";
1043 else
1044 out = ".";
1045 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001046
1047 return repsep_snprintf(bf, size, "%-*s", width, out);
1048}
1049
1050struct sort_entry sort_in_tx = {
1051 .se_header = "Branch in transaction",
1052 .se_cmp = sort__in_tx_cmp,
1053 .se_snprintf = hist_entry__in_tx_snprintf,
1054 .se_width_idx = HISTC_IN_TX,
1055};
1056
Andi Kleen475eeab2013-09-20 07:40:43 -07001057static int64_t
1058sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1059{
1060 return left->transaction - right->transaction;
1061}
1062
1063static inline char *add_str(char *p, const char *str)
1064{
1065 strcpy(p, str);
1066 return p + strlen(str);
1067}
1068
1069static struct txbit {
1070 unsigned flag;
1071 const char *name;
1072 int skip_for_len;
1073} txbits[] = {
1074 { PERF_TXN_ELISION, "EL ", 0 },
1075 { PERF_TXN_TRANSACTION, "TX ", 1 },
1076 { PERF_TXN_SYNC, "SYNC ", 1 },
1077 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1078 { PERF_TXN_RETRY, "RETRY ", 0 },
1079 { PERF_TXN_CONFLICT, "CON ", 0 },
1080 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1081 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1082 { 0, NULL, 0 }
1083};
1084
1085int hist_entry__transaction_len(void)
1086{
1087 int i;
1088 int len = 0;
1089
1090 for (i = 0; txbits[i].name; i++) {
1091 if (!txbits[i].skip_for_len)
1092 len += strlen(txbits[i].name);
1093 }
1094 len += 4; /* :XX<space> */
1095 return len;
1096}
1097
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001098static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001099 size_t size, unsigned int width)
1100{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001101 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001102 char buf[128];
1103 char *p = buf;
1104 int i;
1105
1106 buf[0] = 0;
1107 for (i = 0; txbits[i].name; i++)
1108 if (txbits[i].flag & t)
1109 p = add_str(p, txbits[i].name);
1110 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1111 p = add_str(p, "NEITHER ");
1112 if (t & PERF_TXN_ABORT_MASK) {
1113 sprintf(p, ":%" PRIx64,
1114 (t & PERF_TXN_ABORT_MASK) >>
1115 PERF_TXN_ABORT_SHIFT);
1116 p += strlen(p);
1117 }
1118
1119 return repsep_snprintf(bf, size, "%-*s", width, buf);
1120}
1121
1122struct sort_entry sort_transaction = {
1123 .se_header = "Transaction ",
1124 .se_cmp = sort__transaction_cmp,
1125 .se_snprintf = hist_entry__transaction_snprintf,
1126 .se_width_idx = HISTC_TRANSACTION,
1127};
1128
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001129struct sort_dimension {
1130 const char *name;
1131 struct sort_entry *entry;
1132 int taken;
1133};
1134
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001135#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1136
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001137static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001138 DIM(SORT_PID, "pid", sort_thread),
1139 DIM(SORT_COMM, "comm", sort_comm),
1140 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001141 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001142 DIM(SORT_PARENT, "parent", sort_parent),
1143 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001144 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001145 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1146 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001147 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001148};
1149
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001150#undef DIM
1151
1152#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1153
1154static struct sort_dimension bstack_sort_dimensions[] = {
1155 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1156 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1157 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1158 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1159 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001160 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1161 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001162};
1163
1164#undef DIM
1165
Namhyung Kimafab87b2013-04-03 21:26:11 +09001166#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1167
1168static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001169 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1170 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1171 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1172 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1173 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1174 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001175 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001176};
1177
1178#undef DIM
1179
Namhyung Kima2ce0672014-03-04 09:06:42 +09001180struct hpp_dimension {
1181 const char *name;
1182 struct perf_hpp_fmt *fmt;
1183 int taken;
1184};
1185
1186#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1187
1188static struct hpp_dimension hpp_sort_dimensions[] = {
1189 DIM(PERF_HPP__OVERHEAD, "overhead"),
1190 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1191 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1192 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1193 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001194 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001195 DIM(PERF_HPP__SAMPLES, "sample"),
1196 DIM(PERF_HPP__PERIOD, "period"),
1197};
1198
1199#undef DIM
1200
Namhyung Kim8b536992014-03-03 11:46:55 +09001201struct hpp_sort_entry {
1202 struct perf_hpp_fmt hpp;
1203 struct sort_entry *se;
1204};
1205
Namhyung Kima7d945b2014-03-04 10:46:34 +09001206bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1207{
1208 struct hpp_sort_entry *hse_a;
1209 struct hpp_sort_entry *hse_b;
1210
1211 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1212 return false;
1213
1214 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1215 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1216
1217 return hse_a->se == hse_b->se;
1218}
1219
Namhyung Kime0d66c72014-07-31 14:47:37 +09001220void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001221{
1222 struct hpp_sort_entry *hse;
1223
1224 if (!perf_hpp__is_sort_entry(fmt))
1225 return;
1226
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001228 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001229}
1230
Namhyung Kim8b536992014-03-03 11:46:55 +09001231static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1232 struct perf_evsel *evsel)
1233{
1234 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001235 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001236
1237 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001238
Namhyung Kim5b591662014-07-31 14:47:38 +09001239 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001240 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001241
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001242 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001243}
1244
1245static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1246 struct perf_hpp *hpp __maybe_unused,
1247 struct perf_evsel *evsel)
1248{
1249 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001250 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001251
1252 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1253
Namhyung Kim5b591662014-07-31 14:47:38 +09001254 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001255 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001256
1257 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001258}
1259
1260static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1261 struct hist_entry *he)
1262{
1263 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001264 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001265
1266 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001267
1268 if (!len)
1269 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001270
1271 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1272}
1273
Namhyung Kima7d945b2014-03-04 10:46:34 +09001274static struct hpp_sort_entry *
1275__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001276{
1277 struct hpp_sort_entry *hse;
1278
1279 hse = malloc(sizeof(*hse));
1280 if (hse == NULL) {
1281 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001282 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001283 }
1284
1285 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001286 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001287 hse->hpp.header = __sort__hpp_header;
1288 hse->hpp.width = __sort__hpp_width;
1289 hse->hpp.entry = __sort__hpp_entry;
1290 hse->hpp.color = NULL;
1291
1292 hse->hpp.cmp = sd->entry->se_cmp;
1293 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001294 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001295
1296 INIT_LIST_HEAD(&hse->hpp.list);
1297 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001298 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001299 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001300 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001301
Namhyung Kima7d945b2014-03-04 10:46:34 +09001302 return hse;
1303}
1304
1305bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1306{
1307 return format->header == __sort__hpp_header;
1308}
1309
1310static int __sort_dimension__add_hpp_sort(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
Namhyung Kim8b536992014-03-03 11:46:55 +09001317 perf_hpp__register_sort_field(&hse->hpp);
1318 return 0;
1319}
1320
Namhyung Kima7d945b2014-03-04 10:46:34 +09001321static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1322{
1323 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1324
1325 if (hse == NULL)
1326 return -1;
1327
1328 perf_hpp__column_register(&hse->hpp);
1329 return 0;
1330}
1331
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001332static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001333{
1334 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001335 return 0;
1336
Namhyung Kima7d945b2014-03-04 10:46:34 +09001337 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001338 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001339
1340 if (sd->entry->se_collapse)
1341 sort__need_collapse = 1;
1342
Namhyung Kim2f532d092013-04-03 21:26:10 +09001343 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001344
1345 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001346}
1347
Namhyung Kima2ce0672014-03-04 09:06:42 +09001348static int __hpp_dimension__add(struct hpp_dimension *hd)
1349{
1350 if (!hd->taken) {
1351 hd->taken = 1;
1352
1353 perf_hpp__register_sort_field(hd->fmt);
1354 }
1355 return 0;
1356}
1357
Namhyung Kima7d945b2014-03-04 10:46:34 +09001358static int __sort_dimension__add_output(struct sort_dimension *sd)
1359{
1360 if (sd->taken)
1361 return 0;
1362
1363 if (__sort_dimension__add_hpp_output(sd) < 0)
1364 return -1;
1365
1366 sd->taken = 1;
1367 return 0;
1368}
1369
1370static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1371{
1372 if (!hd->taken) {
1373 hd->taken = 1;
1374
1375 perf_hpp__column_register(hd->fmt);
1376 }
1377 return 0;
1378}
1379
John Kacurdd68ada2009-09-24 18:02:49 +02001380int sort_dimension__add(const char *tok)
1381{
1382 unsigned int i;
1383
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001384 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1385 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001386
John Kacurdd68ada2009-09-24 18:02:49 +02001387 if (strncasecmp(tok, sd->name, strlen(tok)))
1388 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001389
John Kacurdd68ada2009-09-24 18:02:49 +02001390 if (sd->entry == &sort_parent) {
1391 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1392 if (ret) {
1393 char err[BUFSIZ];
1394
1395 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001396 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1397 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001398 }
1399 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001400 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001401 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001402 } else if (sd->entry == &sort_dso) {
1403 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001404 }
1405
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001406 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001407 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001408
Namhyung Kima2ce0672014-03-04 09:06:42 +09001409 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1410 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1411
1412 if (strncasecmp(tok, hd->name, strlen(tok)))
1413 continue;
1414
1415 return __hpp_dimension__add(hd);
1416 }
1417
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001418 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1419 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1420
1421 if (strncasecmp(tok, sd->name, strlen(tok)))
1422 continue;
1423
Namhyung Kim55369fc2013-04-01 20:35:20 +09001424 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001425 return -EINVAL;
1426
1427 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1428 sort__has_sym = 1;
1429
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001430 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001431 return 0;
1432 }
1433
Namhyung Kimafab87b2013-04-03 21:26:11 +09001434 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1435 struct sort_dimension *sd = &memory_sort_dimensions[i];
1436
1437 if (strncasecmp(tok, sd->name, strlen(tok)))
1438 continue;
1439
1440 if (sort__mode != SORT_MODE__MEMORY)
1441 return -EINVAL;
1442
1443 if (sd->entry == &sort_mem_daddr_sym)
1444 sort__has_sym = 1;
1445
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001446 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001447 return 0;
1448 }
1449
John Kacurdd68ada2009-09-24 18:02:49 +02001450 return -ESRCH;
1451}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001452
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001453static const char *get_default_sort_order(void)
1454{
1455 const char *default_sort_orders[] = {
1456 default_sort_order,
1457 default_branch_sort_order,
1458 default_mem_sort_order,
1459 default_top_sort_order,
1460 default_diff_sort_order,
1461 };
1462
1463 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1464
1465 return default_sort_orders[sort__mode];
1466}
1467
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001468static int setup_sort_order(void)
1469{
1470 char *new_sort_order;
1471
1472 /*
1473 * Append '+'-prefixed sort order to the default sort
1474 * order string.
1475 */
1476 if (!sort_order || is_strict_order(sort_order))
1477 return 0;
1478
1479 if (sort_order[1] == '\0') {
1480 error("Invalid --sort key: `+'");
1481 return -EINVAL;
1482 }
1483
1484 /*
1485 * We allocate new sort_order string, but we never free it,
1486 * because it's checked over the rest of the code.
1487 */
1488 if (asprintf(&new_sort_order, "%s,%s",
1489 get_default_sort_order(), sort_order + 1) < 0) {
1490 error("Not enough memory to set up --sort");
1491 return -ENOMEM;
1492 }
1493
1494 sort_order = new_sort_order;
1495 return 0;
1496}
1497
Namhyung Kima7d945b2014-03-04 10:46:34 +09001498static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001499{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001500 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001501 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001502 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001503
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001504 ret = setup_sort_order();
1505 if (ret)
1506 return ret;
1507
1508 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001509 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001510 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001511 /*
1512 * If user specified field order but no sort order,
1513 * we'll honor it and not add default sort orders.
1514 */
1515 return 0;
1516 }
1517
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001518 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001519 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001520
1521 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001522 if (str == NULL) {
1523 error("Not enough memory to setup sort keys");
1524 return -ENOMEM;
1525 }
1526
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001527 for (tok = strtok_r(str, ", ", &tmp);
1528 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001529 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001530 if (ret == -EINVAL) {
1531 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001532 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001533 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001534 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001535 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001536 }
1537 }
1538
1539 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001540 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001541}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001542
Jiri Olsaf2998422014-05-23 17:15:47 +02001543void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001544{
Jiri Olsaf2998422014-05-23 17:15:47 +02001545 struct perf_hpp_fmt *fmt;
1546 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001547
Jiri Olsaf2998422014-05-23 17:15:47 +02001548 perf_hpp__for_each_format(fmt) {
1549 if (!perf_hpp__is_sort_entry(fmt))
1550 continue;
1551
1552 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1553 if (hse->se->se_width_idx == idx) {
1554 fmt->elide = elide;
1555 break;
1556 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001557 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001558}
1559
Jiri Olsaf2998422014-05-23 17:15:47 +02001560static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001561{
1562 if (list && strlist__nr_entries(list) == 1) {
1563 if (fp != NULL)
1564 fprintf(fp, "# %s: %s\n", list_name,
1565 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001566 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001567 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001568 return false;
1569}
1570
1571static bool get_elide(int idx, FILE *output)
1572{
1573 switch (idx) {
1574 case HISTC_SYMBOL:
1575 return __get_elide(symbol_conf.sym_list, "symbol", output);
1576 case HISTC_DSO:
1577 return __get_elide(symbol_conf.dso_list, "dso", output);
1578 case HISTC_COMM:
1579 return __get_elide(symbol_conf.comm_list, "comm", output);
1580 default:
1581 break;
1582 }
1583
1584 if (sort__mode != SORT_MODE__BRANCH)
1585 return false;
1586
1587 switch (idx) {
1588 case HISTC_SYMBOL_FROM:
1589 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1590 case HISTC_SYMBOL_TO:
1591 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1592 case HISTC_DSO_FROM:
1593 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1594 case HISTC_DSO_TO:
1595 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1596 default:
1597 break;
1598 }
1599
1600 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001601}
Namhyung Kim08e71542013-04-03 21:26:19 +09001602
1603void sort__setup_elide(FILE *output)
1604{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001605 struct perf_hpp_fmt *fmt;
1606 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001607
Jiri Olsaf2998422014-05-23 17:15:47 +02001608 perf_hpp__for_each_format(fmt) {
1609 if (!perf_hpp__is_sort_entry(fmt))
1610 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001611
Jiri Olsaf2998422014-05-23 17:15:47 +02001612 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1613 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001614 }
1615
Namhyung Kim7524f632013-11-08 17:53:42 +09001616 /*
1617 * It makes no sense to elide all of sort entries.
1618 * Just revert them to show up again.
1619 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001620 perf_hpp__for_each_format(fmt) {
1621 if (!perf_hpp__is_sort_entry(fmt))
1622 continue;
1623
Jiri Olsaf2998422014-05-23 17:15:47 +02001624 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001625 return;
1626 }
1627
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001628 perf_hpp__for_each_format(fmt) {
1629 if (!perf_hpp__is_sort_entry(fmt))
1630 continue;
1631
Jiri Olsaf2998422014-05-23 17:15:47 +02001632 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001633 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001634}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001635
1636static int output_field_add(char *tok)
1637{
1638 unsigned int i;
1639
1640 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1641 struct sort_dimension *sd = &common_sort_dimensions[i];
1642
1643 if (strncasecmp(tok, sd->name, strlen(tok)))
1644 continue;
1645
1646 return __sort_dimension__add_output(sd);
1647 }
1648
1649 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1650 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1651
1652 if (strncasecmp(tok, hd->name, strlen(tok)))
1653 continue;
1654
1655 return __hpp_dimension__add_output(hd);
1656 }
1657
1658 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1659 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1660
1661 if (strncasecmp(tok, sd->name, strlen(tok)))
1662 continue;
1663
1664 return __sort_dimension__add_output(sd);
1665 }
1666
1667 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1668 struct sort_dimension *sd = &memory_sort_dimensions[i];
1669
1670 if (strncasecmp(tok, sd->name, strlen(tok)))
1671 continue;
1672
1673 return __sort_dimension__add_output(sd);
1674 }
1675
1676 return -ESRCH;
1677}
1678
1679static void reset_dimensions(void)
1680{
1681 unsigned int i;
1682
1683 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1684 common_sort_dimensions[i].taken = 0;
1685
1686 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1687 hpp_sort_dimensions[i].taken = 0;
1688
1689 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1690 bstack_sort_dimensions[i].taken = 0;
1691
1692 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1693 memory_sort_dimensions[i].taken = 0;
1694}
1695
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001696bool is_strict_order(const char *order)
1697{
1698 return order && (*order != '+');
1699}
1700
Namhyung Kima7d945b2014-03-04 10:46:34 +09001701static int __setup_output_field(void)
1702{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001703 char *tmp, *tok, *str, *strp;
1704 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001705
1706 if (field_order == NULL)
1707 return 0;
1708
1709 reset_dimensions();
1710
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001711 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001712 if (str == NULL) {
1713 error("Not enough memory to setup output fields");
1714 return -ENOMEM;
1715 }
1716
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001717 if (!is_strict_order(field_order))
1718 strp++;
1719
1720 if (!strlen(strp)) {
1721 error("Invalid --fields key: `+'");
1722 goto out;
1723 }
1724
1725 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001726 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1727 ret = output_field_add(tok);
1728 if (ret == -EINVAL) {
1729 error("Invalid --fields key: `%s'", tok);
1730 break;
1731 } else if (ret == -ESRCH) {
1732 error("Unknown --fields key: `%s'", tok);
1733 break;
1734 }
1735 }
1736
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001737out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001738 free(str);
1739 return ret;
1740}
1741
1742int setup_sorting(void)
1743{
1744 int err;
1745
1746 err = __setup_sorting();
1747 if (err < 0)
1748 return err;
1749
1750 if (parent_pattern != default_parent_pattern) {
1751 err = sort_dimension__add("parent");
1752 if (err < 0)
1753 return err;
1754 }
1755
1756 reset_dimensions();
1757
1758 /*
1759 * perf diff doesn't use default hpp output fields.
1760 */
1761 if (sort__mode != SORT_MODE__DIFF)
1762 perf_hpp__init();
1763
1764 err = __setup_output_field();
1765 if (err < 0)
1766 return err;
1767
1768 /* copy sort keys to output fields */
1769 perf_hpp__setup_output_field();
1770 /* and then copy output fields to sort keys */
1771 perf_hpp__append_sort_keys();
1772
1773 return 0;
1774}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001775
1776void reset_output_field(void)
1777{
1778 sort__need_collapse = 0;
1779 sort__has_parent = 0;
1780 sort__has_sym = 0;
1781 sort__has_dso = 0;
1782
Namhyung Kimd69b2962014-05-23 10:59:01 +09001783 field_order = NULL;
1784 sort_order = NULL;
1785
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001786 reset_dimensions();
1787 perf_hpp__reset_output_field();
1788}