blob: 9402885a77f383674e40d54e1a543da111dc6725 [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{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200376 if (!left->branch_info || !right->branch_info)
377 return cmp_null(left->branch_info, right->branch_info);
378
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100379 return _sort__dso_cmp(left->branch_info->from.map,
380 right->branch_info->from.map);
381}
382
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300383static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100384 size_t size, unsigned int width)
385{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200386 if (he->branch_info)
387 return _hist_entry__dso_snprintf(he->branch_info->from.map,
388 bf, size, width);
389 else
390 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100391}
392
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393static int64_t
394sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
395{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200396 if (!left->branch_info || !right->branch_info)
397 return cmp_null(left->branch_info, right->branch_info);
398
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100399 return _sort__dso_cmp(left->branch_info->to.map,
400 right->branch_info->to.map);
401}
402
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300403static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100404 size_t size, unsigned int width)
405{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200406 if (he->branch_info)
407 return _hist_entry__dso_snprintf(he->branch_info->to.map,
408 bf, size, width);
409 else
410 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411}
412
413static int64_t
414sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
415{
416 struct addr_map_symbol *from_l = &left->branch_info->from;
417 struct addr_map_symbol *from_r = &right->branch_info->from;
418
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200419 if (!left->branch_info || !right->branch_info)
420 return cmp_null(left->branch_info, right->branch_info);
421
422 from_l = &left->branch_info->from;
423 from_r = &right->branch_info->from;
424
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100425 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900426 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427
Namhyung Kim51f27d12013-02-06 14:57:15 +0900428 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429}
430
431static int64_t
432sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
433{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200434 struct addr_map_symbol *to_l, *to_r;
435
436 if (!left->branch_info || !right->branch_info)
437 return cmp_null(left->branch_info, right->branch_info);
438
439 to_l = &left->branch_info->to;
440 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100441
442 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900443 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100444
Namhyung Kim51f27d12013-02-06 14:57:15 +0900445 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100446}
447
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300448static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900449 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200451 if (he->branch_info) {
452 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100453
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200454 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
455 he->level, bf, size, width);
456 }
457
458 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100459}
460
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300461static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900462 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100463{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200464 if (he->branch_info) {
465 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100466
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200467 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
468 he->level, bf, size, width);
469 }
470
471 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100472}
473
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900474struct sort_entry sort_dso_from = {
475 .se_header = "Source Shared Object",
476 .se_cmp = sort__dso_from_cmp,
477 .se_snprintf = hist_entry__dso_from_snprintf,
478 .se_width_idx = HISTC_DSO_FROM,
479};
480
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100481struct sort_entry sort_dso_to = {
482 .se_header = "Target Shared Object",
483 .se_cmp = sort__dso_to_cmp,
484 .se_snprintf = hist_entry__dso_to_snprintf,
485 .se_width_idx = HISTC_DSO_TO,
486};
487
488struct sort_entry sort_sym_from = {
489 .se_header = "Source Symbol",
490 .se_cmp = sort__sym_from_cmp,
491 .se_snprintf = hist_entry__sym_from_snprintf,
492 .se_width_idx = HISTC_SYMBOL_FROM,
493};
494
495struct sort_entry sort_sym_to = {
496 .se_header = "Target Symbol",
497 .se_cmp = sort__sym_to_cmp,
498 .se_snprintf = hist_entry__sym_to_snprintf,
499 .se_width_idx = HISTC_SYMBOL_TO,
500};
501
502static int64_t
503sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
504{
Jiri Olsa428560e2014-10-16 16:07:03 +0200505 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100506
Jiri Olsa428560e2014-10-16 16:07:03 +0200507 if (!left->branch_info || !right->branch_info)
508 return cmp_null(left->branch_info, right->branch_info);
509
510 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
511 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100512 return mp || p;
513}
514
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300515static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100516 size_t size, unsigned int width){
517 static const char *out = "N/A";
518
Jiri Olsa428560e2014-10-16 16:07:03 +0200519 if (he->branch_info) {
520 if (he->branch_info->flags.predicted)
521 out = "N";
522 else if (he->branch_info->flags.mispred)
523 out = "Y";
524 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100525
Namhyung Kim5b591662014-07-31 14:47:38 +0900526 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100527}
528
Stephane Eranian98a3b322013-01-24 16:10:35 +0100529/* --sort daddr_sym */
530static int64_t
531sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
532{
533 uint64_t l = 0, r = 0;
534
535 if (left->mem_info)
536 l = left->mem_info->daddr.addr;
537 if (right->mem_info)
538 r = right->mem_info->daddr.addr;
539
540 return (int64_t)(r - l);
541}
542
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100544 size_t size, unsigned int width)
545{
546 uint64_t addr = 0;
547 struct map *map = NULL;
548 struct symbol *sym = NULL;
549
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300550 if (he->mem_info) {
551 addr = he->mem_info->daddr.addr;
552 map = he->mem_info->daddr.map;
553 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100554 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300555 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100556 width);
557}
558
559static int64_t
560sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
561{
562 struct map *map_l = NULL;
563 struct map *map_r = NULL;
564
565 if (left->mem_info)
566 map_l = left->mem_info->daddr.map;
567 if (right->mem_info)
568 map_r = right->mem_info->daddr.map;
569
570 return _sort__dso_cmp(map_l, map_r);
571}
572
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300573static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100574 size_t size, unsigned int width)
575{
576 struct map *map = NULL;
577
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300578 if (he->mem_info)
579 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100580
581 return _hist_entry__dso_snprintf(map, bf, size, width);
582}
583
584static int64_t
585sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
586{
587 union perf_mem_data_src data_src_l;
588 union perf_mem_data_src data_src_r;
589
590 if (left->mem_info)
591 data_src_l = left->mem_info->data_src;
592 else
593 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
594
595 if (right->mem_info)
596 data_src_r = right->mem_info->data_src;
597 else
598 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
599
600 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
601}
602
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300603static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100604 size_t size, unsigned int width)
605{
606 const char *out;
607 u64 mask = PERF_MEM_LOCK_NA;
608
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300609 if (he->mem_info)
610 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100611
612 if (mask & PERF_MEM_LOCK_NA)
613 out = "N/A";
614 else if (mask & PERF_MEM_LOCK_LOCKED)
615 out = "Yes";
616 else
617 out = "No";
618
619 return repsep_snprintf(bf, size, "%-*s", width, out);
620}
621
622static int64_t
623sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
624{
625 union perf_mem_data_src data_src_l;
626 union perf_mem_data_src data_src_r;
627
628 if (left->mem_info)
629 data_src_l = left->mem_info->data_src;
630 else
631 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
632
633 if (right->mem_info)
634 data_src_r = right->mem_info->data_src;
635 else
636 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
637
638 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
639}
640
641static const char * const tlb_access[] = {
642 "N/A",
643 "HIT",
644 "MISS",
645 "L1",
646 "L2",
647 "Walker",
648 "Fault",
649};
650#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
651
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300652static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100653 size_t size, unsigned int width)
654{
655 char out[64];
656 size_t sz = sizeof(out) - 1; /* -1 for null termination */
657 size_t l = 0, i;
658 u64 m = PERF_MEM_TLB_NA;
659 u64 hit, miss;
660
661 out[0] = '\0';
662
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300663 if (he->mem_info)
664 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100665
666 hit = m & PERF_MEM_TLB_HIT;
667 miss = m & PERF_MEM_TLB_MISS;
668
669 /* already taken care of */
670 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
671
672 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
673 if (!(m & 0x1))
674 continue;
675 if (l) {
676 strcat(out, " or ");
677 l += 4;
678 }
679 strncat(out, tlb_access[i], sz - l);
680 l += strlen(tlb_access[i]);
681 }
682 if (*out == '\0')
683 strcpy(out, "N/A");
684 if (hit)
685 strncat(out, " hit", sz - l);
686 if (miss)
687 strncat(out, " miss", sz - l);
688
689 return repsep_snprintf(bf, size, "%-*s", width, out);
690}
691
692static int64_t
693sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
694{
695 union perf_mem_data_src data_src_l;
696 union perf_mem_data_src data_src_r;
697
698 if (left->mem_info)
699 data_src_l = left->mem_info->data_src;
700 else
701 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
702
703 if (right->mem_info)
704 data_src_r = right->mem_info->data_src;
705 else
706 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
707
708 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
709}
710
711static const char * const mem_lvl[] = {
712 "N/A",
713 "HIT",
714 "MISS",
715 "L1",
716 "LFB",
717 "L2",
718 "L3",
719 "Local RAM",
720 "Remote RAM (1 hop)",
721 "Remote RAM (2 hops)",
722 "Remote Cache (1 hop)",
723 "Remote Cache (2 hops)",
724 "I/O",
725 "Uncached",
726};
727#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
728
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300729static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100730 size_t size, unsigned int width)
731{
732 char out[64];
733 size_t sz = sizeof(out) - 1; /* -1 for null termination */
734 size_t i, l = 0;
735 u64 m = PERF_MEM_LVL_NA;
736 u64 hit, miss;
737
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300738 if (he->mem_info)
739 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100740
741 out[0] = '\0';
742
743 hit = m & PERF_MEM_LVL_HIT;
744 miss = m & PERF_MEM_LVL_MISS;
745
746 /* already taken care of */
747 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
748
749 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
750 if (!(m & 0x1))
751 continue;
752 if (l) {
753 strcat(out, " or ");
754 l += 4;
755 }
756 strncat(out, mem_lvl[i], sz - l);
757 l += strlen(mem_lvl[i]);
758 }
759 if (*out == '\0')
760 strcpy(out, "N/A");
761 if (hit)
762 strncat(out, " hit", sz - l);
763 if (miss)
764 strncat(out, " miss", sz - l);
765
766 return repsep_snprintf(bf, size, "%-*s", width, out);
767}
768
769static int64_t
770sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
771{
772 union perf_mem_data_src data_src_l;
773 union perf_mem_data_src data_src_r;
774
775 if (left->mem_info)
776 data_src_l = left->mem_info->data_src;
777 else
778 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
779
780 if (right->mem_info)
781 data_src_r = right->mem_info->data_src;
782 else
783 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
784
785 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
786}
787
788static const char * const snoop_access[] = {
789 "N/A",
790 "None",
791 "Miss",
792 "Hit",
793 "HitM",
794};
795#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
796
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300797static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100798 size_t size, unsigned int width)
799{
800 char out[64];
801 size_t sz = sizeof(out) - 1; /* -1 for null termination */
802 size_t i, l = 0;
803 u64 m = PERF_MEM_SNOOP_NA;
804
805 out[0] = '\0';
806
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300807 if (he->mem_info)
808 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100809
810 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
811 if (!(m & 0x1))
812 continue;
813 if (l) {
814 strcat(out, " or ");
815 l += 4;
816 }
817 strncat(out, snoop_access[i], sz - l);
818 l += strlen(snoop_access[i]);
819 }
820
821 if (*out == '\0')
822 strcpy(out, "N/A");
823
824 return repsep_snprintf(bf, size, "%-*s", width, out);
825}
826
Don Zickus9b32ba72014-06-01 15:38:29 +0200827static inline u64 cl_address(u64 address)
828{
829 /* return the cacheline of the address */
830 return (address & ~(cacheline_size - 1));
831}
832
833static int64_t
834sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
835{
836 u64 l, r;
837 struct map *l_map, *r_map;
838
839 if (!left->mem_info) return -1;
840 if (!right->mem_info) return 1;
841
842 /* group event types together */
843 if (left->cpumode > right->cpumode) return -1;
844 if (left->cpumode < right->cpumode) return 1;
845
846 l_map = left->mem_info->daddr.map;
847 r_map = right->mem_info->daddr.map;
848
849 /* if both are NULL, jump to sort on al_addr instead */
850 if (!l_map && !r_map)
851 goto addr;
852
853 if (!l_map) return -1;
854 if (!r_map) return 1;
855
856 if (l_map->maj > r_map->maj) return -1;
857 if (l_map->maj < r_map->maj) return 1;
858
859 if (l_map->min > r_map->min) return -1;
860 if (l_map->min < r_map->min) return 1;
861
862 if (l_map->ino > r_map->ino) return -1;
863 if (l_map->ino < r_map->ino) return 1;
864
865 if (l_map->ino_generation > r_map->ino_generation) return -1;
866 if (l_map->ino_generation < r_map->ino_generation) return 1;
867
868 /*
869 * Addresses with no major/minor numbers are assumed to be
870 * anonymous in userspace. Sort those on pid then address.
871 *
872 * The kernel and non-zero major/minor mapped areas are
873 * assumed to be unity mapped. Sort those on address.
874 */
875
876 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
877 (!(l_map->flags & MAP_SHARED)) &&
878 !l_map->maj && !l_map->min && !l_map->ino &&
879 !l_map->ino_generation) {
880 /* userspace anonymous */
881
882 if (left->thread->pid_ > right->thread->pid_) return -1;
883 if (left->thread->pid_ < right->thread->pid_) return 1;
884 }
885
886addr:
887 /* al_addr does all the right addr - start + offset calculations */
888 l = cl_address(left->mem_info->daddr.al_addr);
889 r = cl_address(right->mem_info->daddr.al_addr);
890
891 if (l > r) return -1;
892 if (l < r) return 1;
893
894 return 0;
895}
896
897static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
898 size_t size, unsigned int width)
899{
900
901 uint64_t addr = 0;
902 struct map *map = NULL;
903 struct symbol *sym = NULL;
904 char level = he->level;
905
906 if (he->mem_info) {
907 addr = cl_address(he->mem_info->daddr.al_addr);
908 map = he->mem_info->daddr.map;
909 sym = he->mem_info->daddr.sym;
910
911 /* print [s] for shared data mmaps */
912 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
913 map && (map->type == MAP__VARIABLE) &&
914 (map->flags & MAP_SHARED) &&
915 (map->maj || map->min || map->ino ||
916 map->ino_generation))
917 level = 's';
918 else if (!map)
919 level = 'X';
920 }
921 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
922 width);
923}
924
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100925struct sort_entry sort_mispredict = {
926 .se_header = "Branch Mispredicted",
927 .se_cmp = sort__mispredict_cmp,
928 .se_snprintf = hist_entry__mispredict_snprintf,
929 .se_width_idx = HISTC_MISPREDICT,
930};
931
Andi Kleen05484292013-01-24 16:10:29 +0100932static u64 he_weight(struct hist_entry *he)
933{
934 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
935}
936
937static int64_t
938sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
939{
940 return he_weight(left) - he_weight(right);
941}
942
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300943static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100944 size_t size, unsigned int width)
945{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300946 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100947}
948
949struct sort_entry sort_local_weight = {
950 .se_header = "Local Weight",
951 .se_cmp = sort__local_weight_cmp,
952 .se_snprintf = hist_entry__local_weight_snprintf,
953 .se_width_idx = HISTC_LOCAL_WEIGHT,
954};
955
956static int64_t
957sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
958{
959 return left->stat.weight - right->stat.weight;
960}
961
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300962static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100963 size_t size, unsigned int width)
964{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300965 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100966}
967
968struct sort_entry sort_global_weight = {
969 .se_header = "Weight",
970 .se_cmp = sort__global_weight_cmp,
971 .se_snprintf = hist_entry__global_weight_snprintf,
972 .se_width_idx = HISTC_GLOBAL_WEIGHT,
973};
974
Stephane Eranian98a3b322013-01-24 16:10:35 +0100975struct sort_entry sort_mem_daddr_sym = {
976 .se_header = "Data Symbol",
977 .se_cmp = sort__daddr_cmp,
978 .se_snprintf = hist_entry__daddr_snprintf,
979 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
980};
981
982struct sort_entry sort_mem_daddr_dso = {
983 .se_header = "Data Object",
984 .se_cmp = sort__dso_daddr_cmp,
985 .se_snprintf = hist_entry__dso_daddr_snprintf,
986 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
987};
988
989struct sort_entry sort_mem_locked = {
990 .se_header = "Locked",
991 .se_cmp = sort__locked_cmp,
992 .se_snprintf = hist_entry__locked_snprintf,
993 .se_width_idx = HISTC_MEM_LOCKED,
994};
995
996struct sort_entry sort_mem_tlb = {
997 .se_header = "TLB access",
998 .se_cmp = sort__tlb_cmp,
999 .se_snprintf = hist_entry__tlb_snprintf,
1000 .se_width_idx = HISTC_MEM_TLB,
1001};
1002
1003struct sort_entry sort_mem_lvl = {
1004 .se_header = "Memory access",
1005 .se_cmp = sort__lvl_cmp,
1006 .se_snprintf = hist_entry__lvl_snprintf,
1007 .se_width_idx = HISTC_MEM_LVL,
1008};
1009
1010struct sort_entry sort_mem_snoop = {
1011 .se_header = "Snoop",
1012 .se_cmp = sort__snoop_cmp,
1013 .se_snprintf = hist_entry__snoop_snprintf,
1014 .se_width_idx = HISTC_MEM_SNOOP,
1015};
1016
Don Zickus9b32ba72014-06-01 15:38:29 +02001017struct sort_entry sort_mem_dcacheline = {
1018 .se_header = "Data Cacheline",
1019 .se_cmp = sort__dcacheline_cmp,
1020 .se_snprintf = hist_entry__dcacheline_snprintf,
1021 .se_width_idx = HISTC_MEM_DCACHELINE,
1022};
1023
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001024static int64_t
1025sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1026{
Jiri Olsa49f47442014-10-16 16:07:01 +02001027 if (!left->branch_info || !right->branch_info)
1028 return cmp_null(left->branch_info, right->branch_info);
1029
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001030 return left->branch_info->flags.abort !=
1031 right->branch_info->flags.abort;
1032}
1033
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001034static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001035 size_t size, unsigned int width)
1036{
Jiri Olsa49f47442014-10-16 16:07:01 +02001037 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001038
Jiri Olsa49f47442014-10-16 16:07:01 +02001039 if (he->branch_info) {
1040 if (he->branch_info->flags.abort)
1041 out = "A";
1042 else
1043 out = ".";
1044 }
1045
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001046 return repsep_snprintf(bf, size, "%-*s", width, out);
1047}
1048
1049struct sort_entry sort_abort = {
1050 .se_header = "Transaction abort",
1051 .se_cmp = sort__abort_cmp,
1052 .se_snprintf = hist_entry__abort_snprintf,
1053 .se_width_idx = HISTC_ABORT,
1054};
1055
1056static int64_t
1057sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1058{
Jiri Olsa0199d242014-10-16 16:07:02 +02001059 if (!left->branch_info || !right->branch_info)
1060 return cmp_null(left->branch_info, right->branch_info);
1061
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001062 return left->branch_info->flags.in_tx !=
1063 right->branch_info->flags.in_tx;
1064}
1065
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001066static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001067 size_t size, unsigned int width)
1068{
Jiri Olsa0199d242014-10-16 16:07:02 +02001069 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001070
Jiri Olsa0199d242014-10-16 16:07:02 +02001071 if (he->branch_info) {
1072 if (he->branch_info->flags.in_tx)
1073 out = "T";
1074 else
1075 out = ".";
1076 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001077
1078 return repsep_snprintf(bf, size, "%-*s", width, out);
1079}
1080
1081struct sort_entry sort_in_tx = {
1082 .se_header = "Branch in transaction",
1083 .se_cmp = sort__in_tx_cmp,
1084 .se_snprintf = hist_entry__in_tx_snprintf,
1085 .se_width_idx = HISTC_IN_TX,
1086};
1087
Andi Kleen475eeab2013-09-20 07:40:43 -07001088static int64_t
1089sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1090{
1091 return left->transaction - right->transaction;
1092}
1093
1094static inline char *add_str(char *p, const char *str)
1095{
1096 strcpy(p, str);
1097 return p + strlen(str);
1098}
1099
1100static struct txbit {
1101 unsigned flag;
1102 const char *name;
1103 int skip_for_len;
1104} txbits[] = {
1105 { PERF_TXN_ELISION, "EL ", 0 },
1106 { PERF_TXN_TRANSACTION, "TX ", 1 },
1107 { PERF_TXN_SYNC, "SYNC ", 1 },
1108 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1109 { PERF_TXN_RETRY, "RETRY ", 0 },
1110 { PERF_TXN_CONFLICT, "CON ", 0 },
1111 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1112 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1113 { 0, NULL, 0 }
1114};
1115
1116int hist_entry__transaction_len(void)
1117{
1118 int i;
1119 int len = 0;
1120
1121 for (i = 0; txbits[i].name; i++) {
1122 if (!txbits[i].skip_for_len)
1123 len += strlen(txbits[i].name);
1124 }
1125 len += 4; /* :XX<space> */
1126 return len;
1127}
1128
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001129static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001130 size_t size, unsigned int width)
1131{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001132 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001133 char buf[128];
1134 char *p = buf;
1135 int i;
1136
1137 buf[0] = 0;
1138 for (i = 0; txbits[i].name; i++)
1139 if (txbits[i].flag & t)
1140 p = add_str(p, txbits[i].name);
1141 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1142 p = add_str(p, "NEITHER ");
1143 if (t & PERF_TXN_ABORT_MASK) {
1144 sprintf(p, ":%" PRIx64,
1145 (t & PERF_TXN_ABORT_MASK) >>
1146 PERF_TXN_ABORT_SHIFT);
1147 p += strlen(p);
1148 }
1149
1150 return repsep_snprintf(bf, size, "%-*s", width, buf);
1151}
1152
1153struct sort_entry sort_transaction = {
1154 .se_header = "Transaction ",
1155 .se_cmp = sort__transaction_cmp,
1156 .se_snprintf = hist_entry__transaction_snprintf,
1157 .se_width_idx = HISTC_TRANSACTION,
1158};
1159
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001160struct sort_dimension {
1161 const char *name;
1162 struct sort_entry *entry;
1163 int taken;
1164};
1165
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001166#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1167
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001168static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001169 DIM(SORT_PID, "pid", sort_thread),
1170 DIM(SORT_COMM, "comm", sort_comm),
1171 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001172 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001173 DIM(SORT_PARENT, "parent", sort_parent),
1174 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001175 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001176 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1177 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001178 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001179};
1180
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001181#undef DIM
1182
1183#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1184
1185static struct sort_dimension bstack_sort_dimensions[] = {
1186 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1187 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1188 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1189 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1190 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001191 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1192 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001193};
1194
1195#undef DIM
1196
Namhyung Kimafab87b2013-04-03 21:26:11 +09001197#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1198
1199static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001200 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1201 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1202 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1203 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1204 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1205 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001206 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001207};
1208
1209#undef DIM
1210
Namhyung Kima2ce0672014-03-04 09:06:42 +09001211struct hpp_dimension {
1212 const char *name;
1213 struct perf_hpp_fmt *fmt;
1214 int taken;
1215};
1216
1217#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1218
1219static struct hpp_dimension hpp_sort_dimensions[] = {
1220 DIM(PERF_HPP__OVERHEAD, "overhead"),
1221 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1222 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1223 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1224 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001225 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001226 DIM(PERF_HPP__SAMPLES, "sample"),
1227 DIM(PERF_HPP__PERIOD, "period"),
1228};
1229
1230#undef DIM
1231
Namhyung Kim8b536992014-03-03 11:46:55 +09001232struct hpp_sort_entry {
1233 struct perf_hpp_fmt hpp;
1234 struct sort_entry *se;
1235};
1236
Namhyung Kima7d945b2014-03-04 10:46:34 +09001237bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1238{
1239 struct hpp_sort_entry *hse_a;
1240 struct hpp_sort_entry *hse_b;
1241
1242 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1243 return false;
1244
1245 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1246 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1247
1248 return hse_a->se == hse_b->se;
1249}
1250
Namhyung Kime0d66c72014-07-31 14:47:37 +09001251void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001252{
1253 struct hpp_sort_entry *hse;
1254
1255 if (!perf_hpp__is_sort_entry(fmt))
1256 return;
1257
1258 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001259 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001260}
1261
Namhyung Kim8b536992014-03-03 11:46:55 +09001262static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1263 struct perf_evsel *evsel)
1264{
1265 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001266 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001267
1268 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001269
Namhyung Kim5b591662014-07-31 14:47:38 +09001270 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001271 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001272
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001273 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001274}
1275
1276static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1277 struct perf_hpp *hpp __maybe_unused,
1278 struct perf_evsel *evsel)
1279{
1280 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001281 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001282
1283 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1284
Namhyung Kim5b591662014-07-31 14:47:38 +09001285 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001286 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001287
1288 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001289}
1290
1291static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1292 struct hist_entry *he)
1293{
1294 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001295 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001296
1297 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001298
1299 if (!len)
1300 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001301
1302 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1303}
1304
Namhyung Kima7d945b2014-03-04 10:46:34 +09001305static struct hpp_sort_entry *
1306__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001307{
1308 struct hpp_sort_entry *hse;
1309
1310 hse = malloc(sizeof(*hse));
1311 if (hse == NULL) {
1312 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001313 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001314 }
1315
1316 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001317 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001318 hse->hpp.header = __sort__hpp_header;
1319 hse->hpp.width = __sort__hpp_width;
1320 hse->hpp.entry = __sort__hpp_entry;
1321 hse->hpp.color = NULL;
1322
1323 hse->hpp.cmp = sd->entry->se_cmp;
1324 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001325 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001326
1327 INIT_LIST_HEAD(&hse->hpp.list);
1328 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001329 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001330 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001331 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001332
Namhyung Kima7d945b2014-03-04 10:46:34 +09001333 return hse;
1334}
1335
1336bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1337{
1338 return format->header == __sort__hpp_header;
1339}
1340
1341static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1342{
1343 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1344
1345 if (hse == NULL)
1346 return -1;
1347
Namhyung Kim8b536992014-03-03 11:46:55 +09001348 perf_hpp__register_sort_field(&hse->hpp);
1349 return 0;
1350}
1351
Namhyung Kima7d945b2014-03-04 10:46:34 +09001352static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1353{
1354 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1355
1356 if (hse == NULL)
1357 return -1;
1358
1359 perf_hpp__column_register(&hse->hpp);
1360 return 0;
1361}
1362
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001363static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d02013-04-03 21:26:10 +09001364{
1365 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001366 return 0;
1367
Namhyung Kima7d945b2014-03-04 10:46:34 +09001368 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001369 return -1;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001370
1371 if (sd->entry->se_collapse)
1372 sort__need_collapse = 1;
1373
Namhyung Kim2f532d02013-04-03 21:26:10 +09001374 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001375
1376 return 0;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001377}
1378
Namhyung Kima2ce0672014-03-04 09:06:42 +09001379static int __hpp_dimension__add(struct hpp_dimension *hd)
1380{
1381 if (!hd->taken) {
1382 hd->taken = 1;
1383
1384 perf_hpp__register_sort_field(hd->fmt);
1385 }
1386 return 0;
1387}
1388
Namhyung Kima7d945b2014-03-04 10:46:34 +09001389static int __sort_dimension__add_output(struct sort_dimension *sd)
1390{
1391 if (sd->taken)
1392 return 0;
1393
1394 if (__sort_dimension__add_hpp_output(sd) < 0)
1395 return -1;
1396
1397 sd->taken = 1;
1398 return 0;
1399}
1400
1401static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1402{
1403 if (!hd->taken) {
1404 hd->taken = 1;
1405
1406 perf_hpp__column_register(hd->fmt);
1407 }
1408 return 0;
1409}
1410
John Kacurdd68ada2009-09-24 18:02:49 +02001411int sort_dimension__add(const char *tok)
1412{
1413 unsigned int i;
1414
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001415 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1416 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001417
John Kacurdd68ada2009-09-24 18:02:49 +02001418 if (strncasecmp(tok, sd->name, strlen(tok)))
1419 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001420
John Kacurdd68ada2009-09-24 18:02:49 +02001421 if (sd->entry == &sort_parent) {
1422 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1423 if (ret) {
1424 char err[BUFSIZ];
1425
1426 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001427 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1428 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001429 }
1430 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001431 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001432 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001433 } else if (sd->entry == &sort_dso) {
1434 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001435 }
1436
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001437 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001438 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001439
Namhyung Kima2ce0672014-03-04 09:06:42 +09001440 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1441 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1442
1443 if (strncasecmp(tok, hd->name, strlen(tok)))
1444 continue;
1445
1446 return __hpp_dimension__add(hd);
1447 }
1448
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001449 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1450 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1451
1452 if (strncasecmp(tok, sd->name, strlen(tok)))
1453 continue;
1454
Namhyung Kim55369fc2013-04-01 20:35:20 +09001455 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001456 return -EINVAL;
1457
1458 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1459 sort__has_sym = 1;
1460
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001461 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001462 return 0;
1463 }
1464
Namhyung Kimafab87b2013-04-03 21:26:11 +09001465 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1466 struct sort_dimension *sd = &memory_sort_dimensions[i];
1467
1468 if (strncasecmp(tok, sd->name, strlen(tok)))
1469 continue;
1470
1471 if (sort__mode != SORT_MODE__MEMORY)
1472 return -EINVAL;
1473
1474 if (sd->entry == &sort_mem_daddr_sym)
1475 sort__has_sym = 1;
1476
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001477 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001478 return 0;
1479 }
1480
John Kacurdd68ada2009-09-24 18:02:49 +02001481 return -ESRCH;
1482}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001483
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001484static const char *get_default_sort_order(void)
1485{
1486 const char *default_sort_orders[] = {
1487 default_sort_order,
1488 default_branch_sort_order,
1489 default_mem_sort_order,
1490 default_top_sort_order,
1491 default_diff_sort_order,
1492 };
1493
1494 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1495
1496 return default_sort_orders[sort__mode];
1497}
1498
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001499static int setup_sort_order(void)
1500{
1501 char *new_sort_order;
1502
1503 /*
1504 * Append '+'-prefixed sort order to the default sort
1505 * order string.
1506 */
1507 if (!sort_order || is_strict_order(sort_order))
1508 return 0;
1509
1510 if (sort_order[1] == '\0') {
1511 error("Invalid --sort key: `+'");
1512 return -EINVAL;
1513 }
1514
1515 /*
1516 * We allocate new sort_order string, but we never free it,
1517 * because it's checked over the rest of the code.
1518 */
1519 if (asprintf(&new_sort_order, "%s,%s",
1520 get_default_sort_order(), sort_order + 1) < 0) {
1521 error("Not enough memory to set up --sort");
1522 return -ENOMEM;
1523 }
1524
1525 sort_order = new_sort_order;
1526 return 0;
1527}
1528
Namhyung Kima7d945b2014-03-04 10:46:34 +09001529static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001530{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001531 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001532 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001533 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001534
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001535 ret = setup_sort_order();
1536 if (ret)
1537 return ret;
1538
1539 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001540 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001541 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001542 /*
1543 * If user specified field order but no sort order,
1544 * we'll honor it and not add default sort orders.
1545 */
1546 return 0;
1547 }
1548
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001549 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001550 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001551
1552 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001553 if (str == NULL) {
1554 error("Not enough memory to setup sort keys");
1555 return -ENOMEM;
1556 }
1557
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001558 for (tok = strtok_r(str, ", ", &tmp);
1559 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001560 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001561 if (ret == -EINVAL) {
1562 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001563 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001564 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001565 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001566 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001567 }
1568 }
1569
1570 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001571 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001572}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001573
Jiri Olsaf2998422014-05-23 17:15:47 +02001574void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001575{
Jiri Olsaf2998422014-05-23 17:15:47 +02001576 struct perf_hpp_fmt *fmt;
1577 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001578
Jiri Olsaf2998422014-05-23 17:15:47 +02001579 perf_hpp__for_each_format(fmt) {
1580 if (!perf_hpp__is_sort_entry(fmt))
1581 continue;
1582
1583 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1584 if (hse->se->se_width_idx == idx) {
1585 fmt->elide = elide;
1586 break;
1587 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001588 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001589}
1590
Jiri Olsaf2998422014-05-23 17:15:47 +02001591static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001592{
1593 if (list && strlist__nr_entries(list) == 1) {
1594 if (fp != NULL)
1595 fprintf(fp, "# %s: %s\n", list_name,
1596 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001597 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001598 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001599 return false;
1600}
1601
1602static bool get_elide(int idx, FILE *output)
1603{
1604 switch (idx) {
1605 case HISTC_SYMBOL:
1606 return __get_elide(symbol_conf.sym_list, "symbol", output);
1607 case HISTC_DSO:
1608 return __get_elide(symbol_conf.dso_list, "dso", output);
1609 case HISTC_COMM:
1610 return __get_elide(symbol_conf.comm_list, "comm", output);
1611 default:
1612 break;
1613 }
1614
1615 if (sort__mode != SORT_MODE__BRANCH)
1616 return false;
1617
1618 switch (idx) {
1619 case HISTC_SYMBOL_FROM:
1620 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1621 case HISTC_SYMBOL_TO:
1622 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1623 case HISTC_DSO_FROM:
1624 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1625 case HISTC_DSO_TO:
1626 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1627 default:
1628 break;
1629 }
1630
1631 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001632}
Namhyung Kim08e71542013-04-03 21:26:19 +09001633
1634void sort__setup_elide(FILE *output)
1635{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001636 struct perf_hpp_fmt *fmt;
1637 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001638
Jiri Olsaf2998422014-05-23 17:15:47 +02001639 perf_hpp__for_each_format(fmt) {
1640 if (!perf_hpp__is_sort_entry(fmt))
1641 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001642
Jiri Olsaf2998422014-05-23 17:15:47 +02001643 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1644 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001645 }
1646
Namhyung Kim7524f632013-11-08 17:53:42 +09001647 /*
1648 * It makes no sense to elide all of sort entries.
1649 * Just revert them to show up again.
1650 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001651 perf_hpp__for_each_format(fmt) {
1652 if (!perf_hpp__is_sort_entry(fmt))
1653 continue;
1654
Jiri Olsaf2998422014-05-23 17:15:47 +02001655 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001656 return;
1657 }
1658
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001659 perf_hpp__for_each_format(fmt) {
1660 if (!perf_hpp__is_sort_entry(fmt))
1661 continue;
1662
Jiri Olsaf2998422014-05-23 17:15:47 +02001663 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001664 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001665}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001666
1667static int output_field_add(char *tok)
1668{
1669 unsigned int i;
1670
1671 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1672 struct sort_dimension *sd = &common_sort_dimensions[i];
1673
1674 if (strncasecmp(tok, sd->name, strlen(tok)))
1675 continue;
1676
1677 return __sort_dimension__add_output(sd);
1678 }
1679
1680 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1681 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1682
1683 if (strncasecmp(tok, hd->name, strlen(tok)))
1684 continue;
1685
1686 return __hpp_dimension__add_output(hd);
1687 }
1688
1689 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1690 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1691
1692 if (strncasecmp(tok, sd->name, strlen(tok)))
1693 continue;
1694
1695 return __sort_dimension__add_output(sd);
1696 }
1697
1698 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1699 struct sort_dimension *sd = &memory_sort_dimensions[i];
1700
1701 if (strncasecmp(tok, sd->name, strlen(tok)))
1702 continue;
1703
1704 return __sort_dimension__add_output(sd);
1705 }
1706
1707 return -ESRCH;
1708}
1709
1710static void reset_dimensions(void)
1711{
1712 unsigned int i;
1713
1714 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1715 common_sort_dimensions[i].taken = 0;
1716
1717 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1718 hpp_sort_dimensions[i].taken = 0;
1719
1720 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1721 bstack_sort_dimensions[i].taken = 0;
1722
1723 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1724 memory_sort_dimensions[i].taken = 0;
1725}
1726
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001727bool is_strict_order(const char *order)
1728{
1729 return order && (*order != '+');
1730}
1731
Namhyung Kima7d945b2014-03-04 10:46:34 +09001732static int __setup_output_field(void)
1733{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001734 char *tmp, *tok, *str, *strp;
1735 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001736
1737 if (field_order == NULL)
1738 return 0;
1739
1740 reset_dimensions();
1741
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001742 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001743 if (str == NULL) {
1744 error("Not enough memory to setup output fields");
1745 return -ENOMEM;
1746 }
1747
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001748 if (!is_strict_order(field_order))
1749 strp++;
1750
1751 if (!strlen(strp)) {
1752 error("Invalid --fields key: `+'");
1753 goto out;
1754 }
1755
1756 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001757 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1758 ret = output_field_add(tok);
1759 if (ret == -EINVAL) {
1760 error("Invalid --fields key: `%s'", tok);
1761 break;
1762 } else if (ret == -ESRCH) {
1763 error("Unknown --fields key: `%s'", tok);
1764 break;
1765 }
1766 }
1767
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001768out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001769 free(str);
1770 return ret;
1771}
1772
1773int setup_sorting(void)
1774{
1775 int err;
1776
1777 err = __setup_sorting();
1778 if (err < 0)
1779 return err;
1780
1781 if (parent_pattern != default_parent_pattern) {
1782 err = sort_dimension__add("parent");
1783 if (err < 0)
1784 return err;
1785 }
1786
1787 reset_dimensions();
1788
1789 /*
1790 * perf diff doesn't use default hpp output fields.
1791 */
1792 if (sort__mode != SORT_MODE__DIFF)
1793 perf_hpp__init();
1794
1795 err = __setup_output_field();
1796 if (err < 0)
1797 return err;
1798
1799 /* copy sort keys to output fields */
1800 perf_hpp__setup_output_field();
1801 /* and then copy output fields to sort keys */
1802 perf_hpp__append_sort_keys();
1803
1804 return 0;
1805}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001806
1807void reset_output_field(void)
1808{
1809 sort__need_collapse = 0;
1810 sort__has_parent = 0;
1811 sort__has_sym = 0;
1812 sort__has_dso = 0;
1813
Namhyung Kimd69b2962014-05-23 10:59:01 +09001814 field_order = NULL;
1815 sort_order = NULL;
1816
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001817 reset_dimensions();
1818 perf_hpp__reset_output_field();
1819}