blob: 4c65a143a34c96747ab7c6d39284f264f0f8d41e [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 */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020092 return strcmp(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 */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020099 return strcmp(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{
185 if (!sym_l || !sym_r)
186 return cmp_null(sym_l, sym_r);
187
188 if (sym_l == sym_r)
189 return 0;
190
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700191 if (sym_l->start != sym_r->start)
192 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900193
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700194 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900195}
196
197static int64_t
198sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
199{
Namhyung Kim09600e02013-10-15 11:01:56 +0900200 int64_t ret;
201
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900202 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900203 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204
Namhyung Kim09600e02013-10-15 11:01:56 +0900205 /*
206 * comparing symbol address alone is not enough since it's a
207 * relative address within a dso.
208 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900209 if (!sort__has_dso) {
210 ret = sort__dso_cmp(left, right);
211 if (ret != 0)
212 return ret;
213 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900214
Namhyung Kim51f27d12013-02-06 14:57:15 +0900215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900216}
217
Namhyung Kim202e7a62014-03-04 11:01:41 +0900218static int64_t
219sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220{
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
223
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
225}
226
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100227static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
228 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900229 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100230{
231 size_t ret = 0;
232
233 if (verbose) {
234 char o = map ? dso__symtab_origin(map->dso) : '!';
235 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900236 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100237 }
238
239 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100240 if (sym && map) {
241 if (map->type == MAP__VARIABLE) {
242 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
243 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100244 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100245 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
246 width - ret, "");
247 } else {
248 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
249 width - ret,
250 sym->name);
251 }
252 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100253 size_t len = BITS_PER_LONG / 4;
254 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
255 len, ip);
256 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
257 width - ret, "");
258 }
259
Namhyung Kim5b591662014-07-31 14:47:38 +0900260 if (ret > width)
261 bf[width] = '\0';
262
263 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100264}
265
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300266static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900267 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100268{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300269 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
270 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100271}
John Kacurdd68ada2009-09-24 18:02:49 +0200272
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200273struct sort_entry sort_sym = {
274 .se_header = "Symbol",
275 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900276 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200277 .se_snprintf = hist_entry__sym_snprintf,
278 .se_width_idx = HISTC_SYMBOL,
279};
John Kacurdd68ada2009-09-24 18:02:49 +0200280
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300281/* --sort srcline */
282
283static int64_t
284sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
285{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900286 if (!left->srcline) {
287 if (!left->ms.map)
288 left->srcline = SRCLINE_UNKNOWN;
289 else {
290 struct map *map = left->ms.map;
291 left->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800292 map__rip_2objdump(map, left->ip),
293 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900294 }
295 }
296 if (!right->srcline) {
297 if (!right->ms.map)
298 right->srcline = SRCLINE_UNKNOWN;
299 else {
300 struct map *map = right->ms.map;
301 right->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800302 map__rip_2objdump(map, right->ip),
303 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900304 }
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{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300312 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313}
314
315struct sort_entry sort_srcline = {
316 .se_header = "Source:Line",
317 .se_cmp = sort__srcline_cmp,
318 .se_snprintf = hist_entry__srcline_snprintf,
319 .se_width_idx = HISTC_SRCLINE,
320};
321
John Kacurdd68ada2009-09-24 18:02:49 +0200322/* --sort parent */
323
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200324static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200325sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
326{
327 struct symbol *sym_l = left->parent;
328 struct symbol *sym_r = right->parent;
329
330 if (!sym_l || !sym_r)
331 return cmp_null(sym_l, sym_r);
332
Namhyung Kim202e7a62014-03-04 11:01:41 +0900333 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200334}
335
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300336static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300337 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200338{
Namhyung Kim5b591662014-07-31 14:47:38 +0900339 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300340 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200341}
342
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200343struct sort_entry sort_parent = {
344 .se_header = "Parent symbol",
345 .se_cmp = sort__parent_cmp,
346 .se_snprintf = hist_entry__parent_snprintf,
347 .se_width_idx = HISTC_PARENT,
348};
349
Arun Sharmaf60f3592010-06-04 11:27:10 -0300350/* --sort cpu */
351
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200352static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300353sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
354{
355 return right->cpu - left->cpu;
356}
357
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300358static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
359 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300360{
Namhyung Kim5b591662014-07-31 14:47:38 +0900361 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300362}
363
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200364struct sort_entry sort_cpu = {
365 .se_header = "CPU",
366 .se_cmp = sort__cpu_cmp,
367 .se_snprintf = hist_entry__cpu_snprintf,
368 .se_width_idx = HISTC_CPU,
369};
370
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900371/* sort keys for branch stacks */
372
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100373static int64_t
374sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
375{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200376 if (!left->branch_info || !right->branch_info)
377 return cmp_null(left->branch_info, right->branch_info);
378
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100379 return _sort__dso_cmp(left->branch_info->from.map,
380 right->branch_info->from.map);
381}
382
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300383static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100384 size_t size, unsigned int width)
385{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200386 if (he->branch_info)
387 return _hist_entry__dso_snprintf(he->branch_info->from.map,
388 bf, size, width);
389 else
390 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100391}
392
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393static int64_t
394sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
395{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200396 if (!left->branch_info || !right->branch_info)
397 return cmp_null(left->branch_info, right->branch_info);
398
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100399 return _sort__dso_cmp(left->branch_info->to.map,
400 right->branch_info->to.map);
401}
402
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300403static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100404 size_t size, unsigned int width)
405{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200406 if (he->branch_info)
407 return _hist_entry__dso_snprintf(he->branch_info->to.map,
408 bf, size, width);
409 else
410 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100411}
412
413static int64_t
414sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
415{
416 struct addr_map_symbol *from_l = &left->branch_info->from;
417 struct addr_map_symbol *from_r = &right->branch_info->from;
418
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200419 if (!left->branch_info || !right->branch_info)
420 return cmp_null(left->branch_info, right->branch_info);
421
422 from_l = &left->branch_info->from;
423 from_r = &right->branch_info->from;
424
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100425 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900426 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427
Namhyung Kim51f27d12013-02-06 14:57:15 +0900428 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429}
430
431static int64_t
432sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
433{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200434 struct addr_map_symbol *to_l, *to_r;
435
436 if (!left->branch_info || !right->branch_info)
437 return cmp_null(left->branch_info, right->branch_info);
438
439 to_l = &left->branch_info->to;
440 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100441
442 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900443 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100444
Namhyung Kim51f27d12013-02-06 14:57:15 +0900445 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100446}
447
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300448static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900449 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200451 if (he->branch_info) {
452 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100453
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200454 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
455 he->level, bf, size, width);
456 }
457
458 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100459}
460
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300461static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900462 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100463{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200464 if (he->branch_info) {
465 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100466
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200467 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
468 he->level, bf, size, width);
469 }
470
471 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100472}
473
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900474struct sort_entry sort_dso_from = {
475 .se_header = "Source Shared Object",
476 .se_cmp = sort__dso_from_cmp,
477 .se_snprintf = hist_entry__dso_from_snprintf,
478 .se_width_idx = HISTC_DSO_FROM,
479};
480
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100481struct sort_entry sort_dso_to = {
482 .se_header = "Target Shared Object",
483 .se_cmp = sort__dso_to_cmp,
484 .se_snprintf = hist_entry__dso_to_snprintf,
485 .se_width_idx = HISTC_DSO_TO,
486};
487
488struct sort_entry sort_sym_from = {
489 .se_header = "Source Symbol",
490 .se_cmp = sort__sym_from_cmp,
491 .se_snprintf = hist_entry__sym_from_snprintf,
492 .se_width_idx = HISTC_SYMBOL_FROM,
493};
494
495struct sort_entry sort_sym_to = {
496 .se_header = "Target Symbol",
497 .se_cmp = sort__sym_to_cmp,
498 .se_snprintf = hist_entry__sym_to_snprintf,
499 .se_width_idx = HISTC_SYMBOL_TO,
500};
501
502static int64_t
503sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
504{
Jiri Olsa428560e2014-10-16 16:07:03 +0200505 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100506
Jiri Olsa428560e2014-10-16 16:07:03 +0200507 if (!left->branch_info || !right->branch_info)
508 return cmp_null(left->branch_info, right->branch_info);
509
510 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
511 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100512 return mp || p;
513}
514
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300515static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100516 size_t size, unsigned int width){
517 static const char *out = "N/A";
518
Jiri Olsa428560e2014-10-16 16:07:03 +0200519 if (he->branch_info) {
520 if (he->branch_info->flags.predicted)
521 out = "N";
522 else if (he->branch_info->flags.mispred)
523 out = "Y";
524 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100525
Namhyung Kim5b591662014-07-31 14:47:38 +0900526 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100527}
528
Stephane Eranian98a3b322013-01-24 16:10:35 +0100529/* --sort daddr_sym */
530static int64_t
531sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
532{
533 uint64_t l = 0, r = 0;
534
535 if (left->mem_info)
536 l = left->mem_info->daddr.addr;
537 if (right->mem_info)
538 r = right->mem_info->daddr.addr;
539
540 return (int64_t)(r - l);
541}
542
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300543static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100544 size_t size, unsigned int width)
545{
546 uint64_t addr = 0;
547 struct map *map = NULL;
548 struct symbol *sym = NULL;
549
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300550 if (he->mem_info) {
551 addr = he->mem_info->daddr.addr;
552 map = he->mem_info->daddr.map;
553 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100554 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300555 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100556 width);
557}
558
559static int64_t
560sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
561{
562 struct map *map_l = NULL;
563 struct map *map_r = NULL;
564
565 if (left->mem_info)
566 map_l = left->mem_info->daddr.map;
567 if (right->mem_info)
568 map_r = right->mem_info->daddr.map;
569
570 return _sort__dso_cmp(map_l, map_r);
571}
572
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300573static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100574 size_t size, unsigned int width)
575{
576 struct map *map = NULL;
577
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300578 if (he->mem_info)
579 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100580
581 return _hist_entry__dso_snprintf(map, bf, size, width);
582}
583
584static int64_t
585sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
586{
587 union perf_mem_data_src data_src_l;
588 union perf_mem_data_src data_src_r;
589
590 if (left->mem_info)
591 data_src_l = left->mem_info->data_src;
592 else
593 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
594
595 if (right->mem_info)
596 data_src_r = right->mem_info->data_src;
597 else
598 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
599
600 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
601}
602
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300603static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100604 size_t size, unsigned int width)
605{
606 const char *out;
607 u64 mask = PERF_MEM_LOCK_NA;
608
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300609 if (he->mem_info)
610 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100611
612 if (mask & PERF_MEM_LOCK_NA)
613 out = "N/A";
614 else if (mask & PERF_MEM_LOCK_LOCKED)
615 out = "Yes";
616 else
617 out = "No";
618
619 return repsep_snprintf(bf, size, "%-*s", width, out);
620}
621
622static int64_t
623sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
624{
625 union perf_mem_data_src data_src_l;
626 union perf_mem_data_src data_src_r;
627
628 if (left->mem_info)
629 data_src_l = left->mem_info->data_src;
630 else
631 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
632
633 if (right->mem_info)
634 data_src_r = right->mem_info->data_src;
635 else
636 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
637
638 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
639}
640
641static const char * const tlb_access[] = {
642 "N/A",
643 "HIT",
644 "MISS",
645 "L1",
646 "L2",
647 "Walker",
648 "Fault",
649};
650#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
651
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300652static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100653 size_t size, unsigned int width)
654{
655 char out[64];
656 size_t sz = sizeof(out) - 1; /* -1 for null termination */
657 size_t l = 0, i;
658 u64 m = PERF_MEM_TLB_NA;
659 u64 hit, miss;
660
661 out[0] = '\0';
662
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300663 if (he->mem_info)
664 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100665
666 hit = m & PERF_MEM_TLB_HIT;
667 miss = m & PERF_MEM_TLB_MISS;
668
669 /* already taken care of */
670 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
671
672 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
673 if (!(m & 0x1))
674 continue;
675 if (l) {
676 strcat(out, " or ");
677 l += 4;
678 }
679 strncat(out, tlb_access[i], sz - l);
680 l += strlen(tlb_access[i]);
681 }
682 if (*out == '\0')
683 strcpy(out, "N/A");
684 if (hit)
685 strncat(out, " hit", sz - l);
686 if (miss)
687 strncat(out, " miss", sz - l);
688
689 return repsep_snprintf(bf, size, "%-*s", width, out);
690}
691
692static int64_t
693sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
694{
695 union perf_mem_data_src data_src_l;
696 union perf_mem_data_src data_src_r;
697
698 if (left->mem_info)
699 data_src_l = left->mem_info->data_src;
700 else
701 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
702
703 if (right->mem_info)
704 data_src_r = right->mem_info->data_src;
705 else
706 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
707
708 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
709}
710
711static const char * const mem_lvl[] = {
712 "N/A",
713 "HIT",
714 "MISS",
715 "L1",
716 "LFB",
717 "L2",
718 "L3",
719 "Local RAM",
720 "Remote RAM (1 hop)",
721 "Remote RAM (2 hops)",
722 "Remote Cache (1 hop)",
723 "Remote Cache (2 hops)",
724 "I/O",
725 "Uncached",
726};
727#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
728
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300729static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100730 size_t size, unsigned int width)
731{
732 char out[64];
733 size_t sz = sizeof(out) - 1; /* -1 for null termination */
734 size_t i, l = 0;
735 u64 m = PERF_MEM_LVL_NA;
736 u64 hit, miss;
737
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300738 if (he->mem_info)
739 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100740
741 out[0] = '\0';
742
743 hit = m & PERF_MEM_LVL_HIT;
744 miss = m & PERF_MEM_LVL_MISS;
745
746 /* already taken care of */
747 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
748
749 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
750 if (!(m & 0x1))
751 continue;
752 if (l) {
753 strcat(out, " or ");
754 l += 4;
755 }
756 strncat(out, mem_lvl[i], sz - l);
757 l += strlen(mem_lvl[i]);
758 }
759 if (*out == '\0')
760 strcpy(out, "N/A");
761 if (hit)
762 strncat(out, " hit", sz - l);
763 if (miss)
764 strncat(out, " miss", sz - l);
765
766 return repsep_snprintf(bf, size, "%-*s", width, out);
767}
768
769static int64_t
770sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
771{
772 union perf_mem_data_src data_src_l;
773 union perf_mem_data_src data_src_r;
774
775 if (left->mem_info)
776 data_src_l = left->mem_info->data_src;
777 else
778 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
779
780 if (right->mem_info)
781 data_src_r = right->mem_info->data_src;
782 else
783 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
784
785 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
786}
787
788static const char * const snoop_access[] = {
789 "N/A",
790 "None",
791 "Miss",
792 "Hit",
793 "HitM",
794};
795#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
796
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300797static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100798 size_t size, unsigned int width)
799{
800 char out[64];
801 size_t sz = sizeof(out) - 1; /* -1 for null termination */
802 size_t i, l = 0;
803 u64 m = PERF_MEM_SNOOP_NA;
804
805 out[0] = '\0';
806
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300807 if (he->mem_info)
808 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100809
810 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
811 if (!(m & 0x1))
812 continue;
813 if (l) {
814 strcat(out, " or ");
815 l += 4;
816 }
817 strncat(out, snoop_access[i], sz - l);
818 l += strlen(snoop_access[i]);
819 }
820
821 if (*out == '\0')
822 strcpy(out, "N/A");
823
824 return repsep_snprintf(bf, size, "%-*s", width, out);
825}
826
Don Zickus9b32ba72014-06-01 15:38:29 +0200827static inline u64 cl_address(u64 address)
828{
829 /* return the cacheline of the address */
830 return (address & ~(cacheline_size - 1));
831}
832
833static int64_t
834sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
835{
836 u64 l, r;
837 struct map *l_map, *r_map;
838
839 if (!left->mem_info) return -1;
840 if (!right->mem_info) return 1;
841
842 /* group event types together */
843 if (left->cpumode > right->cpumode) return -1;
844 if (left->cpumode < right->cpumode) return 1;
845
846 l_map = left->mem_info->daddr.map;
847 r_map = right->mem_info->daddr.map;
848
849 /* if both are NULL, jump to sort on al_addr instead */
850 if (!l_map && !r_map)
851 goto addr;
852
853 if (!l_map) return -1;
854 if (!r_map) return 1;
855
856 if (l_map->maj > r_map->maj) return -1;
857 if (l_map->maj < r_map->maj) return 1;
858
859 if (l_map->min > r_map->min) return -1;
860 if (l_map->min < r_map->min) return 1;
861
862 if (l_map->ino > r_map->ino) return -1;
863 if (l_map->ino < r_map->ino) return 1;
864
865 if (l_map->ino_generation > r_map->ino_generation) return -1;
866 if (l_map->ino_generation < r_map->ino_generation) return 1;
867
868 /*
869 * Addresses with no major/minor numbers are assumed to be
870 * anonymous in userspace. Sort those on pid then address.
871 *
872 * The kernel and non-zero major/minor mapped areas are
873 * assumed to be unity mapped. Sort those on address.
874 */
875
876 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
877 (!(l_map->flags & MAP_SHARED)) &&
878 !l_map->maj && !l_map->min && !l_map->ino &&
879 !l_map->ino_generation) {
880 /* userspace anonymous */
881
882 if (left->thread->pid_ > right->thread->pid_) return -1;
883 if (left->thread->pid_ < right->thread->pid_) return 1;
884 }
885
886addr:
887 /* al_addr does all the right addr - start + offset calculations */
888 l = cl_address(left->mem_info->daddr.al_addr);
889 r = cl_address(right->mem_info->daddr.al_addr);
890
891 if (l > r) return -1;
892 if (l < r) return 1;
893
894 return 0;
895}
896
897static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
898 size_t size, unsigned int width)
899{
900
901 uint64_t addr = 0;
902 struct map *map = NULL;
903 struct symbol *sym = NULL;
904 char level = he->level;
905
906 if (he->mem_info) {
907 addr = cl_address(he->mem_info->daddr.al_addr);
908 map = he->mem_info->daddr.map;
909 sym = he->mem_info->daddr.sym;
910
911 /* print [s] for shared data mmaps */
912 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
913 map && (map->type == MAP__VARIABLE) &&
914 (map->flags & MAP_SHARED) &&
915 (map->maj || map->min || map->ino ||
916 map->ino_generation))
917 level = 's';
918 else if (!map)
919 level = 'X';
920 }
921 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
922 width);
923}
924
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100925struct sort_entry sort_mispredict = {
926 .se_header = "Branch Mispredicted",
927 .se_cmp = sort__mispredict_cmp,
928 .se_snprintf = hist_entry__mispredict_snprintf,
929 .se_width_idx = HISTC_MISPREDICT,
930};
931
Andi Kleen05484292013-01-24 16:10:29 +0100932static u64 he_weight(struct hist_entry *he)
933{
934 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
935}
936
937static int64_t
938sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
939{
940 return he_weight(left) - he_weight(right);
941}
942
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300943static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100944 size_t size, unsigned int width)
945{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300946 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100947}
948
949struct sort_entry sort_local_weight = {
950 .se_header = "Local Weight",
951 .se_cmp = sort__local_weight_cmp,
952 .se_snprintf = hist_entry__local_weight_snprintf,
953 .se_width_idx = HISTC_LOCAL_WEIGHT,
954};
955
956static int64_t
957sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
958{
959 return left->stat.weight - right->stat.weight;
960}
961
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300962static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100963 size_t size, unsigned int width)
964{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300965 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100966}
967
968struct sort_entry sort_global_weight = {
969 .se_header = "Weight",
970 .se_cmp = sort__global_weight_cmp,
971 .se_snprintf = hist_entry__global_weight_snprintf,
972 .se_width_idx = HISTC_GLOBAL_WEIGHT,
973};
974
Stephane Eranian98a3b322013-01-24 16:10:35 +0100975struct sort_entry sort_mem_daddr_sym = {
976 .se_header = "Data Symbol",
977 .se_cmp = sort__daddr_cmp,
978 .se_snprintf = hist_entry__daddr_snprintf,
979 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
980};
981
982struct sort_entry sort_mem_daddr_dso = {
983 .se_header = "Data Object",
984 .se_cmp = sort__dso_daddr_cmp,
985 .se_snprintf = hist_entry__dso_daddr_snprintf,
986 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
987};
988
989struct sort_entry sort_mem_locked = {
990 .se_header = "Locked",
991 .se_cmp = sort__locked_cmp,
992 .se_snprintf = hist_entry__locked_snprintf,
993 .se_width_idx = HISTC_MEM_LOCKED,
994};
995
996struct sort_entry sort_mem_tlb = {
997 .se_header = "TLB access",
998 .se_cmp = sort__tlb_cmp,
999 .se_snprintf = hist_entry__tlb_snprintf,
1000 .se_width_idx = HISTC_MEM_TLB,
1001};
1002
1003struct sort_entry sort_mem_lvl = {
1004 .se_header = "Memory access",
1005 .se_cmp = sort__lvl_cmp,
1006 .se_snprintf = hist_entry__lvl_snprintf,
1007 .se_width_idx = HISTC_MEM_LVL,
1008};
1009
1010struct sort_entry sort_mem_snoop = {
1011 .se_header = "Snoop",
1012 .se_cmp = sort__snoop_cmp,
1013 .se_snprintf = hist_entry__snoop_snprintf,
1014 .se_width_idx = HISTC_MEM_SNOOP,
1015};
1016
Don Zickus9b32ba72014-06-01 15:38:29 +02001017struct sort_entry sort_mem_dcacheline = {
1018 .se_header = "Data Cacheline",
1019 .se_cmp = sort__dcacheline_cmp,
1020 .se_snprintf = hist_entry__dcacheline_snprintf,
1021 .se_width_idx = HISTC_MEM_DCACHELINE,
1022};
1023
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001024static int64_t
1025sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1026{
Jiri Olsa49f47442014-10-16 16:07:01 +02001027 if (!left->branch_info || !right->branch_info)
1028 return cmp_null(left->branch_info, right->branch_info);
1029
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001030 return left->branch_info->flags.abort !=
1031 right->branch_info->flags.abort;
1032}
1033
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001034static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001035 size_t size, unsigned int width)
1036{
Jiri Olsa49f47442014-10-16 16:07:01 +02001037 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001038
Jiri Olsa49f47442014-10-16 16:07:01 +02001039 if (he->branch_info) {
1040 if (he->branch_info->flags.abort)
1041 out = "A";
1042 else
1043 out = ".";
1044 }
1045
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001046 return repsep_snprintf(bf, size, "%-*s", width, out);
1047}
1048
1049struct sort_entry sort_abort = {
1050 .se_header = "Transaction abort",
1051 .se_cmp = sort__abort_cmp,
1052 .se_snprintf = hist_entry__abort_snprintf,
1053 .se_width_idx = HISTC_ABORT,
1054};
1055
1056static int64_t
1057sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1058{
Jiri Olsa0199d242014-10-16 16:07:02 +02001059 if (!left->branch_info || !right->branch_info)
1060 return cmp_null(left->branch_info, right->branch_info);
1061
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001062 return left->branch_info->flags.in_tx !=
1063 right->branch_info->flags.in_tx;
1064}
1065
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001066static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001067 size_t size, unsigned int width)
1068{
Jiri Olsa0199d242014-10-16 16:07:02 +02001069 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001070
Jiri Olsa0199d242014-10-16 16:07:02 +02001071 if (he->branch_info) {
1072 if (he->branch_info->flags.in_tx)
1073 out = "T";
1074 else
1075 out = ".";
1076 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001077
1078 return repsep_snprintf(bf, size, "%-*s", width, out);
1079}
1080
1081struct sort_entry sort_in_tx = {
1082 .se_header = "Branch in transaction",
1083 .se_cmp = sort__in_tx_cmp,
1084 .se_snprintf = hist_entry__in_tx_snprintf,
1085 .se_width_idx = HISTC_IN_TX,
1086};
1087
Andi Kleen475eeab2013-09-20 07:40:43 -07001088static int64_t
1089sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1090{
1091 return left->transaction - right->transaction;
1092}
1093
1094static inline char *add_str(char *p, const char *str)
1095{
1096 strcpy(p, str);
1097 return p + strlen(str);
1098}
1099
1100static struct txbit {
1101 unsigned flag;
1102 const char *name;
1103 int skip_for_len;
1104} txbits[] = {
1105 { PERF_TXN_ELISION, "EL ", 0 },
1106 { PERF_TXN_TRANSACTION, "TX ", 1 },
1107 { PERF_TXN_SYNC, "SYNC ", 1 },
1108 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1109 { PERF_TXN_RETRY, "RETRY ", 0 },
1110 { PERF_TXN_CONFLICT, "CON ", 0 },
1111 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1112 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1113 { 0, NULL, 0 }
1114};
1115
1116int hist_entry__transaction_len(void)
1117{
1118 int i;
1119 int len = 0;
1120
1121 for (i = 0; txbits[i].name; i++) {
1122 if (!txbits[i].skip_for_len)
1123 len += strlen(txbits[i].name);
1124 }
1125 len += 4; /* :XX<space> */
1126 return len;
1127}
1128
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001129static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001130 size_t size, unsigned int width)
1131{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001132 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001133 char buf[128];
1134 char *p = buf;
1135 int i;
1136
1137 buf[0] = 0;
1138 for (i = 0; txbits[i].name; i++)
1139 if (txbits[i].flag & t)
1140 p = add_str(p, txbits[i].name);
1141 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1142 p = add_str(p, "NEITHER ");
1143 if (t & PERF_TXN_ABORT_MASK) {
1144 sprintf(p, ":%" PRIx64,
1145 (t & PERF_TXN_ABORT_MASK) >>
1146 PERF_TXN_ABORT_SHIFT);
1147 p += strlen(p);
1148 }
1149
1150 return repsep_snprintf(bf, size, "%-*s", width, buf);
1151}
1152
1153struct sort_entry sort_transaction = {
1154 .se_header = "Transaction ",
1155 .se_cmp = sort__transaction_cmp,
1156 .se_snprintf = hist_entry__transaction_snprintf,
1157 .se_width_idx = HISTC_TRANSACTION,
1158};
1159
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001160struct sort_dimension {
1161 const char *name;
1162 struct sort_entry *entry;
1163 int taken;
1164};
1165
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001166#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1167
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001168static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001169 DIM(SORT_PID, "pid", sort_thread),
1170 DIM(SORT_COMM, "comm", sort_comm),
1171 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001172 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001173 DIM(SORT_PARENT, "parent", sort_parent),
1174 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001175 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001176 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1177 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001178 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001179};
1180
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001181#undef DIM
1182
1183#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1184
1185static struct sort_dimension bstack_sort_dimensions[] = {
1186 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1187 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1188 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1189 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1190 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001191 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1192 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001193};
1194
1195#undef DIM
1196
Namhyung Kimafab87b2013-04-03 21:26:11 +09001197#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1198
1199static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001200 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1201 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1202 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1203 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1204 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1205 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001206 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001207};
1208
1209#undef DIM
1210
Namhyung Kima2ce0672014-03-04 09:06:42 +09001211struct hpp_dimension {
1212 const char *name;
1213 struct perf_hpp_fmt *fmt;
1214 int taken;
1215};
1216
1217#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1218
1219static struct hpp_dimension hpp_sort_dimensions[] = {
1220 DIM(PERF_HPP__OVERHEAD, "overhead"),
1221 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1222 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1223 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1224 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001225 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001226 DIM(PERF_HPP__SAMPLES, "sample"),
1227 DIM(PERF_HPP__PERIOD, "period"),
1228};
1229
1230#undef DIM
1231
Namhyung Kim8b536992014-03-03 11:46:55 +09001232struct hpp_sort_entry {
1233 struct perf_hpp_fmt hpp;
1234 struct sort_entry *se;
1235};
1236
Namhyung Kima7d945b2014-03-04 10:46:34 +09001237bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1238{
1239 struct hpp_sort_entry *hse_a;
1240 struct hpp_sort_entry *hse_b;
1241
1242 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1243 return false;
1244
1245 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1246 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1247
1248 return hse_a->se == hse_b->se;
1249}
1250
Namhyung Kime0d66c72014-07-31 14:47:37 +09001251void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001252{
1253 struct hpp_sort_entry *hse;
1254
1255 if (!perf_hpp__is_sort_entry(fmt))
1256 return;
1257
1258 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001259 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001260}
1261
Namhyung Kim8b536992014-03-03 11:46:55 +09001262static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1263 struct perf_evsel *evsel)
1264{
1265 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001266 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001267
1268 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001269
Namhyung Kim5b591662014-07-31 14:47:38 +09001270 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001271 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001272
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001273 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001274}
1275
1276static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1277 struct perf_hpp *hpp __maybe_unused,
1278 struct perf_evsel *evsel)
1279{
1280 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001281 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001282
1283 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1284
Namhyung Kim5b591662014-07-31 14:47:38 +09001285 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001286 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001287
1288 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001289}
1290
1291static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1292 struct hist_entry *he)
1293{
1294 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001295 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001296
1297 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001298
1299 if (!len)
1300 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001301
1302 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1303}
1304
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001305static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1306 struct hist_entry *a, struct hist_entry *b)
1307{
1308 struct hpp_sort_entry *hse;
1309
1310 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1311 return hse->se->se_cmp(a, b);
1312}
1313
1314static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1315 struct hist_entry *a, struct hist_entry *b)
1316{
1317 struct hpp_sort_entry *hse;
1318 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1319
1320 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1321 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1322 return collapse_fn(a, b);
1323}
1324
1325static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1326 struct hist_entry *a, struct hist_entry *b)
1327{
1328 struct hpp_sort_entry *hse;
1329 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1330
1331 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1332 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1333 return sort_fn(a, b);
1334}
1335
Namhyung Kima7d945b2014-03-04 10:46:34 +09001336static struct hpp_sort_entry *
1337__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001338{
1339 struct hpp_sort_entry *hse;
1340
1341 hse = malloc(sizeof(*hse));
1342 if (hse == NULL) {
1343 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001344 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001345 }
1346
1347 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001348 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001349 hse->hpp.header = __sort__hpp_header;
1350 hse->hpp.width = __sort__hpp_width;
1351 hse->hpp.entry = __sort__hpp_entry;
1352 hse->hpp.color = NULL;
1353
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001354 hse->hpp.cmp = __sort__hpp_cmp;
1355 hse->hpp.collapse = __sort__hpp_collapse;
1356 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001357
1358 INIT_LIST_HEAD(&hse->hpp.list);
1359 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001360 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001361 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001362 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001363
Namhyung Kima7d945b2014-03-04 10:46:34 +09001364 return hse;
1365}
1366
1367bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1368{
1369 return format->header == __sort__hpp_header;
1370}
1371
1372static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1373{
1374 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1375
1376 if (hse == NULL)
1377 return -1;
1378
Namhyung Kim8b536992014-03-03 11:46:55 +09001379 perf_hpp__register_sort_field(&hse->hpp);
1380 return 0;
1381}
1382
Namhyung Kima7d945b2014-03-04 10:46:34 +09001383static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1384{
1385 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1386
1387 if (hse == NULL)
1388 return -1;
1389
1390 perf_hpp__column_register(&hse->hpp);
1391 return 0;
1392}
1393
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001394static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001395{
1396 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001397 return 0;
1398
Namhyung Kima7d945b2014-03-04 10:46:34 +09001399 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001400 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001401
1402 if (sd->entry->se_collapse)
1403 sort__need_collapse = 1;
1404
Namhyung Kim2f532d092013-04-03 21:26:10 +09001405 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001406
1407 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001408}
1409
Namhyung Kima2ce0672014-03-04 09:06:42 +09001410static int __hpp_dimension__add(struct hpp_dimension *hd)
1411{
1412 if (!hd->taken) {
1413 hd->taken = 1;
1414
1415 perf_hpp__register_sort_field(hd->fmt);
1416 }
1417 return 0;
1418}
1419
Namhyung Kima7d945b2014-03-04 10:46:34 +09001420static int __sort_dimension__add_output(struct sort_dimension *sd)
1421{
1422 if (sd->taken)
1423 return 0;
1424
1425 if (__sort_dimension__add_hpp_output(sd) < 0)
1426 return -1;
1427
1428 sd->taken = 1;
1429 return 0;
1430}
1431
1432static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1433{
1434 if (!hd->taken) {
1435 hd->taken = 1;
1436
1437 perf_hpp__column_register(hd->fmt);
1438 }
1439 return 0;
1440}
1441
John Kacurdd68ada2009-09-24 18:02:49 +02001442int sort_dimension__add(const char *tok)
1443{
1444 unsigned int i;
1445
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001446 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1447 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001448
John Kacurdd68ada2009-09-24 18:02:49 +02001449 if (strncasecmp(tok, sd->name, strlen(tok)))
1450 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001451
John Kacurdd68ada2009-09-24 18:02:49 +02001452 if (sd->entry == &sort_parent) {
1453 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1454 if (ret) {
1455 char err[BUFSIZ];
1456
1457 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001458 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1459 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001460 }
1461 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001462 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001463 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00001464 /*
1465 * perf diff displays the performance difference amongst
1466 * two or more perf.data files. Those files could come
1467 * from different binaries. So we should not compare
1468 * their ips, but the name of symbol.
1469 */
1470 if (sort__mode == SORT_MODE__DIFF)
1471 sd->entry->se_collapse = sort__sym_sort;
1472
Namhyung Kim68f6d022013-12-18 14:21:10 +09001473 } else if (sd->entry == &sort_dso) {
1474 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001475 }
1476
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001477 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001478 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001479
Namhyung Kima2ce0672014-03-04 09:06:42 +09001480 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1481 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1482
1483 if (strncasecmp(tok, hd->name, strlen(tok)))
1484 continue;
1485
1486 return __hpp_dimension__add(hd);
1487 }
1488
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001489 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1490 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1491
1492 if (strncasecmp(tok, sd->name, strlen(tok)))
1493 continue;
1494
Namhyung Kim55369fc2013-04-01 20:35:20 +09001495 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001496 return -EINVAL;
1497
1498 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1499 sort__has_sym = 1;
1500
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001501 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001502 return 0;
1503 }
1504
Namhyung Kimafab87b2013-04-03 21:26:11 +09001505 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1506 struct sort_dimension *sd = &memory_sort_dimensions[i];
1507
1508 if (strncasecmp(tok, sd->name, strlen(tok)))
1509 continue;
1510
1511 if (sort__mode != SORT_MODE__MEMORY)
1512 return -EINVAL;
1513
1514 if (sd->entry == &sort_mem_daddr_sym)
1515 sort__has_sym = 1;
1516
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001517 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001518 return 0;
1519 }
1520
John Kacurdd68ada2009-09-24 18:02:49 +02001521 return -ESRCH;
1522}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001523
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001524static const char *get_default_sort_order(void)
1525{
1526 const char *default_sort_orders[] = {
1527 default_sort_order,
1528 default_branch_sort_order,
1529 default_mem_sort_order,
1530 default_top_sort_order,
1531 default_diff_sort_order,
1532 };
1533
1534 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1535
1536 return default_sort_orders[sort__mode];
1537}
1538
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001539static int setup_sort_order(void)
1540{
1541 char *new_sort_order;
1542
1543 /*
1544 * Append '+'-prefixed sort order to the default sort
1545 * order string.
1546 */
1547 if (!sort_order || is_strict_order(sort_order))
1548 return 0;
1549
1550 if (sort_order[1] == '\0') {
1551 error("Invalid --sort key: `+'");
1552 return -EINVAL;
1553 }
1554
1555 /*
1556 * We allocate new sort_order string, but we never free it,
1557 * because it's checked over the rest of the code.
1558 */
1559 if (asprintf(&new_sort_order, "%s,%s",
1560 get_default_sort_order(), sort_order + 1) < 0) {
1561 error("Not enough memory to set up --sort");
1562 return -ENOMEM;
1563 }
1564
1565 sort_order = new_sort_order;
1566 return 0;
1567}
1568
Namhyung Kima7d945b2014-03-04 10:46:34 +09001569static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001570{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001571 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001572 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001573 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001574
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001575 ret = setup_sort_order();
1576 if (ret)
1577 return ret;
1578
1579 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001580 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001581 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001582 /*
1583 * If user specified field order but no sort order,
1584 * we'll honor it and not add default sort orders.
1585 */
1586 return 0;
1587 }
1588
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001589 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001590 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001591
1592 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001593 if (str == NULL) {
1594 error("Not enough memory to setup sort keys");
1595 return -ENOMEM;
1596 }
1597
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001598 for (tok = strtok_r(str, ", ", &tmp);
1599 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001600 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001601 if (ret == -EINVAL) {
1602 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001603 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001604 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001605 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001606 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001607 }
1608 }
1609
1610 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001611 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001612}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001613
Jiri Olsaf2998422014-05-23 17:15:47 +02001614void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001615{
Jiri Olsaf2998422014-05-23 17:15:47 +02001616 struct perf_hpp_fmt *fmt;
1617 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001618
Jiri Olsaf2998422014-05-23 17:15:47 +02001619 perf_hpp__for_each_format(fmt) {
1620 if (!perf_hpp__is_sort_entry(fmt))
1621 continue;
1622
1623 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1624 if (hse->se->se_width_idx == idx) {
1625 fmt->elide = elide;
1626 break;
1627 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001628 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001629}
1630
Jiri Olsaf2998422014-05-23 17:15:47 +02001631static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001632{
1633 if (list && strlist__nr_entries(list) == 1) {
1634 if (fp != NULL)
1635 fprintf(fp, "# %s: %s\n", list_name,
1636 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001637 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001638 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001639 return false;
1640}
1641
1642static bool get_elide(int idx, FILE *output)
1643{
1644 switch (idx) {
1645 case HISTC_SYMBOL:
1646 return __get_elide(symbol_conf.sym_list, "symbol", output);
1647 case HISTC_DSO:
1648 return __get_elide(symbol_conf.dso_list, "dso", output);
1649 case HISTC_COMM:
1650 return __get_elide(symbol_conf.comm_list, "comm", output);
1651 default:
1652 break;
1653 }
1654
1655 if (sort__mode != SORT_MODE__BRANCH)
1656 return false;
1657
1658 switch (idx) {
1659 case HISTC_SYMBOL_FROM:
1660 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1661 case HISTC_SYMBOL_TO:
1662 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1663 case HISTC_DSO_FROM:
1664 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1665 case HISTC_DSO_TO:
1666 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1667 default:
1668 break;
1669 }
1670
1671 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001672}
Namhyung Kim08e71542013-04-03 21:26:19 +09001673
1674void sort__setup_elide(FILE *output)
1675{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001676 struct perf_hpp_fmt *fmt;
1677 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001678
Jiri Olsaf2998422014-05-23 17:15:47 +02001679 perf_hpp__for_each_format(fmt) {
1680 if (!perf_hpp__is_sort_entry(fmt))
1681 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001682
Jiri Olsaf2998422014-05-23 17:15:47 +02001683 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1684 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001685 }
1686
Namhyung Kim7524f632013-11-08 17:53:42 +09001687 /*
1688 * It makes no sense to elide all of sort entries.
1689 * Just revert them to show up again.
1690 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001691 perf_hpp__for_each_format(fmt) {
1692 if (!perf_hpp__is_sort_entry(fmt))
1693 continue;
1694
Jiri Olsaf2998422014-05-23 17:15:47 +02001695 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001696 return;
1697 }
1698
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001699 perf_hpp__for_each_format(fmt) {
1700 if (!perf_hpp__is_sort_entry(fmt))
1701 continue;
1702
Jiri Olsaf2998422014-05-23 17:15:47 +02001703 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001704 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001705}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001706
1707static int output_field_add(char *tok)
1708{
1709 unsigned int i;
1710
1711 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1712 struct sort_dimension *sd = &common_sort_dimensions[i];
1713
1714 if (strncasecmp(tok, sd->name, strlen(tok)))
1715 continue;
1716
1717 return __sort_dimension__add_output(sd);
1718 }
1719
1720 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1721 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1722
1723 if (strncasecmp(tok, hd->name, strlen(tok)))
1724 continue;
1725
1726 return __hpp_dimension__add_output(hd);
1727 }
1728
1729 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1730 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1731
1732 if (strncasecmp(tok, sd->name, strlen(tok)))
1733 continue;
1734
1735 return __sort_dimension__add_output(sd);
1736 }
1737
1738 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1739 struct sort_dimension *sd = &memory_sort_dimensions[i];
1740
1741 if (strncasecmp(tok, sd->name, strlen(tok)))
1742 continue;
1743
1744 return __sort_dimension__add_output(sd);
1745 }
1746
1747 return -ESRCH;
1748}
1749
1750static void reset_dimensions(void)
1751{
1752 unsigned int i;
1753
1754 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1755 common_sort_dimensions[i].taken = 0;
1756
1757 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1758 hpp_sort_dimensions[i].taken = 0;
1759
1760 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1761 bstack_sort_dimensions[i].taken = 0;
1762
1763 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1764 memory_sort_dimensions[i].taken = 0;
1765}
1766
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001767bool is_strict_order(const char *order)
1768{
1769 return order && (*order != '+');
1770}
1771
Namhyung Kima7d945b2014-03-04 10:46:34 +09001772static int __setup_output_field(void)
1773{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001774 char *tmp, *tok, *str, *strp;
1775 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001776
1777 if (field_order == NULL)
1778 return 0;
1779
1780 reset_dimensions();
1781
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001782 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001783 if (str == NULL) {
1784 error("Not enough memory to setup output fields");
1785 return -ENOMEM;
1786 }
1787
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001788 if (!is_strict_order(field_order))
1789 strp++;
1790
1791 if (!strlen(strp)) {
1792 error("Invalid --fields key: `+'");
1793 goto out;
1794 }
1795
1796 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001797 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1798 ret = output_field_add(tok);
1799 if (ret == -EINVAL) {
1800 error("Invalid --fields key: `%s'", tok);
1801 break;
1802 } else if (ret == -ESRCH) {
1803 error("Unknown --fields key: `%s'", tok);
1804 break;
1805 }
1806 }
1807
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001808out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001809 free(str);
1810 return ret;
1811}
1812
1813int setup_sorting(void)
1814{
1815 int err;
1816
1817 err = __setup_sorting();
1818 if (err < 0)
1819 return err;
1820
1821 if (parent_pattern != default_parent_pattern) {
1822 err = sort_dimension__add("parent");
1823 if (err < 0)
1824 return err;
1825 }
1826
1827 reset_dimensions();
1828
1829 /*
1830 * perf diff doesn't use default hpp output fields.
1831 */
1832 if (sort__mode != SORT_MODE__DIFF)
1833 perf_hpp__init();
1834
1835 err = __setup_output_field();
1836 if (err < 0)
1837 return err;
1838
1839 /* copy sort keys to output fields */
1840 perf_hpp__setup_output_field();
1841 /* and then copy output fields to sort keys */
1842 perf_hpp__append_sort_keys();
1843
1844 return 0;
1845}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001846
1847void reset_output_field(void)
1848{
1849 sort__need_collapse = 0;
1850 sort__has_parent = 0;
1851 sort__has_sym = 0;
1852 sort__has_dso = 0;
1853
Namhyung Kimd69b2962014-05-23 10:59:01 +09001854 field_order = NULL;
1855 sort_order = NULL;
1856
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001857 reset_dimensions();
1858 perf_hpp__reset_output_field();
1859}