blob: 7a9054a23c36493e6a495df21bf40f4134745d19 [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{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200390 if (!left->branch_info || !right->branch_info)
391 return cmp_null(left->branch_info, right->branch_info);
392
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393 return _sort__dso_cmp(left->branch_info->to.map,
394 right->branch_info->to.map);
395}
396
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100398 size_t size, unsigned int width)
399{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200400 if (he->branch_info)
401 return _hist_entry__dso_snprintf(he->branch_info->to.map,
402 bf, size, width);
403 else
404 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100405}
406
407static int64_t
408sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
409{
410 struct addr_map_symbol *from_l = &left->branch_info->from;
411 struct addr_map_symbol *from_r = &right->branch_info->from;
412
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200413 if (!left->branch_info || !right->branch_info)
414 return cmp_null(left->branch_info, right->branch_info);
415
416 from_l = &left->branch_info->from;
417 from_r = &right->branch_info->from;
418
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100419 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900420 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421
Namhyung Kim51f27d12013-02-06 14:57:15 +0900422 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100423}
424
425static int64_t
426sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
427{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200428 struct addr_map_symbol *to_l, *to_r;
429
430 if (!left->branch_info || !right->branch_info)
431 return cmp_null(left->branch_info, right->branch_info);
432
433 to_l = &left->branch_info->to;
434 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100435
436 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900437 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100438
Namhyung Kim51f27d12013-02-06 14:57:15 +0900439 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100440}
441
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300442static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900443 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100444{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200445 if (he->branch_info) {
446 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100447
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200448 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
449 he->level, bf, size, width);
450 }
451
452 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100453}
454
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300455static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900456 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100457{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200458 if (he->branch_info) {
459 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100460
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200461 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
462 he->level, bf, size, width);
463 }
464
465 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100466}
467
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900468struct sort_entry sort_dso_from = {
469 .se_header = "Source Shared Object",
470 .se_cmp = sort__dso_from_cmp,
471 .se_snprintf = hist_entry__dso_from_snprintf,
472 .se_width_idx = HISTC_DSO_FROM,
473};
474
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100475struct sort_entry sort_dso_to = {
476 .se_header = "Target Shared Object",
477 .se_cmp = sort__dso_to_cmp,
478 .se_snprintf = hist_entry__dso_to_snprintf,
479 .se_width_idx = HISTC_DSO_TO,
480};
481
482struct sort_entry sort_sym_from = {
483 .se_header = "Source Symbol",
484 .se_cmp = sort__sym_from_cmp,
485 .se_snprintf = hist_entry__sym_from_snprintf,
486 .se_width_idx = HISTC_SYMBOL_FROM,
487};
488
489struct sort_entry sort_sym_to = {
490 .se_header = "Target Symbol",
491 .se_cmp = sort__sym_to_cmp,
492 .se_snprintf = hist_entry__sym_to_snprintf,
493 .se_width_idx = HISTC_SYMBOL_TO,
494};
495
496static int64_t
497sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
498{
Jiri Olsa428560e2014-10-16 16:07:03 +0200499 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100500
Jiri Olsa428560e2014-10-16 16:07:03 +0200501 if (!left->branch_info || !right->branch_info)
502 return cmp_null(left->branch_info, right->branch_info);
503
504 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
505 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100506 return mp || p;
507}
508
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300509static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100510 size_t size, unsigned int width){
511 static const char *out = "N/A";
512
Jiri Olsa428560e2014-10-16 16:07:03 +0200513 if (he->branch_info) {
514 if (he->branch_info->flags.predicted)
515 out = "N";
516 else if (he->branch_info->flags.mispred)
517 out = "Y";
518 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100519
Namhyung Kim5b591662014-07-31 14:47:38 +0900520 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100521}
522
Stephane Eranian98a3b322013-01-24 16:10:35 +0100523/* --sort daddr_sym */
524static int64_t
525sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
526{
527 uint64_t l = 0, r = 0;
528
529 if (left->mem_info)
530 l = left->mem_info->daddr.addr;
531 if (right->mem_info)
532 r = right->mem_info->daddr.addr;
533
534 return (int64_t)(r - l);
535}
536
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300537static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100538 size_t size, unsigned int width)
539{
540 uint64_t addr = 0;
541 struct map *map = NULL;
542 struct symbol *sym = NULL;
543
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300544 if (he->mem_info) {
545 addr = he->mem_info->daddr.addr;
546 map = he->mem_info->daddr.map;
547 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100548 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300549 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100550 width);
551}
552
553static int64_t
554sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
555{
556 struct map *map_l = NULL;
557 struct map *map_r = NULL;
558
559 if (left->mem_info)
560 map_l = left->mem_info->daddr.map;
561 if (right->mem_info)
562 map_r = right->mem_info->daddr.map;
563
564 return _sort__dso_cmp(map_l, map_r);
565}
566
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300567static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100568 size_t size, unsigned int width)
569{
570 struct map *map = NULL;
571
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300572 if (he->mem_info)
573 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100574
575 return _hist_entry__dso_snprintf(map, bf, size, width);
576}
577
578static int64_t
579sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
580{
581 union perf_mem_data_src data_src_l;
582 union perf_mem_data_src data_src_r;
583
584 if (left->mem_info)
585 data_src_l = left->mem_info->data_src;
586 else
587 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
588
589 if (right->mem_info)
590 data_src_r = right->mem_info->data_src;
591 else
592 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
593
594 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
595}
596
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300597static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100598 size_t size, unsigned int width)
599{
600 const char *out;
601 u64 mask = PERF_MEM_LOCK_NA;
602
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300603 if (he->mem_info)
604 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100605
606 if (mask & PERF_MEM_LOCK_NA)
607 out = "N/A";
608 else if (mask & PERF_MEM_LOCK_LOCKED)
609 out = "Yes";
610 else
611 out = "No";
612
613 return repsep_snprintf(bf, size, "%-*s", width, out);
614}
615
616static int64_t
617sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
618{
619 union perf_mem_data_src data_src_l;
620 union perf_mem_data_src data_src_r;
621
622 if (left->mem_info)
623 data_src_l = left->mem_info->data_src;
624 else
625 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
626
627 if (right->mem_info)
628 data_src_r = right->mem_info->data_src;
629 else
630 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
631
632 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
633}
634
635static const char * const tlb_access[] = {
636 "N/A",
637 "HIT",
638 "MISS",
639 "L1",
640 "L2",
641 "Walker",
642 "Fault",
643};
644#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
645
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300646static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100647 size_t size, unsigned int width)
648{
649 char out[64];
650 size_t sz = sizeof(out) - 1; /* -1 for null termination */
651 size_t l = 0, i;
652 u64 m = PERF_MEM_TLB_NA;
653 u64 hit, miss;
654
655 out[0] = '\0';
656
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300657 if (he->mem_info)
658 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100659
660 hit = m & PERF_MEM_TLB_HIT;
661 miss = m & PERF_MEM_TLB_MISS;
662
663 /* already taken care of */
664 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
665
666 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
667 if (!(m & 0x1))
668 continue;
669 if (l) {
670 strcat(out, " or ");
671 l += 4;
672 }
673 strncat(out, tlb_access[i], sz - l);
674 l += strlen(tlb_access[i]);
675 }
676 if (*out == '\0')
677 strcpy(out, "N/A");
678 if (hit)
679 strncat(out, " hit", sz - l);
680 if (miss)
681 strncat(out, " miss", sz - l);
682
683 return repsep_snprintf(bf, size, "%-*s", width, out);
684}
685
686static int64_t
687sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
688{
689 union perf_mem_data_src data_src_l;
690 union perf_mem_data_src data_src_r;
691
692 if (left->mem_info)
693 data_src_l = left->mem_info->data_src;
694 else
695 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
696
697 if (right->mem_info)
698 data_src_r = right->mem_info->data_src;
699 else
700 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
701
702 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
703}
704
705static const char * const mem_lvl[] = {
706 "N/A",
707 "HIT",
708 "MISS",
709 "L1",
710 "LFB",
711 "L2",
712 "L3",
713 "Local RAM",
714 "Remote RAM (1 hop)",
715 "Remote RAM (2 hops)",
716 "Remote Cache (1 hop)",
717 "Remote Cache (2 hops)",
718 "I/O",
719 "Uncached",
720};
721#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
722
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300723static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100724 size_t size, unsigned int width)
725{
726 char out[64];
727 size_t sz = sizeof(out) - 1; /* -1 for null termination */
728 size_t i, l = 0;
729 u64 m = PERF_MEM_LVL_NA;
730 u64 hit, miss;
731
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300732 if (he->mem_info)
733 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100734
735 out[0] = '\0';
736
737 hit = m & PERF_MEM_LVL_HIT;
738 miss = m & PERF_MEM_LVL_MISS;
739
740 /* already taken care of */
741 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
742
743 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
744 if (!(m & 0x1))
745 continue;
746 if (l) {
747 strcat(out, " or ");
748 l += 4;
749 }
750 strncat(out, mem_lvl[i], sz - l);
751 l += strlen(mem_lvl[i]);
752 }
753 if (*out == '\0')
754 strcpy(out, "N/A");
755 if (hit)
756 strncat(out, " hit", sz - l);
757 if (miss)
758 strncat(out, " miss", sz - l);
759
760 return repsep_snprintf(bf, size, "%-*s", width, out);
761}
762
763static int64_t
764sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
765{
766 union perf_mem_data_src data_src_l;
767 union perf_mem_data_src data_src_r;
768
769 if (left->mem_info)
770 data_src_l = left->mem_info->data_src;
771 else
772 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
773
774 if (right->mem_info)
775 data_src_r = right->mem_info->data_src;
776 else
777 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
778
779 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
780}
781
782static const char * const snoop_access[] = {
783 "N/A",
784 "None",
785 "Miss",
786 "Hit",
787 "HitM",
788};
789#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
790
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300791static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100792 size_t size, unsigned int width)
793{
794 char out[64];
795 size_t sz = sizeof(out) - 1; /* -1 for null termination */
796 size_t i, l = 0;
797 u64 m = PERF_MEM_SNOOP_NA;
798
799 out[0] = '\0';
800
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300801 if (he->mem_info)
802 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100803
804 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
805 if (!(m & 0x1))
806 continue;
807 if (l) {
808 strcat(out, " or ");
809 l += 4;
810 }
811 strncat(out, snoop_access[i], sz - l);
812 l += strlen(snoop_access[i]);
813 }
814
815 if (*out == '\0')
816 strcpy(out, "N/A");
817
818 return repsep_snprintf(bf, size, "%-*s", width, out);
819}
820
Don Zickus9b32ba72014-06-01 15:38:29 +0200821static inline u64 cl_address(u64 address)
822{
823 /* return the cacheline of the address */
824 return (address & ~(cacheline_size - 1));
825}
826
827static int64_t
828sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
829{
830 u64 l, r;
831 struct map *l_map, *r_map;
832
833 if (!left->mem_info) return -1;
834 if (!right->mem_info) return 1;
835
836 /* group event types together */
837 if (left->cpumode > right->cpumode) return -1;
838 if (left->cpumode < right->cpumode) return 1;
839
840 l_map = left->mem_info->daddr.map;
841 r_map = right->mem_info->daddr.map;
842
843 /* if both are NULL, jump to sort on al_addr instead */
844 if (!l_map && !r_map)
845 goto addr;
846
847 if (!l_map) return -1;
848 if (!r_map) return 1;
849
850 if (l_map->maj > r_map->maj) return -1;
851 if (l_map->maj < r_map->maj) return 1;
852
853 if (l_map->min > r_map->min) return -1;
854 if (l_map->min < r_map->min) return 1;
855
856 if (l_map->ino > r_map->ino) return -1;
857 if (l_map->ino < r_map->ino) return 1;
858
859 if (l_map->ino_generation > r_map->ino_generation) return -1;
860 if (l_map->ino_generation < r_map->ino_generation) return 1;
861
862 /*
863 * Addresses with no major/minor numbers are assumed to be
864 * anonymous in userspace. Sort those on pid then address.
865 *
866 * The kernel and non-zero major/minor mapped areas are
867 * assumed to be unity mapped. Sort those on address.
868 */
869
870 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
871 (!(l_map->flags & MAP_SHARED)) &&
872 !l_map->maj && !l_map->min && !l_map->ino &&
873 !l_map->ino_generation) {
874 /* userspace anonymous */
875
876 if (left->thread->pid_ > right->thread->pid_) return -1;
877 if (left->thread->pid_ < right->thread->pid_) return 1;
878 }
879
880addr:
881 /* al_addr does all the right addr - start + offset calculations */
882 l = cl_address(left->mem_info->daddr.al_addr);
883 r = cl_address(right->mem_info->daddr.al_addr);
884
885 if (l > r) return -1;
886 if (l < r) return 1;
887
888 return 0;
889}
890
891static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
892 size_t size, unsigned int width)
893{
894
895 uint64_t addr = 0;
896 struct map *map = NULL;
897 struct symbol *sym = NULL;
898 char level = he->level;
899
900 if (he->mem_info) {
901 addr = cl_address(he->mem_info->daddr.al_addr);
902 map = he->mem_info->daddr.map;
903 sym = he->mem_info->daddr.sym;
904
905 /* print [s] for shared data mmaps */
906 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
907 map && (map->type == MAP__VARIABLE) &&
908 (map->flags & MAP_SHARED) &&
909 (map->maj || map->min || map->ino ||
910 map->ino_generation))
911 level = 's';
912 else if (!map)
913 level = 'X';
914 }
915 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
916 width);
917}
918
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100919struct sort_entry sort_mispredict = {
920 .se_header = "Branch Mispredicted",
921 .se_cmp = sort__mispredict_cmp,
922 .se_snprintf = hist_entry__mispredict_snprintf,
923 .se_width_idx = HISTC_MISPREDICT,
924};
925
Andi Kleen05484292013-01-24 16:10:29 +0100926static u64 he_weight(struct hist_entry *he)
927{
928 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
929}
930
931static int64_t
932sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
933{
934 return he_weight(left) - he_weight(right);
935}
936
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300937static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100938 size_t size, unsigned int width)
939{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300940 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100941}
942
943struct sort_entry sort_local_weight = {
944 .se_header = "Local Weight",
945 .se_cmp = sort__local_weight_cmp,
946 .se_snprintf = hist_entry__local_weight_snprintf,
947 .se_width_idx = HISTC_LOCAL_WEIGHT,
948};
949
950static int64_t
951sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
952{
953 return left->stat.weight - right->stat.weight;
954}
955
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300956static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100957 size_t size, unsigned int width)
958{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300959 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100960}
961
962struct sort_entry sort_global_weight = {
963 .se_header = "Weight",
964 .se_cmp = sort__global_weight_cmp,
965 .se_snprintf = hist_entry__global_weight_snprintf,
966 .se_width_idx = HISTC_GLOBAL_WEIGHT,
967};
968
Stephane Eranian98a3b322013-01-24 16:10:35 +0100969struct sort_entry sort_mem_daddr_sym = {
970 .se_header = "Data Symbol",
971 .se_cmp = sort__daddr_cmp,
972 .se_snprintf = hist_entry__daddr_snprintf,
973 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
974};
975
976struct sort_entry sort_mem_daddr_dso = {
977 .se_header = "Data Object",
978 .se_cmp = sort__dso_daddr_cmp,
979 .se_snprintf = hist_entry__dso_daddr_snprintf,
980 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
981};
982
983struct sort_entry sort_mem_locked = {
984 .se_header = "Locked",
985 .se_cmp = sort__locked_cmp,
986 .se_snprintf = hist_entry__locked_snprintf,
987 .se_width_idx = HISTC_MEM_LOCKED,
988};
989
990struct sort_entry sort_mem_tlb = {
991 .se_header = "TLB access",
992 .se_cmp = sort__tlb_cmp,
993 .se_snprintf = hist_entry__tlb_snprintf,
994 .se_width_idx = HISTC_MEM_TLB,
995};
996
997struct sort_entry sort_mem_lvl = {
998 .se_header = "Memory access",
999 .se_cmp = sort__lvl_cmp,
1000 .se_snprintf = hist_entry__lvl_snprintf,
1001 .se_width_idx = HISTC_MEM_LVL,
1002};
1003
1004struct sort_entry sort_mem_snoop = {
1005 .se_header = "Snoop",
1006 .se_cmp = sort__snoop_cmp,
1007 .se_snprintf = hist_entry__snoop_snprintf,
1008 .se_width_idx = HISTC_MEM_SNOOP,
1009};
1010
Don Zickus9b32ba72014-06-01 15:38:29 +02001011struct sort_entry sort_mem_dcacheline = {
1012 .se_header = "Data Cacheline",
1013 .se_cmp = sort__dcacheline_cmp,
1014 .se_snprintf = hist_entry__dcacheline_snprintf,
1015 .se_width_idx = HISTC_MEM_DCACHELINE,
1016};
1017
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001018static int64_t
1019sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1020{
Jiri Olsa49f47442014-10-16 16:07:01 +02001021 if (!left->branch_info || !right->branch_info)
1022 return cmp_null(left->branch_info, right->branch_info);
1023
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001024 return left->branch_info->flags.abort !=
1025 right->branch_info->flags.abort;
1026}
1027
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001028static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001029 size_t size, unsigned int width)
1030{
Jiri Olsa49f47442014-10-16 16:07:01 +02001031 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001032
Jiri Olsa49f47442014-10-16 16:07:01 +02001033 if (he->branch_info) {
1034 if (he->branch_info->flags.abort)
1035 out = "A";
1036 else
1037 out = ".";
1038 }
1039
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001040 return repsep_snprintf(bf, size, "%-*s", width, out);
1041}
1042
1043struct sort_entry sort_abort = {
1044 .se_header = "Transaction abort",
1045 .se_cmp = sort__abort_cmp,
1046 .se_snprintf = hist_entry__abort_snprintf,
1047 .se_width_idx = HISTC_ABORT,
1048};
1049
1050static int64_t
1051sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1052{
Jiri Olsa0199d242014-10-16 16:07:02 +02001053 if (!left->branch_info || !right->branch_info)
1054 return cmp_null(left->branch_info, right->branch_info);
1055
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001056 return left->branch_info->flags.in_tx !=
1057 right->branch_info->flags.in_tx;
1058}
1059
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001060static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001061 size_t size, unsigned int width)
1062{
Jiri Olsa0199d242014-10-16 16:07:02 +02001063 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001064
Jiri Olsa0199d242014-10-16 16:07:02 +02001065 if (he->branch_info) {
1066 if (he->branch_info->flags.in_tx)
1067 out = "T";
1068 else
1069 out = ".";
1070 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001071
1072 return repsep_snprintf(bf, size, "%-*s", width, out);
1073}
1074
1075struct sort_entry sort_in_tx = {
1076 .se_header = "Branch in transaction",
1077 .se_cmp = sort__in_tx_cmp,
1078 .se_snprintf = hist_entry__in_tx_snprintf,
1079 .se_width_idx = HISTC_IN_TX,
1080};
1081
Andi Kleen475eeab2013-09-20 07:40:43 -07001082static int64_t
1083sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1084{
1085 return left->transaction - right->transaction;
1086}
1087
1088static inline char *add_str(char *p, const char *str)
1089{
1090 strcpy(p, str);
1091 return p + strlen(str);
1092}
1093
1094static struct txbit {
1095 unsigned flag;
1096 const char *name;
1097 int skip_for_len;
1098} txbits[] = {
1099 { PERF_TXN_ELISION, "EL ", 0 },
1100 { PERF_TXN_TRANSACTION, "TX ", 1 },
1101 { PERF_TXN_SYNC, "SYNC ", 1 },
1102 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1103 { PERF_TXN_RETRY, "RETRY ", 0 },
1104 { PERF_TXN_CONFLICT, "CON ", 0 },
1105 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1106 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1107 { 0, NULL, 0 }
1108};
1109
1110int hist_entry__transaction_len(void)
1111{
1112 int i;
1113 int len = 0;
1114
1115 for (i = 0; txbits[i].name; i++) {
1116 if (!txbits[i].skip_for_len)
1117 len += strlen(txbits[i].name);
1118 }
1119 len += 4; /* :XX<space> */
1120 return len;
1121}
1122
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001123static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001124 size_t size, unsigned int width)
1125{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001126 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001127 char buf[128];
1128 char *p = buf;
1129 int i;
1130
1131 buf[0] = 0;
1132 for (i = 0; txbits[i].name; i++)
1133 if (txbits[i].flag & t)
1134 p = add_str(p, txbits[i].name);
1135 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1136 p = add_str(p, "NEITHER ");
1137 if (t & PERF_TXN_ABORT_MASK) {
1138 sprintf(p, ":%" PRIx64,
1139 (t & PERF_TXN_ABORT_MASK) >>
1140 PERF_TXN_ABORT_SHIFT);
1141 p += strlen(p);
1142 }
1143
1144 return repsep_snprintf(bf, size, "%-*s", width, buf);
1145}
1146
1147struct sort_entry sort_transaction = {
1148 .se_header = "Transaction ",
1149 .se_cmp = sort__transaction_cmp,
1150 .se_snprintf = hist_entry__transaction_snprintf,
1151 .se_width_idx = HISTC_TRANSACTION,
1152};
1153
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001154struct sort_dimension {
1155 const char *name;
1156 struct sort_entry *entry;
1157 int taken;
1158};
1159
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001160#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1161
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001162static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001163 DIM(SORT_PID, "pid", sort_thread),
1164 DIM(SORT_COMM, "comm", sort_comm),
1165 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001166 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001167 DIM(SORT_PARENT, "parent", sort_parent),
1168 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001169 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001170 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1171 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001172 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001173};
1174
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001175#undef DIM
1176
1177#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1178
1179static struct sort_dimension bstack_sort_dimensions[] = {
1180 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1181 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1182 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1183 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1184 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001185 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1186 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001187};
1188
1189#undef DIM
1190
Namhyung Kimafab87b2013-04-03 21:26:11 +09001191#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1192
1193static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001194 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1195 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1196 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1197 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1198 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1199 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001200 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001201};
1202
1203#undef DIM
1204
Namhyung Kima2ce0672014-03-04 09:06:42 +09001205struct hpp_dimension {
1206 const char *name;
1207 struct perf_hpp_fmt *fmt;
1208 int taken;
1209};
1210
1211#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1212
1213static struct hpp_dimension hpp_sort_dimensions[] = {
1214 DIM(PERF_HPP__OVERHEAD, "overhead"),
1215 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1216 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1217 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1218 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001219 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001220 DIM(PERF_HPP__SAMPLES, "sample"),
1221 DIM(PERF_HPP__PERIOD, "period"),
1222};
1223
1224#undef DIM
1225
Namhyung Kim8b536992014-03-03 11:46:55 +09001226struct hpp_sort_entry {
1227 struct perf_hpp_fmt hpp;
1228 struct sort_entry *se;
1229};
1230
Namhyung Kima7d945b2014-03-04 10:46:34 +09001231bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1232{
1233 struct hpp_sort_entry *hse_a;
1234 struct hpp_sort_entry *hse_b;
1235
1236 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1237 return false;
1238
1239 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1240 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1241
1242 return hse_a->se == hse_b->se;
1243}
1244
Namhyung Kime0d66c72014-07-31 14:47:37 +09001245void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001246{
1247 struct hpp_sort_entry *hse;
1248
1249 if (!perf_hpp__is_sort_entry(fmt))
1250 return;
1251
1252 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001253 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001254}
1255
Namhyung Kim8b536992014-03-03 11:46:55 +09001256static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1257 struct perf_evsel *evsel)
1258{
1259 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001260 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001261
1262 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001263
Namhyung Kim5b591662014-07-31 14:47:38 +09001264 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001265 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001266
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001267 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001268}
1269
1270static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1271 struct perf_hpp *hpp __maybe_unused,
1272 struct perf_evsel *evsel)
1273{
1274 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001275 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001276
1277 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1278
Namhyung Kim5b591662014-07-31 14:47:38 +09001279 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001280 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001281
1282 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001283}
1284
1285static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1286 struct hist_entry *he)
1287{
1288 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001289 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001290
1291 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001292
1293 if (!len)
1294 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001295
1296 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1297}
1298
Namhyung Kima7d945b2014-03-04 10:46:34 +09001299static struct hpp_sort_entry *
1300__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001301{
1302 struct hpp_sort_entry *hse;
1303
1304 hse = malloc(sizeof(*hse));
1305 if (hse == NULL) {
1306 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001307 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001308 }
1309
1310 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001311 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001312 hse->hpp.header = __sort__hpp_header;
1313 hse->hpp.width = __sort__hpp_width;
1314 hse->hpp.entry = __sort__hpp_entry;
1315 hse->hpp.color = NULL;
1316
1317 hse->hpp.cmp = sd->entry->se_cmp;
1318 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001319 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001320
1321 INIT_LIST_HEAD(&hse->hpp.list);
1322 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001323 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001324 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001325 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001326
Namhyung Kima7d945b2014-03-04 10:46:34 +09001327 return hse;
1328}
1329
1330bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1331{
1332 return format->header == __sort__hpp_header;
1333}
1334
1335static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1336{
1337 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1338
1339 if (hse == NULL)
1340 return -1;
1341
Namhyung Kim8b536992014-03-03 11:46:55 +09001342 perf_hpp__register_sort_field(&hse->hpp);
1343 return 0;
1344}
1345
Namhyung Kima7d945b2014-03-04 10:46:34 +09001346static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1347{
1348 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1349
1350 if (hse == NULL)
1351 return -1;
1352
1353 perf_hpp__column_register(&hse->hpp);
1354 return 0;
1355}
1356
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001357static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001358{
1359 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001360 return 0;
1361
Namhyung Kima7d945b2014-03-04 10:46:34 +09001362 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001363 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001364
1365 if (sd->entry->se_collapse)
1366 sort__need_collapse = 1;
1367
Namhyung Kim2f532d092013-04-03 21:26:10 +09001368 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001369
1370 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001371}
1372
Namhyung Kima2ce0672014-03-04 09:06:42 +09001373static int __hpp_dimension__add(struct hpp_dimension *hd)
1374{
1375 if (!hd->taken) {
1376 hd->taken = 1;
1377
1378 perf_hpp__register_sort_field(hd->fmt);
1379 }
1380 return 0;
1381}
1382
Namhyung Kima7d945b2014-03-04 10:46:34 +09001383static int __sort_dimension__add_output(struct sort_dimension *sd)
1384{
1385 if (sd->taken)
1386 return 0;
1387
1388 if (__sort_dimension__add_hpp_output(sd) < 0)
1389 return -1;
1390
1391 sd->taken = 1;
1392 return 0;
1393}
1394
1395static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1396{
1397 if (!hd->taken) {
1398 hd->taken = 1;
1399
1400 perf_hpp__column_register(hd->fmt);
1401 }
1402 return 0;
1403}
1404
John Kacurdd68ada2009-09-24 18:02:49 +02001405int sort_dimension__add(const char *tok)
1406{
1407 unsigned int i;
1408
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001409 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1410 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001411
John Kacurdd68ada2009-09-24 18:02:49 +02001412 if (strncasecmp(tok, sd->name, strlen(tok)))
1413 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001414
John Kacurdd68ada2009-09-24 18:02:49 +02001415 if (sd->entry == &sort_parent) {
1416 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1417 if (ret) {
1418 char err[BUFSIZ];
1419
1420 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001421 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1422 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001423 }
1424 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001425 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001426 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001427 } else if (sd->entry == &sort_dso) {
1428 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001429 }
1430
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001431 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001432 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001433
Namhyung Kima2ce0672014-03-04 09:06:42 +09001434 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1435 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1436
1437 if (strncasecmp(tok, hd->name, strlen(tok)))
1438 continue;
1439
1440 return __hpp_dimension__add(hd);
1441 }
1442
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001443 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1444 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1445
1446 if (strncasecmp(tok, sd->name, strlen(tok)))
1447 continue;
1448
Namhyung Kim55369fc2013-04-01 20:35:20 +09001449 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001450 return -EINVAL;
1451
1452 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1453 sort__has_sym = 1;
1454
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001455 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001456 return 0;
1457 }
1458
Namhyung Kimafab87b2013-04-03 21:26:11 +09001459 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1460 struct sort_dimension *sd = &memory_sort_dimensions[i];
1461
1462 if (strncasecmp(tok, sd->name, strlen(tok)))
1463 continue;
1464
1465 if (sort__mode != SORT_MODE__MEMORY)
1466 return -EINVAL;
1467
1468 if (sd->entry == &sort_mem_daddr_sym)
1469 sort__has_sym = 1;
1470
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001471 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001472 return 0;
1473 }
1474
John Kacurdd68ada2009-09-24 18:02:49 +02001475 return -ESRCH;
1476}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001477
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001478static const char *get_default_sort_order(void)
1479{
1480 const char *default_sort_orders[] = {
1481 default_sort_order,
1482 default_branch_sort_order,
1483 default_mem_sort_order,
1484 default_top_sort_order,
1485 default_diff_sort_order,
1486 };
1487
1488 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1489
1490 return default_sort_orders[sort__mode];
1491}
1492
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001493static int setup_sort_order(void)
1494{
1495 char *new_sort_order;
1496
1497 /*
1498 * Append '+'-prefixed sort order to the default sort
1499 * order string.
1500 */
1501 if (!sort_order || is_strict_order(sort_order))
1502 return 0;
1503
1504 if (sort_order[1] == '\0') {
1505 error("Invalid --sort key: `+'");
1506 return -EINVAL;
1507 }
1508
1509 /*
1510 * We allocate new sort_order string, but we never free it,
1511 * because it's checked over the rest of the code.
1512 */
1513 if (asprintf(&new_sort_order, "%s,%s",
1514 get_default_sort_order(), sort_order + 1) < 0) {
1515 error("Not enough memory to set up --sort");
1516 return -ENOMEM;
1517 }
1518
1519 sort_order = new_sort_order;
1520 return 0;
1521}
1522
Namhyung Kima7d945b2014-03-04 10:46:34 +09001523static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001524{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001525 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001526 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001527 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001528
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001529 ret = setup_sort_order();
1530 if (ret)
1531 return ret;
1532
1533 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001534 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001535 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001536 /*
1537 * If user specified field order but no sort order,
1538 * we'll honor it and not add default sort orders.
1539 */
1540 return 0;
1541 }
1542
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001543 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001544 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001545
1546 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001547 if (str == NULL) {
1548 error("Not enough memory to setup sort keys");
1549 return -ENOMEM;
1550 }
1551
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001552 for (tok = strtok_r(str, ", ", &tmp);
1553 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001554 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001555 if (ret == -EINVAL) {
1556 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001557 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001558 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001559 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001560 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001561 }
1562 }
1563
1564 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001565 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001566}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001567
Jiri Olsaf2998422014-05-23 17:15:47 +02001568void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001569{
Jiri Olsaf2998422014-05-23 17:15:47 +02001570 struct perf_hpp_fmt *fmt;
1571 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001572
Jiri Olsaf2998422014-05-23 17:15:47 +02001573 perf_hpp__for_each_format(fmt) {
1574 if (!perf_hpp__is_sort_entry(fmt))
1575 continue;
1576
1577 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1578 if (hse->se->se_width_idx == idx) {
1579 fmt->elide = elide;
1580 break;
1581 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001582 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001583}
1584
Jiri Olsaf2998422014-05-23 17:15:47 +02001585static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001586{
1587 if (list && strlist__nr_entries(list) == 1) {
1588 if (fp != NULL)
1589 fprintf(fp, "# %s: %s\n", list_name,
1590 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001591 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001592 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001593 return false;
1594}
1595
1596static bool get_elide(int idx, FILE *output)
1597{
1598 switch (idx) {
1599 case HISTC_SYMBOL:
1600 return __get_elide(symbol_conf.sym_list, "symbol", output);
1601 case HISTC_DSO:
1602 return __get_elide(symbol_conf.dso_list, "dso", output);
1603 case HISTC_COMM:
1604 return __get_elide(symbol_conf.comm_list, "comm", output);
1605 default:
1606 break;
1607 }
1608
1609 if (sort__mode != SORT_MODE__BRANCH)
1610 return false;
1611
1612 switch (idx) {
1613 case HISTC_SYMBOL_FROM:
1614 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1615 case HISTC_SYMBOL_TO:
1616 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1617 case HISTC_DSO_FROM:
1618 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1619 case HISTC_DSO_TO:
1620 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1621 default:
1622 break;
1623 }
1624
1625 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001626}
Namhyung Kim08e71542013-04-03 21:26:19 +09001627
1628void sort__setup_elide(FILE *output)
1629{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001630 struct perf_hpp_fmt *fmt;
1631 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001632
Jiri Olsaf2998422014-05-23 17:15:47 +02001633 perf_hpp__for_each_format(fmt) {
1634 if (!perf_hpp__is_sort_entry(fmt))
1635 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001636
Jiri Olsaf2998422014-05-23 17:15:47 +02001637 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1638 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001639 }
1640
Namhyung Kim7524f632013-11-08 17:53:42 +09001641 /*
1642 * It makes no sense to elide all of sort entries.
1643 * Just revert them to show up again.
1644 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001645 perf_hpp__for_each_format(fmt) {
1646 if (!perf_hpp__is_sort_entry(fmt))
1647 continue;
1648
Jiri Olsaf2998422014-05-23 17:15:47 +02001649 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001650 return;
1651 }
1652
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001653 perf_hpp__for_each_format(fmt) {
1654 if (!perf_hpp__is_sort_entry(fmt))
1655 continue;
1656
Jiri Olsaf2998422014-05-23 17:15:47 +02001657 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001658 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001659}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001660
1661static int output_field_add(char *tok)
1662{
1663 unsigned int i;
1664
1665 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1666 struct sort_dimension *sd = &common_sort_dimensions[i];
1667
1668 if (strncasecmp(tok, sd->name, strlen(tok)))
1669 continue;
1670
1671 return __sort_dimension__add_output(sd);
1672 }
1673
1674 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1675 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1676
1677 if (strncasecmp(tok, hd->name, strlen(tok)))
1678 continue;
1679
1680 return __hpp_dimension__add_output(hd);
1681 }
1682
1683 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1684 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1685
1686 if (strncasecmp(tok, sd->name, strlen(tok)))
1687 continue;
1688
1689 return __sort_dimension__add_output(sd);
1690 }
1691
1692 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1693 struct sort_dimension *sd = &memory_sort_dimensions[i];
1694
1695 if (strncasecmp(tok, sd->name, strlen(tok)))
1696 continue;
1697
1698 return __sort_dimension__add_output(sd);
1699 }
1700
1701 return -ESRCH;
1702}
1703
1704static void reset_dimensions(void)
1705{
1706 unsigned int i;
1707
1708 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1709 common_sort_dimensions[i].taken = 0;
1710
1711 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1712 hpp_sort_dimensions[i].taken = 0;
1713
1714 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1715 bstack_sort_dimensions[i].taken = 0;
1716
1717 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1718 memory_sort_dimensions[i].taken = 0;
1719}
1720
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001721bool is_strict_order(const char *order)
1722{
1723 return order && (*order != '+');
1724}
1725
Namhyung Kima7d945b2014-03-04 10:46:34 +09001726static int __setup_output_field(void)
1727{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001728 char *tmp, *tok, *str, *strp;
1729 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001730
1731 if (field_order == NULL)
1732 return 0;
1733
1734 reset_dimensions();
1735
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001736 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001737 if (str == NULL) {
1738 error("Not enough memory to setup output fields");
1739 return -ENOMEM;
1740 }
1741
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001742 if (!is_strict_order(field_order))
1743 strp++;
1744
1745 if (!strlen(strp)) {
1746 error("Invalid --fields key: `+'");
1747 goto out;
1748 }
1749
1750 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001751 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1752 ret = output_field_add(tok);
1753 if (ret == -EINVAL) {
1754 error("Invalid --fields key: `%s'", tok);
1755 break;
1756 } else if (ret == -ESRCH) {
1757 error("Unknown --fields key: `%s'", tok);
1758 break;
1759 }
1760 }
1761
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001762out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001763 free(str);
1764 return ret;
1765}
1766
1767int setup_sorting(void)
1768{
1769 int err;
1770
1771 err = __setup_sorting();
1772 if (err < 0)
1773 return err;
1774
1775 if (parent_pattern != default_parent_pattern) {
1776 err = sort_dimension__add("parent");
1777 if (err < 0)
1778 return err;
1779 }
1780
1781 reset_dimensions();
1782
1783 /*
1784 * perf diff doesn't use default hpp output fields.
1785 */
1786 if (sort__mode != SORT_MODE__DIFF)
1787 perf_hpp__init();
1788
1789 err = __setup_output_field();
1790 if (err < 0)
1791 return err;
1792
1793 /* copy sort keys to output fields */
1794 perf_hpp__setup_output_field();
1795 /* and then copy output fields to sort keys */
1796 perf_hpp__append_sort_keys();
1797
1798 return 0;
1799}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001800
1801void reset_output_field(void)
1802{
1803 sort__need_collapse = 0;
1804 sort__has_parent = 0;
1805 sort__has_sym = 0;
1806 sort__has_dso = 0;
1807
Namhyung Kimd69b2962014-05-23 10:59:01 +09001808 field_order = NULL;
1809 sort_order = NULL;
1810
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001811 reset_dimensions();
1812 perf_hpp__reset_output_field();
1813}