blob: b4a805e5e44035fe26c2689b8eb29f0f7497a791 [file] [log] [blame]
Don Zickus9b32ba72014-06-01 15:38:29 +02001#include <sys/mman.h>
John Kacurdd68ada2009-09-24 18:02:49 +02002#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03003#include "hist.h"
Namhyung Kim4dfced32013-09-13 16:28:57 +09004#include "comm.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09005#include "symbol.h"
Namhyung Kim8b536992014-03-03 11:46:55 +09006#include "evsel.h"
John Kacurdd68ada2009-09-24 18:02:49 +02007
8regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03009const char default_parent_pattern[] = "^sys_|^do_page_fault";
10const char *parent_pattern = default_parent_pattern;
11const char default_sort_order[] = "comm,dso,symbol";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090012const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090017const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080018regex_t ignore_callees_regex;
19int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020020int sort__need_collapse = 0;
21int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090022int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090023int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090024enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020025
John Kacurdd68ada2009-09-24 18:02:49 +020026
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030027static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020028{
29 int n;
30 va_list ap;
31
32 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030033 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020034 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030035 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020036
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030037 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020038 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030039 if (sep == NULL)
40 break;
41 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020042 }
John Kacurdd68ada2009-09-24 18:02:49 +020043 }
44 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110045
46 if (n >= (int)size)
47 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020048 return n;
49}
50
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020051static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020052{
53 if (!l && !r)
54 return 0;
55 else if (!l)
56 return -1;
57 else
58 return 1;
59}
60
61/* --sort pid */
62
63static int64_t
64sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
65{
Adrian Hunter38051232013-07-04 16:20:31 +030066 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020067}
68
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030069static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030070 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020071{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020072 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090073
74 width = max(7U, width) - 6;
75 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020077}
78
Frederic Weisbecker872a8782011-06-29 03:14:52 +020079struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090080 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020081 .se_cmp = sort__thread_cmp,
82 .se_snprintf = hist_entry__thread_snprintf,
83 .se_width_idx = HISTC_THREAD,
84};
85
86/* --sort comm */
87
88static int64_t
89sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
90{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020091 /* Compare the addr that should be unique among comm */
Namhyung Kim4dfced32013-09-13 16:28:57 +090092 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +020093}
94
95static int64_t
96sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97{
Namhyung Kim4dfced32013-09-13 16:28:57 +090098 /* Compare the addr that should be unique among comm */
99 return comm__str(right->comm) - comm__str(left->comm);
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200100}
101
Namhyung Kim202e7a62014-03-04 11:01:41 +0900102static int64_t
103sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104{
105 return strcmp(comm__str(right->comm), comm__str(left->comm));
106}
107
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300108static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300109 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200110{
Namhyung Kim5b591662014-07-31 14:47:38 +0900111 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200112}
113
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900114struct sort_entry sort_comm = {
115 .se_header = "Command",
116 .se_cmp = sort__comm_cmp,
117 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900118 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900119 .se_snprintf = hist_entry__comm_snprintf,
120 .se_width_idx = HISTC_COMM,
121};
122
123/* --sort dso */
124
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100125static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200126{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100127 struct dso *dso_l = map_l ? map_l->dso : NULL;
128 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300129 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200130
131 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900132 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200133
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300134 if (verbose) {
135 dso_name_l = dso_l->long_name;
136 dso_name_r = dso_r->long_name;
137 } else {
138 dso_name_l = dso_l->short_name;
139 dso_name_r = dso_r->short_name;
140 }
141
142 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200143}
144
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100145static int64_t
146sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200147{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900148 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149}
150
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100151static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 size_t size, unsigned int width)
153{
154 if (map && map->dso) {
155 const char *dso_name = !verbose ? map->dso->short_name :
156 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900157 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300158 }
John Kacurdd68ada2009-09-24 18:02:49 +0200159
Namhyung Kim5b591662014-07-31 14:47:38 +0900160 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200161}
162
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300163static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164 size_t size, unsigned int width)
165{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300166 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100167}
168
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900169struct sort_entry sort_dso = {
170 .se_header = "Shared Object",
171 .se_cmp = sort__dso_cmp,
172 .se_snprintf = hist_entry__dso_snprintf,
173 .se_width_idx = HISTC_DSO,
174};
175
176/* --sort symbol */
177
Namhyung Kim2037be52013-12-18 14:21:09 +0900178static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179{
180 return (int64_t)(right_ip - left_ip);
181}
182
Namhyung Kim51f27d12013-02-06 14:57:15 +0900183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900184{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900185 u64 ip_l, ip_r;
186
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187 if (!sym_l || !sym_r)
188 return cmp_null(sym_l, sym_r);
189
190 if (sym_l == sym_r)
191 return 0;
192
193 ip_l = sym_l->start;
194 ip_r = sym_r->start;
195
196 return (int64_t)(ip_r - ip_l);
197}
198
199static int64_t
200sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
201{
Namhyung Kim09600e02013-10-15 11:01:56 +0900202 int64_t ret;
203
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900205 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Namhyung Kim09600e02013-10-15 11:01:56 +0900207 /*
208 * comparing symbol address alone is not enough since it's a
209 * relative address within a dso.
210 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900211 if (!sort__has_dso) {
212 ret = sort__dso_cmp(left, right);
213 if (ret != 0)
214 return ret;
215 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900216
Namhyung Kim51f27d12013-02-06 14:57:15 +0900217 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900218}
219
Namhyung Kim202e7a62014-03-04 11:01:41 +0900220static int64_t
221sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
222{
223 if (!left->ms.sym || !right->ms.sym)
224 return cmp_null(left->ms.sym, right->ms.sym);
225
226 return strcmp(right->ms.sym->name, left->ms.sym->name);
227}
228
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
230 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900231 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100232{
233 size_t ret = 0;
234
235 if (verbose) {
236 char o = map ? dso__symtab_origin(map->dso) : '!';
237 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900238 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239 }
240
241 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100242 if (sym && map) {
243 if (map->type == MAP__VARIABLE) {
244 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
245 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100246 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100247 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
248 width - ret, "");
249 } else {
250 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
251 width - ret,
252 sym->name);
253 }
254 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100255 size_t len = BITS_PER_LONG / 4;
256 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
257 len, ip);
258 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259 width - ret, "");
260 }
261
Namhyung Kim5b591662014-07-31 14:47:38 +0900262 if (ret > width)
263 bf[width] = '\0';
264
265 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100266}
267
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300268static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900269 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300271 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
272 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100273}
John Kacurdd68ada2009-09-24 18:02:49 +0200274
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200275struct sort_entry sort_sym = {
276 .se_header = "Symbol",
277 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900278 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200279 .se_snprintf = hist_entry__sym_snprintf,
280 .se_width_idx = HISTC_SYMBOL,
281};
John Kacurdd68ada2009-09-24 18:02:49 +0200282
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300283/* --sort srcline */
284
285static int64_t
286sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
287{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900288 if (!left->srcline) {
289 if (!left->ms.map)
290 left->srcline = SRCLINE_UNKNOWN;
291 else {
292 struct map *map = left->ms.map;
293 left->srcline = get_srcline(map->dso,
294 map__rip_2objdump(map, left->ip));
295 }
296 }
297 if (!right->srcline) {
298 if (!right->ms.map)
299 right->srcline = SRCLINE_UNKNOWN;
300 else {
301 struct map *map = right->ms.map;
302 right->srcline = get_srcline(map->dso,
303 map__rip_2objdump(map, right->ip));
304 }
305 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900306 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300307}
308
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300309static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900310 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300311{
Namhyung Kim5b591662014-07-31 14:47:38 +0900312 return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313}
314
315struct sort_entry sort_srcline = {
316 .se_header = "Source:Line",
317 .se_cmp = sort__srcline_cmp,
318 .se_snprintf = hist_entry__srcline_snprintf,
319 .se_width_idx = HISTC_SRCLINE,
320};
321
John Kacurdd68ada2009-09-24 18:02:49 +0200322/* --sort parent */
323
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200324static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200325sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
326{
327 struct symbol *sym_l = left->parent;
328 struct symbol *sym_r = right->parent;
329
330 if (!sym_l || !sym_r)
331 return cmp_null(sym_l, sym_r);
332
Namhyung Kim202e7a62014-03-04 11:01:41 +0900333 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200334}
335
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300336static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300337 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200338{
Namhyung Kim5b591662014-07-31 14:47:38 +0900339 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300340 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200341}
342
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200343struct sort_entry sort_parent = {
344 .se_header = "Parent symbol",
345 .se_cmp = sort__parent_cmp,
346 .se_snprintf = hist_entry__parent_snprintf,
347 .se_width_idx = HISTC_PARENT,
348};
349
Arun Sharmaf60f3592010-06-04 11:27:10 -0300350/* --sort cpu */
351
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200352static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300353sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354{
355 return right->cpu - left->cpu;
356}
357
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300358static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
359 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300360{
Namhyung Kim5b591662014-07-31 14:47:38 +0900361 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300362}
363
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200364struct sort_entry sort_cpu = {
365 .se_header = "CPU",
366 .se_cmp = sort__cpu_cmp,
367 .se_snprintf = hist_entry__cpu_snprintf,
368 .se_width_idx = HISTC_CPU,
369};
370
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900371/* sort keys for branch stacks */
372
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100373static int64_t
374sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
375{
376 return _sort__dso_cmp(left->branch_info->from.map,
377 right->branch_info->from.map);
378}
379
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300380static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100381 size_t size, unsigned int width)
382{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300383 return _hist_entry__dso_snprintf(he->branch_info->from.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100384 bf, size, width);
385}
386
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100387static int64_t
388sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
389{
390 return _sort__dso_cmp(left->branch_info->to.map,
391 right->branch_info->to.map);
392}
393
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300394static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100395 size_t size, unsigned int width)
396{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397 return _hist_entry__dso_snprintf(he->branch_info->to.map,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100398 bf, size, width);
399}
400
401static int64_t
402sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
403{
404 struct addr_map_symbol *from_l = &left->branch_info->from;
405 struct addr_map_symbol *from_r = &right->branch_info->from;
406
407 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900408 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100409
Namhyung Kim51f27d12013-02-06 14:57:15 +0900410 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411}
412
413static int64_t
414sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
415{
416 struct addr_map_symbol *to_l = &left->branch_info->to;
417 struct addr_map_symbol *to_r = &right->branch_info->to;
418
419 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900420 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100421
Namhyung Kim51f27d12013-02-06 14:57:15 +0900422 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100423}
424
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300425static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900426 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300428 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300430 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100431
432}
433
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300434static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900435 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100436{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300437 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100438 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300439 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100440
441}
442
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900443struct sort_entry sort_dso_from = {
444 .se_header = "Source Shared Object",
445 .se_cmp = sort__dso_from_cmp,
446 .se_snprintf = hist_entry__dso_from_snprintf,
447 .se_width_idx = HISTC_DSO_FROM,
448};
449
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450struct sort_entry sort_dso_to = {
451 .se_header = "Target Shared Object",
452 .se_cmp = sort__dso_to_cmp,
453 .se_snprintf = hist_entry__dso_to_snprintf,
454 .se_width_idx = HISTC_DSO_TO,
455};
456
457struct sort_entry sort_sym_from = {
458 .se_header = "Source Symbol",
459 .se_cmp = sort__sym_from_cmp,
460 .se_snprintf = hist_entry__sym_from_snprintf,
461 .se_width_idx = HISTC_SYMBOL_FROM,
462};
463
464struct sort_entry sort_sym_to = {
465 .se_header = "Target Symbol",
466 .se_cmp = sort__sym_to_cmp,
467 .se_snprintf = hist_entry__sym_to_snprintf,
468 .se_width_idx = HISTC_SYMBOL_TO,
469};
470
471static int64_t
472sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
473{
474 const unsigned char mp = left->branch_info->flags.mispred !=
475 right->branch_info->flags.mispred;
476 const unsigned char p = left->branch_info->flags.predicted !=
477 right->branch_info->flags.predicted;
478
479 return mp || p;
480}
481
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300482static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100483 size_t size, unsigned int width){
484 static const char *out = "N/A";
485
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300486 if (he->branch_info->flags.predicted)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100487 out = "N";
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300488 else if (he->branch_info->flags.mispred)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100489 out = "Y";
490
Namhyung Kim5b591662014-07-31 14:47:38 +0900491 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100492}
493
Stephane Eranian98a3b322013-01-24 16:10:35 +0100494/* --sort daddr_sym */
495static int64_t
496sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
497{
498 uint64_t l = 0, r = 0;
499
500 if (left->mem_info)
501 l = left->mem_info->daddr.addr;
502 if (right->mem_info)
503 r = right->mem_info->daddr.addr;
504
505 return (int64_t)(r - l);
506}
507
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300508static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100509 size_t size, unsigned int width)
510{
511 uint64_t addr = 0;
512 struct map *map = NULL;
513 struct symbol *sym = NULL;
514
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300515 if (he->mem_info) {
516 addr = he->mem_info->daddr.addr;
517 map = he->mem_info->daddr.map;
518 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100519 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300520 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100521 width);
522}
523
524static int64_t
525sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
526{
527 struct map *map_l = NULL;
528 struct map *map_r = NULL;
529
530 if (left->mem_info)
531 map_l = left->mem_info->daddr.map;
532 if (right->mem_info)
533 map_r = right->mem_info->daddr.map;
534
535 return _sort__dso_cmp(map_l, map_r);
536}
537
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300538static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100539 size_t size, unsigned int width)
540{
541 struct map *map = NULL;
542
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543 if (he->mem_info)
544 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100545
546 return _hist_entry__dso_snprintf(map, bf, size, width);
547}
548
549static int64_t
550sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
551{
552 union perf_mem_data_src data_src_l;
553 union perf_mem_data_src data_src_r;
554
555 if (left->mem_info)
556 data_src_l = left->mem_info->data_src;
557 else
558 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
559
560 if (right->mem_info)
561 data_src_r = right->mem_info->data_src;
562 else
563 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
564
565 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
566}
567
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300568static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100569 size_t size, unsigned int width)
570{
571 const char *out;
572 u64 mask = PERF_MEM_LOCK_NA;
573
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300574 if (he->mem_info)
575 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100576
577 if (mask & PERF_MEM_LOCK_NA)
578 out = "N/A";
579 else if (mask & PERF_MEM_LOCK_LOCKED)
580 out = "Yes";
581 else
582 out = "No";
583
584 return repsep_snprintf(bf, size, "%-*s", width, out);
585}
586
587static int64_t
588sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
589{
590 union perf_mem_data_src data_src_l;
591 union perf_mem_data_src data_src_r;
592
593 if (left->mem_info)
594 data_src_l = left->mem_info->data_src;
595 else
596 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
597
598 if (right->mem_info)
599 data_src_r = right->mem_info->data_src;
600 else
601 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
602
603 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
604}
605
606static const char * const tlb_access[] = {
607 "N/A",
608 "HIT",
609 "MISS",
610 "L1",
611 "L2",
612 "Walker",
613 "Fault",
614};
615#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
616
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300617static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100618 size_t size, unsigned int width)
619{
620 char out[64];
621 size_t sz = sizeof(out) - 1; /* -1 for null termination */
622 size_t l = 0, i;
623 u64 m = PERF_MEM_TLB_NA;
624 u64 hit, miss;
625
626 out[0] = '\0';
627
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300628 if (he->mem_info)
629 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100630
631 hit = m & PERF_MEM_TLB_HIT;
632 miss = m & PERF_MEM_TLB_MISS;
633
634 /* already taken care of */
635 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
636
637 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
638 if (!(m & 0x1))
639 continue;
640 if (l) {
641 strcat(out, " or ");
642 l += 4;
643 }
644 strncat(out, tlb_access[i], sz - l);
645 l += strlen(tlb_access[i]);
646 }
647 if (*out == '\0')
648 strcpy(out, "N/A");
649 if (hit)
650 strncat(out, " hit", sz - l);
651 if (miss)
652 strncat(out, " miss", sz - l);
653
654 return repsep_snprintf(bf, size, "%-*s", width, out);
655}
656
657static int64_t
658sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
659{
660 union perf_mem_data_src data_src_l;
661 union perf_mem_data_src data_src_r;
662
663 if (left->mem_info)
664 data_src_l = left->mem_info->data_src;
665 else
666 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
667
668 if (right->mem_info)
669 data_src_r = right->mem_info->data_src;
670 else
671 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
672
673 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
674}
675
676static const char * const mem_lvl[] = {
677 "N/A",
678 "HIT",
679 "MISS",
680 "L1",
681 "LFB",
682 "L2",
683 "L3",
684 "Local RAM",
685 "Remote RAM (1 hop)",
686 "Remote RAM (2 hops)",
687 "Remote Cache (1 hop)",
688 "Remote Cache (2 hops)",
689 "I/O",
690 "Uncached",
691};
692#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
693
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300694static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100695 size_t size, unsigned int width)
696{
697 char out[64];
698 size_t sz = sizeof(out) - 1; /* -1 for null termination */
699 size_t i, l = 0;
700 u64 m = PERF_MEM_LVL_NA;
701 u64 hit, miss;
702
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300703 if (he->mem_info)
704 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100705
706 out[0] = '\0';
707
708 hit = m & PERF_MEM_LVL_HIT;
709 miss = m & PERF_MEM_LVL_MISS;
710
711 /* already taken care of */
712 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
713
714 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
715 if (!(m & 0x1))
716 continue;
717 if (l) {
718 strcat(out, " or ");
719 l += 4;
720 }
721 strncat(out, mem_lvl[i], sz - l);
722 l += strlen(mem_lvl[i]);
723 }
724 if (*out == '\0')
725 strcpy(out, "N/A");
726 if (hit)
727 strncat(out, " hit", sz - l);
728 if (miss)
729 strncat(out, " miss", sz - l);
730
731 return repsep_snprintf(bf, size, "%-*s", width, out);
732}
733
734static int64_t
735sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
736{
737 union perf_mem_data_src data_src_l;
738 union perf_mem_data_src data_src_r;
739
740 if (left->mem_info)
741 data_src_l = left->mem_info->data_src;
742 else
743 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
744
745 if (right->mem_info)
746 data_src_r = right->mem_info->data_src;
747 else
748 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
749
750 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
751}
752
753static const char * const snoop_access[] = {
754 "N/A",
755 "None",
756 "Miss",
757 "Hit",
758 "HitM",
759};
760#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
761
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300762static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100763 size_t size, unsigned int width)
764{
765 char out[64];
766 size_t sz = sizeof(out) - 1; /* -1 for null termination */
767 size_t i, l = 0;
768 u64 m = PERF_MEM_SNOOP_NA;
769
770 out[0] = '\0';
771
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300772 if (he->mem_info)
773 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100774
775 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
776 if (!(m & 0x1))
777 continue;
778 if (l) {
779 strcat(out, " or ");
780 l += 4;
781 }
782 strncat(out, snoop_access[i], sz - l);
783 l += strlen(snoop_access[i]);
784 }
785
786 if (*out == '\0')
787 strcpy(out, "N/A");
788
789 return repsep_snprintf(bf, size, "%-*s", width, out);
790}
791
Don Zickus9b32ba72014-06-01 15:38:29 +0200792static inline u64 cl_address(u64 address)
793{
794 /* return the cacheline of the address */
795 return (address & ~(cacheline_size - 1));
796}
797
798static int64_t
799sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
800{
801 u64 l, r;
802 struct map *l_map, *r_map;
803
804 if (!left->mem_info) return -1;
805 if (!right->mem_info) return 1;
806
807 /* group event types together */
808 if (left->cpumode > right->cpumode) return -1;
809 if (left->cpumode < right->cpumode) return 1;
810
811 l_map = left->mem_info->daddr.map;
812 r_map = right->mem_info->daddr.map;
813
814 /* if both are NULL, jump to sort on al_addr instead */
815 if (!l_map && !r_map)
816 goto addr;
817
818 if (!l_map) return -1;
819 if (!r_map) return 1;
820
821 if (l_map->maj > r_map->maj) return -1;
822 if (l_map->maj < r_map->maj) return 1;
823
824 if (l_map->min > r_map->min) return -1;
825 if (l_map->min < r_map->min) return 1;
826
827 if (l_map->ino > r_map->ino) return -1;
828 if (l_map->ino < r_map->ino) return 1;
829
830 if (l_map->ino_generation > r_map->ino_generation) return -1;
831 if (l_map->ino_generation < r_map->ino_generation) return 1;
832
833 /*
834 * Addresses with no major/minor numbers are assumed to be
835 * anonymous in userspace. Sort those on pid then address.
836 *
837 * The kernel and non-zero major/minor mapped areas are
838 * assumed to be unity mapped. Sort those on address.
839 */
840
841 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
842 (!(l_map->flags & MAP_SHARED)) &&
843 !l_map->maj && !l_map->min && !l_map->ino &&
844 !l_map->ino_generation) {
845 /* userspace anonymous */
846
847 if (left->thread->pid_ > right->thread->pid_) return -1;
848 if (left->thread->pid_ < right->thread->pid_) return 1;
849 }
850
851addr:
852 /* al_addr does all the right addr - start + offset calculations */
853 l = cl_address(left->mem_info->daddr.al_addr);
854 r = cl_address(right->mem_info->daddr.al_addr);
855
856 if (l > r) return -1;
857 if (l < r) return 1;
858
859 return 0;
860}
861
862static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
863 size_t size, unsigned int width)
864{
865
866 uint64_t addr = 0;
867 struct map *map = NULL;
868 struct symbol *sym = NULL;
869 char level = he->level;
870
871 if (he->mem_info) {
872 addr = cl_address(he->mem_info->daddr.al_addr);
873 map = he->mem_info->daddr.map;
874 sym = he->mem_info->daddr.sym;
875
876 /* print [s] for shared data mmaps */
877 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
878 map && (map->type == MAP__VARIABLE) &&
879 (map->flags & MAP_SHARED) &&
880 (map->maj || map->min || map->ino ||
881 map->ino_generation))
882 level = 's';
883 else if (!map)
884 level = 'X';
885 }
886 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
887 width);
888}
889
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100890struct sort_entry sort_mispredict = {
891 .se_header = "Branch Mispredicted",
892 .se_cmp = sort__mispredict_cmp,
893 .se_snprintf = hist_entry__mispredict_snprintf,
894 .se_width_idx = HISTC_MISPREDICT,
895};
896
Andi Kleen05484292013-01-24 16:10:29 +0100897static u64 he_weight(struct hist_entry *he)
898{
899 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
900}
901
902static int64_t
903sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
904{
905 return he_weight(left) - he_weight(right);
906}
907
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300908static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100909 size_t size, unsigned int width)
910{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300911 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100912}
913
914struct sort_entry sort_local_weight = {
915 .se_header = "Local Weight",
916 .se_cmp = sort__local_weight_cmp,
917 .se_snprintf = hist_entry__local_weight_snprintf,
918 .se_width_idx = HISTC_LOCAL_WEIGHT,
919};
920
921static int64_t
922sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
923{
924 return left->stat.weight - right->stat.weight;
925}
926
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300927static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100928 size_t size, unsigned int width)
929{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300930 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100931}
932
933struct sort_entry sort_global_weight = {
934 .se_header = "Weight",
935 .se_cmp = sort__global_weight_cmp,
936 .se_snprintf = hist_entry__global_weight_snprintf,
937 .se_width_idx = HISTC_GLOBAL_WEIGHT,
938};
939
Stephane Eranian98a3b322013-01-24 16:10:35 +0100940struct sort_entry sort_mem_daddr_sym = {
941 .se_header = "Data Symbol",
942 .se_cmp = sort__daddr_cmp,
943 .se_snprintf = hist_entry__daddr_snprintf,
944 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
945};
946
947struct sort_entry sort_mem_daddr_dso = {
948 .se_header = "Data Object",
949 .se_cmp = sort__dso_daddr_cmp,
950 .se_snprintf = hist_entry__dso_daddr_snprintf,
951 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
952};
953
954struct sort_entry sort_mem_locked = {
955 .se_header = "Locked",
956 .se_cmp = sort__locked_cmp,
957 .se_snprintf = hist_entry__locked_snprintf,
958 .se_width_idx = HISTC_MEM_LOCKED,
959};
960
961struct sort_entry sort_mem_tlb = {
962 .se_header = "TLB access",
963 .se_cmp = sort__tlb_cmp,
964 .se_snprintf = hist_entry__tlb_snprintf,
965 .se_width_idx = HISTC_MEM_TLB,
966};
967
968struct sort_entry sort_mem_lvl = {
969 .se_header = "Memory access",
970 .se_cmp = sort__lvl_cmp,
971 .se_snprintf = hist_entry__lvl_snprintf,
972 .se_width_idx = HISTC_MEM_LVL,
973};
974
975struct sort_entry sort_mem_snoop = {
976 .se_header = "Snoop",
977 .se_cmp = sort__snoop_cmp,
978 .se_snprintf = hist_entry__snoop_snprintf,
979 .se_width_idx = HISTC_MEM_SNOOP,
980};
981
Don Zickus9b32ba72014-06-01 15:38:29 +0200982struct sort_entry sort_mem_dcacheline = {
983 .se_header = "Data Cacheline",
984 .se_cmp = sort__dcacheline_cmp,
985 .se_snprintf = hist_entry__dcacheline_snprintf,
986 .se_width_idx = HISTC_MEM_DCACHELINE,
987};
988
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700989static int64_t
990sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
991{
992 return left->branch_info->flags.abort !=
993 right->branch_info->flags.abort;
994}
995
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300996static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -0700997 size_t size, unsigned int width)
998{
999 static const char *out = ".";
1000
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001001 if (he->branch_info->flags.abort)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001002 out = "A";
1003 return repsep_snprintf(bf, size, "%-*s", width, out);
1004}
1005
1006struct sort_entry sort_abort = {
1007 .se_header = "Transaction abort",
1008 .se_cmp = sort__abort_cmp,
1009 .se_snprintf = hist_entry__abort_snprintf,
1010 .se_width_idx = HISTC_ABORT,
1011};
1012
1013static int64_t
1014sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1015{
1016 return left->branch_info->flags.in_tx !=
1017 right->branch_info->flags.in_tx;
1018}
1019
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001020static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001021 size_t size, unsigned int width)
1022{
1023 static const char *out = ".";
1024
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001025 if (he->branch_info->flags.in_tx)
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001026 out = "T";
1027
1028 return repsep_snprintf(bf, size, "%-*s", width, out);
1029}
1030
1031struct sort_entry sort_in_tx = {
1032 .se_header = "Branch in transaction",
1033 .se_cmp = sort__in_tx_cmp,
1034 .se_snprintf = hist_entry__in_tx_snprintf,
1035 .se_width_idx = HISTC_IN_TX,
1036};
1037
Andi Kleen475eeab2013-09-20 07:40:43 -07001038static int64_t
1039sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1040{
1041 return left->transaction - right->transaction;
1042}
1043
1044static inline char *add_str(char *p, const char *str)
1045{
1046 strcpy(p, str);
1047 return p + strlen(str);
1048}
1049
1050static struct txbit {
1051 unsigned flag;
1052 const char *name;
1053 int skip_for_len;
1054} txbits[] = {
1055 { PERF_TXN_ELISION, "EL ", 0 },
1056 { PERF_TXN_TRANSACTION, "TX ", 1 },
1057 { PERF_TXN_SYNC, "SYNC ", 1 },
1058 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1059 { PERF_TXN_RETRY, "RETRY ", 0 },
1060 { PERF_TXN_CONFLICT, "CON ", 0 },
1061 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1062 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1063 { 0, NULL, 0 }
1064};
1065
1066int hist_entry__transaction_len(void)
1067{
1068 int i;
1069 int len = 0;
1070
1071 for (i = 0; txbits[i].name; i++) {
1072 if (!txbits[i].skip_for_len)
1073 len += strlen(txbits[i].name);
1074 }
1075 len += 4; /* :XX<space> */
1076 return len;
1077}
1078
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001079static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001080 size_t size, unsigned int width)
1081{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001082 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001083 char buf[128];
1084 char *p = buf;
1085 int i;
1086
1087 buf[0] = 0;
1088 for (i = 0; txbits[i].name; i++)
1089 if (txbits[i].flag & t)
1090 p = add_str(p, txbits[i].name);
1091 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1092 p = add_str(p, "NEITHER ");
1093 if (t & PERF_TXN_ABORT_MASK) {
1094 sprintf(p, ":%" PRIx64,
1095 (t & PERF_TXN_ABORT_MASK) >>
1096 PERF_TXN_ABORT_SHIFT);
1097 p += strlen(p);
1098 }
1099
1100 return repsep_snprintf(bf, size, "%-*s", width, buf);
1101}
1102
1103struct sort_entry sort_transaction = {
1104 .se_header = "Transaction ",
1105 .se_cmp = sort__transaction_cmp,
1106 .se_snprintf = hist_entry__transaction_snprintf,
1107 .se_width_idx = HISTC_TRANSACTION,
1108};
1109
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001110struct sort_dimension {
1111 const char *name;
1112 struct sort_entry *entry;
1113 int taken;
1114};
1115
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001116#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1117
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001118static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001119 DIM(SORT_PID, "pid", sort_thread),
1120 DIM(SORT_COMM, "comm", sort_comm),
1121 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001122 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001123 DIM(SORT_PARENT, "parent", sort_parent),
1124 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001125 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001126 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1127 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001128 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001129};
1130
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001131#undef DIM
1132
1133#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1134
1135static struct sort_dimension bstack_sort_dimensions[] = {
1136 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1137 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1138 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1139 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1140 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001141 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1142 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001143};
1144
1145#undef DIM
1146
Namhyung Kimafab87b2013-04-03 21:26:11 +09001147#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1148
1149static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001150 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1151 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1152 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1153 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1154 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1155 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001156 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001157};
1158
1159#undef DIM
1160
Namhyung Kima2ce0672014-03-04 09:06:42 +09001161struct hpp_dimension {
1162 const char *name;
1163 struct perf_hpp_fmt *fmt;
1164 int taken;
1165};
1166
1167#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1168
1169static struct hpp_dimension hpp_sort_dimensions[] = {
1170 DIM(PERF_HPP__OVERHEAD, "overhead"),
1171 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1172 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1173 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1174 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001175 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001176 DIM(PERF_HPP__SAMPLES, "sample"),
1177 DIM(PERF_HPP__PERIOD, "period"),
1178};
1179
1180#undef DIM
1181
Namhyung Kim8b536992014-03-03 11:46:55 +09001182struct hpp_sort_entry {
1183 struct perf_hpp_fmt hpp;
1184 struct sort_entry *se;
1185};
1186
Namhyung Kima7d945b2014-03-04 10:46:34 +09001187bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1188{
1189 struct hpp_sort_entry *hse_a;
1190 struct hpp_sort_entry *hse_b;
1191
1192 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1193 return false;
1194
1195 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1196 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1197
1198 return hse_a->se == hse_b->se;
1199}
1200
Namhyung Kime0d66c72014-07-31 14:47:37 +09001201void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001202{
1203 struct hpp_sort_entry *hse;
1204
1205 if (!perf_hpp__is_sort_entry(fmt))
1206 return;
1207
1208 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001209 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001210}
1211
Namhyung Kim8b536992014-03-03 11:46:55 +09001212static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1213 struct perf_evsel *evsel)
1214{
1215 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001216 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001217
1218 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001219
Namhyung Kim5b591662014-07-31 14:47:38 +09001220 if (!len)
1221 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1222
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001223 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001224}
1225
1226static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1227 struct perf_hpp *hpp __maybe_unused,
1228 struct perf_evsel *evsel)
1229{
1230 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001231 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001232
1233 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1234
Namhyung Kim5b591662014-07-31 14:47:38 +09001235 if (!len)
1236 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1237
1238 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001239}
1240
1241static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1242 struct hist_entry *he)
1243{
1244 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001245 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001246
1247 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001248
1249 if (!len)
1250 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001251
1252 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1253}
1254
Namhyung Kima7d945b2014-03-04 10:46:34 +09001255static struct hpp_sort_entry *
1256__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001257{
1258 struct hpp_sort_entry *hse;
1259
1260 hse = malloc(sizeof(*hse));
1261 if (hse == NULL) {
1262 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001263 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001264 }
1265
1266 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001267 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001268 hse->hpp.header = __sort__hpp_header;
1269 hse->hpp.width = __sort__hpp_width;
1270 hse->hpp.entry = __sort__hpp_entry;
1271 hse->hpp.color = NULL;
1272
1273 hse->hpp.cmp = sd->entry->se_cmp;
1274 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
Namhyung Kim202e7a62014-03-04 11:01:41 +09001275 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
Namhyung Kim8b536992014-03-03 11:46:55 +09001276
1277 INIT_LIST_HEAD(&hse->hpp.list);
1278 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001279 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001280 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001281 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001282
Namhyung Kima7d945b2014-03-04 10:46:34 +09001283 return hse;
1284}
1285
1286bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1287{
1288 return format->header == __sort__hpp_header;
1289}
1290
1291static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1292{
1293 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1294
1295 if (hse == NULL)
1296 return -1;
1297
Namhyung Kim8b536992014-03-03 11:46:55 +09001298 perf_hpp__register_sort_field(&hse->hpp);
1299 return 0;
1300}
1301
Namhyung Kima7d945b2014-03-04 10:46:34 +09001302static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1303{
1304 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1305
1306 if (hse == NULL)
1307 return -1;
1308
1309 perf_hpp__column_register(&hse->hpp);
1310 return 0;
1311}
1312
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001313static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001314{
1315 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001316 return 0;
1317
Namhyung Kima7d945b2014-03-04 10:46:34 +09001318 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001319 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001320
1321 if (sd->entry->se_collapse)
1322 sort__need_collapse = 1;
1323
Namhyung Kim2f532d092013-04-03 21:26:10 +09001324 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001325
1326 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001327}
1328
Namhyung Kima2ce0672014-03-04 09:06:42 +09001329static int __hpp_dimension__add(struct hpp_dimension *hd)
1330{
1331 if (!hd->taken) {
1332 hd->taken = 1;
1333
1334 perf_hpp__register_sort_field(hd->fmt);
1335 }
1336 return 0;
1337}
1338
Namhyung Kima7d945b2014-03-04 10:46:34 +09001339static int __sort_dimension__add_output(struct sort_dimension *sd)
1340{
1341 if (sd->taken)
1342 return 0;
1343
1344 if (__sort_dimension__add_hpp_output(sd) < 0)
1345 return -1;
1346
1347 sd->taken = 1;
1348 return 0;
1349}
1350
1351static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1352{
1353 if (!hd->taken) {
1354 hd->taken = 1;
1355
1356 perf_hpp__column_register(hd->fmt);
1357 }
1358 return 0;
1359}
1360
John Kacurdd68ada2009-09-24 18:02:49 +02001361int sort_dimension__add(const char *tok)
1362{
1363 unsigned int i;
1364
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001365 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1366 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001367
John Kacurdd68ada2009-09-24 18:02:49 +02001368 if (strncasecmp(tok, sd->name, strlen(tok)))
1369 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001370
John Kacurdd68ada2009-09-24 18:02:49 +02001371 if (sd->entry == &sort_parent) {
1372 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1373 if (ret) {
1374 char err[BUFSIZ];
1375
1376 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001377 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1378 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001379 }
1380 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001381 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001382 sort__has_sym = 1;
Namhyung Kim68f6d022013-12-18 14:21:10 +09001383 } else if (sd->entry == &sort_dso) {
1384 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001385 }
1386
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001387 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001388 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001389
Namhyung Kima2ce0672014-03-04 09:06:42 +09001390 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1391 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1392
1393 if (strncasecmp(tok, hd->name, strlen(tok)))
1394 continue;
1395
1396 return __hpp_dimension__add(hd);
1397 }
1398
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001399 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1400 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1401
1402 if (strncasecmp(tok, sd->name, strlen(tok)))
1403 continue;
1404
Namhyung Kim55369fc2013-04-01 20:35:20 +09001405 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001406 return -EINVAL;
1407
1408 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1409 sort__has_sym = 1;
1410
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001411 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001412 return 0;
1413 }
1414
Namhyung Kimafab87b2013-04-03 21:26:11 +09001415 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1416 struct sort_dimension *sd = &memory_sort_dimensions[i];
1417
1418 if (strncasecmp(tok, sd->name, strlen(tok)))
1419 continue;
1420
1421 if (sort__mode != SORT_MODE__MEMORY)
1422 return -EINVAL;
1423
1424 if (sd->entry == &sort_mem_daddr_sym)
1425 sort__has_sym = 1;
1426
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001427 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001428 return 0;
1429 }
1430
John Kacurdd68ada2009-09-24 18:02:49 +02001431 return -ESRCH;
1432}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001433
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001434static const char *get_default_sort_order(void)
1435{
1436 const char *default_sort_orders[] = {
1437 default_sort_order,
1438 default_branch_sort_order,
1439 default_mem_sort_order,
1440 default_top_sort_order,
1441 default_diff_sort_order,
1442 };
1443
1444 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1445
1446 return default_sort_orders[sort__mode];
1447}
1448
Namhyung Kima7d945b2014-03-04 10:46:34 +09001449static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001450{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001451 char *tmp, *tok, *str;
1452 const char *sort_keys = sort_order;
Namhyung Kim55309982013-02-06 14:57:16 +09001453 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001454
Namhyung Kima7d945b2014-03-04 10:46:34 +09001455 if (sort_keys == NULL) {
1456 if (field_order) {
1457 /*
1458 * If user specified field order but no sort order,
1459 * we'll honor it and not add default sort orders.
1460 */
1461 return 0;
1462 }
1463
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001464 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001465 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001466
1467 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001468 if (str == NULL) {
1469 error("Not enough memory to setup sort keys");
1470 return -ENOMEM;
1471 }
1472
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001473 for (tok = strtok_r(str, ", ", &tmp);
1474 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001475 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001476 if (ret == -EINVAL) {
1477 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001478 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001479 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001480 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001481 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001482 }
1483 }
1484
1485 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001486 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001487}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001488
Jiri Olsaf2998422014-05-23 17:15:47 +02001489void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001490{
Jiri Olsaf2998422014-05-23 17:15:47 +02001491 struct perf_hpp_fmt *fmt;
1492 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001493
Jiri Olsaf2998422014-05-23 17:15:47 +02001494 perf_hpp__for_each_format(fmt) {
1495 if (!perf_hpp__is_sort_entry(fmt))
1496 continue;
1497
1498 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1499 if (hse->se->se_width_idx == idx) {
1500 fmt->elide = elide;
1501 break;
1502 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001503 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001504}
1505
Jiri Olsaf2998422014-05-23 17:15:47 +02001506static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001507{
1508 if (list && strlist__nr_entries(list) == 1) {
1509 if (fp != NULL)
1510 fprintf(fp, "# %s: %s\n", list_name,
1511 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001512 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001513 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001514 return false;
1515}
1516
1517static bool get_elide(int idx, FILE *output)
1518{
1519 switch (idx) {
1520 case HISTC_SYMBOL:
1521 return __get_elide(symbol_conf.sym_list, "symbol", output);
1522 case HISTC_DSO:
1523 return __get_elide(symbol_conf.dso_list, "dso", output);
1524 case HISTC_COMM:
1525 return __get_elide(symbol_conf.comm_list, "comm", output);
1526 default:
1527 break;
1528 }
1529
1530 if (sort__mode != SORT_MODE__BRANCH)
1531 return false;
1532
1533 switch (idx) {
1534 case HISTC_SYMBOL_FROM:
1535 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1536 case HISTC_SYMBOL_TO:
1537 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1538 case HISTC_DSO_FROM:
1539 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1540 case HISTC_DSO_TO:
1541 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1542 default:
1543 break;
1544 }
1545
1546 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001547}
Namhyung Kim08e71542013-04-03 21:26:19 +09001548
1549void sort__setup_elide(FILE *output)
1550{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001551 struct perf_hpp_fmt *fmt;
1552 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001553
Jiri Olsaf2998422014-05-23 17:15:47 +02001554 perf_hpp__for_each_format(fmt) {
1555 if (!perf_hpp__is_sort_entry(fmt))
1556 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001557
Jiri Olsaf2998422014-05-23 17:15:47 +02001558 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1559 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001560 }
1561
Namhyung Kim7524f632013-11-08 17:53:42 +09001562 /*
1563 * It makes no sense to elide all of sort entries.
1564 * Just revert them to show up again.
1565 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001566 perf_hpp__for_each_format(fmt) {
1567 if (!perf_hpp__is_sort_entry(fmt))
1568 continue;
1569
Jiri Olsaf2998422014-05-23 17:15:47 +02001570 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001571 return;
1572 }
1573
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001574 perf_hpp__for_each_format(fmt) {
1575 if (!perf_hpp__is_sort_entry(fmt))
1576 continue;
1577
Jiri Olsaf2998422014-05-23 17:15:47 +02001578 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001579 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001580}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001581
1582static int output_field_add(char *tok)
1583{
1584 unsigned int i;
1585
1586 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1587 struct sort_dimension *sd = &common_sort_dimensions[i];
1588
1589 if (strncasecmp(tok, sd->name, strlen(tok)))
1590 continue;
1591
1592 return __sort_dimension__add_output(sd);
1593 }
1594
1595 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1596 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1597
1598 if (strncasecmp(tok, hd->name, strlen(tok)))
1599 continue;
1600
1601 return __hpp_dimension__add_output(hd);
1602 }
1603
1604 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1605 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1606
1607 if (strncasecmp(tok, sd->name, strlen(tok)))
1608 continue;
1609
1610 return __sort_dimension__add_output(sd);
1611 }
1612
1613 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1614 struct sort_dimension *sd = &memory_sort_dimensions[i];
1615
1616 if (strncasecmp(tok, sd->name, strlen(tok)))
1617 continue;
1618
1619 return __sort_dimension__add_output(sd);
1620 }
1621
1622 return -ESRCH;
1623}
1624
1625static void reset_dimensions(void)
1626{
1627 unsigned int i;
1628
1629 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1630 common_sort_dimensions[i].taken = 0;
1631
1632 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1633 hpp_sort_dimensions[i].taken = 0;
1634
1635 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1636 bstack_sort_dimensions[i].taken = 0;
1637
1638 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1639 memory_sort_dimensions[i].taken = 0;
1640}
1641
1642static int __setup_output_field(void)
1643{
1644 char *tmp, *tok, *str;
1645 int ret = 0;
1646
1647 if (field_order == NULL)
1648 return 0;
1649
1650 reset_dimensions();
1651
1652 str = strdup(field_order);
1653 if (str == NULL) {
1654 error("Not enough memory to setup output fields");
1655 return -ENOMEM;
1656 }
1657
1658 for (tok = strtok_r(str, ", ", &tmp);
1659 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1660 ret = output_field_add(tok);
1661 if (ret == -EINVAL) {
1662 error("Invalid --fields key: `%s'", tok);
1663 break;
1664 } else if (ret == -ESRCH) {
1665 error("Unknown --fields key: `%s'", tok);
1666 break;
1667 }
1668 }
1669
1670 free(str);
1671 return ret;
1672}
1673
1674int setup_sorting(void)
1675{
1676 int err;
1677
1678 err = __setup_sorting();
1679 if (err < 0)
1680 return err;
1681
1682 if (parent_pattern != default_parent_pattern) {
1683 err = sort_dimension__add("parent");
1684 if (err < 0)
1685 return err;
1686 }
1687
1688 reset_dimensions();
1689
1690 /*
1691 * perf diff doesn't use default hpp output fields.
1692 */
1693 if (sort__mode != SORT_MODE__DIFF)
1694 perf_hpp__init();
1695
1696 err = __setup_output_field();
1697 if (err < 0)
1698 return err;
1699
1700 /* copy sort keys to output fields */
1701 perf_hpp__setup_output_field();
1702 /* and then copy output fields to sort keys */
1703 perf_hpp__append_sort_keys();
1704
1705 return 0;
1706}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001707
1708void reset_output_field(void)
1709{
1710 sort__need_collapse = 0;
1711 sort__has_parent = 0;
1712 sort__has_sym = 0;
1713 sort__has_dso = 0;
1714
Namhyung Kimd69b2962014-05-23 10:59:01 +09001715 field_order = NULL;
1716 sort_order = NULL;
1717
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001718 reset_dimensions();
1719 perf_hpp__reset_output_field();
1720}