blob: c0c32b050e45e1eb784ffc0d73622b8d49b73c8a [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";
Andi Kleen40997d62015-07-18 08:24:53 -070012const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090013const 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
Andi Kleen31191a82015-08-07 15:54:24 -0700322/* --sort srcfile */
323
324static char no_srcfile[1];
325
326static char *get_srcfile(struct hist_entry *e)
327{
328 char *sf, *p;
329 struct map *map = e->ms.map;
330
331 sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip),
332 e->ms.sym, true);
333 p = strchr(sf, ':');
334 if (p && *sf) {
335 *p = 0;
336 return sf;
337 }
338 free(sf);
339 return no_srcfile;
340}
341
342static int64_t
343sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
344{
345 if (!left->srcfile) {
346 if (!left->ms.map)
347 left->srcfile = no_srcfile;
348 else
349 left->srcfile = get_srcfile(left);
350 }
351 if (!right->srcfile) {
352 if (!right->ms.map)
353 right->srcfile = no_srcfile;
354 else
355 right->srcfile = get_srcfile(right);
356 }
357 return strcmp(right->srcfile, left->srcfile);
358}
359
360static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
361 size_t size, unsigned int width)
362{
363 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
364}
365
366struct sort_entry sort_srcfile = {
367 .se_header = "Source File",
368 .se_cmp = sort__srcfile_cmp,
369 .se_snprintf = hist_entry__srcfile_snprintf,
370 .se_width_idx = HISTC_SRCFILE,
371};
372
John Kacurdd68ada2009-09-24 18:02:49 +0200373/* --sort parent */
374
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200375static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200376sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
377{
378 struct symbol *sym_l = left->parent;
379 struct symbol *sym_r = right->parent;
380
381 if (!sym_l || !sym_r)
382 return cmp_null(sym_l, sym_r);
383
Namhyung Kim202e7a62014-03-04 11:01:41 +0900384 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200385}
386
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300387static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300388 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200389{
Namhyung Kim5b591662014-07-31 14:47:38 +0900390 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300391 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200392}
393
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200394struct sort_entry sort_parent = {
395 .se_header = "Parent symbol",
396 .se_cmp = sort__parent_cmp,
397 .se_snprintf = hist_entry__parent_snprintf,
398 .se_width_idx = HISTC_PARENT,
399};
400
Arun Sharmaf60f3592010-06-04 11:27:10 -0300401/* --sort cpu */
402
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200403static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300404sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
405{
406 return right->cpu - left->cpu;
407}
408
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300409static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
410 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300411{
Namhyung Kim5b591662014-07-31 14:47:38 +0900412 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300413}
414
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200415struct sort_entry sort_cpu = {
416 .se_header = "CPU",
417 .se_cmp = sort__cpu_cmp,
418 .se_snprintf = hist_entry__cpu_snprintf,
419 .se_width_idx = HISTC_CPU,
420};
421
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900422/* sort keys for branch stacks */
423
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100424static int64_t
425sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
426{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200427 if (!left->branch_info || !right->branch_info)
428 return cmp_null(left->branch_info, right->branch_info);
429
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100430 return _sort__dso_cmp(left->branch_info->from.map,
431 right->branch_info->from.map);
432}
433
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300434static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100435 size_t size, unsigned int width)
436{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200437 if (he->branch_info)
438 return _hist_entry__dso_snprintf(he->branch_info->from.map,
439 bf, size, width);
440 else
441 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100442}
443
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100444static int64_t
445sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
446{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200447 if (!left->branch_info || !right->branch_info)
448 return cmp_null(left->branch_info, right->branch_info);
449
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100450 return _sort__dso_cmp(left->branch_info->to.map,
451 right->branch_info->to.map);
452}
453
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300454static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100455 size_t size, unsigned int width)
456{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200457 if (he->branch_info)
458 return _hist_entry__dso_snprintf(he->branch_info->to.map,
459 bf, size, width);
460 else
461 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100462}
463
464static int64_t
465sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
466{
467 struct addr_map_symbol *from_l = &left->branch_info->from;
468 struct addr_map_symbol *from_r = &right->branch_info->from;
469
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200470 if (!left->branch_info || !right->branch_info)
471 return cmp_null(left->branch_info, right->branch_info);
472
473 from_l = &left->branch_info->from;
474 from_r = &right->branch_info->from;
475
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100476 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900477 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100478
Namhyung Kim51f27d12013-02-06 14:57:15 +0900479 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100480}
481
482static int64_t
483sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
484{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200485 struct addr_map_symbol *to_l, *to_r;
486
487 if (!left->branch_info || !right->branch_info)
488 return cmp_null(left->branch_info, right->branch_info);
489
490 to_l = &left->branch_info->to;
491 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100492
493 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900494 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100495
Namhyung Kim51f27d12013-02-06 14:57:15 +0900496 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100497}
498
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300499static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900500 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100501{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200502 if (he->branch_info) {
503 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100504
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200505 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
506 he->level, bf, size, width);
507 }
508
509 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100510}
511
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300512static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900513 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100514{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200515 if (he->branch_info) {
516 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100517
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200518 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
519 he->level, bf, size, width);
520 }
521
522 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100523}
524
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900525struct sort_entry sort_dso_from = {
526 .se_header = "Source Shared Object",
527 .se_cmp = sort__dso_from_cmp,
528 .se_snprintf = hist_entry__dso_from_snprintf,
529 .se_width_idx = HISTC_DSO_FROM,
530};
531
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100532struct sort_entry sort_dso_to = {
533 .se_header = "Target Shared Object",
534 .se_cmp = sort__dso_to_cmp,
535 .se_snprintf = hist_entry__dso_to_snprintf,
536 .se_width_idx = HISTC_DSO_TO,
537};
538
539struct sort_entry sort_sym_from = {
540 .se_header = "Source Symbol",
541 .se_cmp = sort__sym_from_cmp,
542 .se_snprintf = hist_entry__sym_from_snprintf,
543 .se_width_idx = HISTC_SYMBOL_FROM,
544};
545
546struct sort_entry sort_sym_to = {
547 .se_header = "Target Symbol",
548 .se_cmp = sort__sym_to_cmp,
549 .se_snprintf = hist_entry__sym_to_snprintf,
550 .se_width_idx = HISTC_SYMBOL_TO,
551};
552
553static int64_t
554sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
555{
Jiri Olsa428560e2014-10-16 16:07:03 +0200556 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100557
Jiri Olsa428560e2014-10-16 16:07:03 +0200558 if (!left->branch_info || !right->branch_info)
559 return cmp_null(left->branch_info, right->branch_info);
560
561 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
562 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100563 return mp || p;
564}
565
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300566static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100567 size_t size, unsigned int width){
568 static const char *out = "N/A";
569
Jiri Olsa428560e2014-10-16 16:07:03 +0200570 if (he->branch_info) {
571 if (he->branch_info->flags.predicted)
572 out = "N";
573 else if (he->branch_info->flags.mispred)
574 out = "Y";
575 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100576
Namhyung Kim5b591662014-07-31 14:47:38 +0900577 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100578}
579
Andi Kleen0e332f02015-07-18 08:24:46 -0700580static int64_t
581sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
582{
583 return left->branch_info->flags.cycles -
584 right->branch_info->flags.cycles;
585}
586
587static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
588 size_t size, unsigned int width)
589{
590 if (he->branch_info->flags.cycles == 0)
591 return repsep_snprintf(bf, size, "%-*s", width, "-");
592 return repsep_snprintf(bf, size, "%-*hd", width,
593 he->branch_info->flags.cycles);
594}
595
596struct sort_entry sort_cycles = {
597 .se_header = "Basic Block Cycles",
598 .se_cmp = sort__cycles_cmp,
599 .se_snprintf = hist_entry__cycles_snprintf,
600 .se_width_idx = HISTC_CYCLES,
601};
602
Stephane Eranian98a3b322013-01-24 16:10:35 +0100603/* --sort daddr_sym */
604static int64_t
605sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
606{
607 uint64_t l = 0, r = 0;
608
609 if (left->mem_info)
610 l = left->mem_info->daddr.addr;
611 if (right->mem_info)
612 r = right->mem_info->daddr.addr;
613
614 return (int64_t)(r - l);
615}
616
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300617static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100618 size_t size, unsigned int width)
619{
620 uint64_t addr = 0;
621 struct map *map = NULL;
622 struct symbol *sym = NULL;
623
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300624 if (he->mem_info) {
625 addr = he->mem_info->daddr.addr;
626 map = he->mem_info->daddr.map;
627 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100628 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300629 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100630 width);
631}
632
633static int64_t
634sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
635{
636 struct map *map_l = NULL;
637 struct map *map_r = NULL;
638
639 if (left->mem_info)
640 map_l = left->mem_info->daddr.map;
641 if (right->mem_info)
642 map_r = right->mem_info->daddr.map;
643
644 return _sort__dso_cmp(map_l, map_r);
645}
646
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300647static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100648 size_t size, unsigned int width)
649{
650 struct map *map = NULL;
651
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300652 if (he->mem_info)
653 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100654
655 return _hist_entry__dso_snprintf(map, bf, size, width);
656}
657
658static int64_t
659sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
660{
661 union perf_mem_data_src data_src_l;
662 union perf_mem_data_src data_src_r;
663
664 if (left->mem_info)
665 data_src_l = left->mem_info->data_src;
666 else
667 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
668
669 if (right->mem_info)
670 data_src_r = right->mem_info->data_src;
671 else
672 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
673
674 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
675}
676
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300677static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100678 size_t size, unsigned int width)
679{
680 const char *out;
681 u64 mask = PERF_MEM_LOCK_NA;
682
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300683 if (he->mem_info)
684 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100685
686 if (mask & PERF_MEM_LOCK_NA)
687 out = "N/A";
688 else if (mask & PERF_MEM_LOCK_LOCKED)
689 out = "Yes";
690 else
691 out = "No";
692
693 return repsep_snprintf(bf, size, "%-*s", width, out);
694}
695
696static int64_t
697sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
698{
699 union perf_mem_data_src data_src_l;
700 union perf_mem_data_src data_src_r;
701
702 if (left->mem_info)
703 data_src_l = left->mem_info->data_src;
704 else
705 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
706
707 if (right->mem_info)
708 data_src_r = right->mem_info->data_src;
709 else
710 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
711
712 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
713}
714
715static const char * const tlb_access[] = {
716 "N/A",
717 "HIT",
718 "MISS",
719 "L1",
720 "L2",
721 "Walker",
722 "Fault",
723};
724#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
725
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300726static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100727 size_t size, unsigned int width)
728{
729 char out[64];
730 size_t sz = sizeof(out) - 1; /* -1 for null termination */
731 size_t l = 0, i;
732 u64 m = PERF_MEM_TLB_NA;
733 u64 hit, miss;
734
735 out[0] = '\0';
736
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300737 if (he->mem_info)
738 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100739
740 hit = m & PERF_MEM_TLB_HIT;
741 miss = m & PERF_MEM_TLB_MISS;
742
743 /* already taken care of */
744 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
745
746 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
747 if (!(m & 0x1))
748 continue;
749 if (l) {
750 strcat(out, " or ");
751 l += 4;
752 }
753 strncat(out, tlb_access[i], sz - l);
754 l += strlen(tlb_access[i]);
755 }
756 if (*out == '\0')
757 strcpy(out, "N/A");
758 if (hit)
759 strncat(out, " hit", sz - l);
760 if (miss)
761 strncat(out, " miss", sz - l);
762
763 return repsep_snprintf(bf, size, "%-*s", width, out);
764}
765
766static int64_t
767sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
768{
769 union perf_mem_data_src data_src_l;
770 union perf_mem_data_src data_src_r;
771
772 if (left->mem_info)
773 data_src_l = left->mem_info->data_src;
774 else
775 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
776
777 if (right->mem_info)
778 data_src_r = right->mem_info->data_src;
779 else
780 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
781
782 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
783}
784
785static const char * const mem_lvl[] = {
786 "N/A",
787 "HIT",
788 "MISS",
789 "L1",
790 "LFB",
791 "L2",
792 "L3",
793 "Local RAM",
794 "Remote RAM (1 hop)",
795 "Remote RAM (2 hops)",
796 "Remote Cache (1 hop)",
797 "Remote Cache (2 hops)",
798 "I/O",
799 "Uncached",
800};
801#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
802
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300803static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100804 size_t size, unsigned int width)
805{
806 char out[64];
807 size_t sz = sizeof(out) - 1; /* -1 for null termination */
808 size_t i, l = 0;
809 u64 m = PERF_MEM_LVL_NA;
810 u64 hit, miss;
811
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300812 if (he->mem_info)
813 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100814
815 out[0] = '\0';
816
817 hit = m & PERF_MEM_LVL_HIT;
818 miss = m & PERF_MEM_LVL_MISS;
819
820 /* already taken care of */
821 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
822
823 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
824 if (!(m & 0x1))
825 continue;
826 if (l) {
827 strcat(out, " or ");
828 l += 4;
829 }
830 strncat(out, mem_lvl[i], sz - l);
831 l += strlen(mem_lvl[i]);
832 }
833 if (*out == '\0')
834 strcpy(out, "N/A");
835 if (hit)
836 strncat(out, " hit", sz - l);
837 if (miss)
838 strncat(out, " miss", sz - l);
839
840 return repsep_snprintf(bf, size, "%-*s", width, out);
841}
842
843static int64_t
844sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
845{
846 union perf_mem_data_src data_src_l;
847 union perf_mem_data_src data_src_r;
848
849 if (left->mem_info)
850 data_src_l = left->mem_info->data_src;
851 else
852 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
853
854 if (right->mem_info)
855 data_src_r = right->mem_info->data_src;
856 else
857 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
858
859 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
860}
861
862static const char * const snoop_access[] = {
863 "N/A",
864 "None",
865 "Miss",
866 "Hit",
867 "HitM",
868};
869#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
870
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300871static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100872 size_t size, unsigned int width)
873{
874 char out[64];
875 size_t sz = sizeof(out) - 1; /* -1 for null termination */
876 size_t i, l = 0;
877 u64 m = PERF_MEM_SNOOP_NA;
878
879 out[0] = '\0';
880
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300881 if (he->mem_info)
882 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100883
884 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
885 if (!(m & 0x1))
886 continue;
887 if (l) {
888 strcat(out, " or ");
889 l += 4;
890 }
891 strncat(out, snoop_access[i], sz - l);
892 l += strlen(snoop_access[i]);
893 }
894
895 if (*out == '\0')
896 strcpy(out, "N/A");
897
898 return repsep_snprintf(bf, size, "%-*s", width, out);
899}
900
Don Zickus9b32ba72014-06-01 15:38:29 +0200901static inline u64 cl_address(u64 address)
902{
903 /* return the cacheline of the address */
904 return (address & ~(cacheline_size - 1));
905}
906
907static int64_t
908sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
909{
910 u64 l, r;
911 struct map *l_map, *r_map;
912
913 if (!left->mem_info) return -1;
914 if (!right->mem_info) return 1;
915
916 /* group event types together */
917 if (left->cpumode > right->cpumode) return -1;
918 if (left->cpumode < right->cpumode) return 1;
919
920 l_map = left->mem_info->daddr.map;
921 r_map = right->mem_info->daddr.map;
922
923 /* if both are NULL, jump to sort on al_addr instead */
924 if (!l_map && !r_map)
925 goto addr;
926
927 if (!l_map) return -1;
928 if (!r_map) return 1;
929
930 if (l_map->maj > r_map->maj) return -1;
931 if (l_map->maj < r_map->maj) return 1;
932
933 if (l_map->min > r_map->min) return -1;
934 if (l_map->min < r_map->min) return 1;
935
936 if (l_map->ino > r_map->ino) return -1;
937 if (l_map->ino < r_map->ino) return 1;
938
939 if (l_map->ino_generation > r_map->ino_generation) return -1;
940 if (l_map->ino_generation < r_map->ino_generation) return 1;
941
942 /*
943 * Addresses with no major/minor numbers are assumed to be
944 * anonymous in userspace. Sort those on pid then address.
945 *
946 * The kernel and non-zero major/minor mapped areas are
947 * assumed to be unity mapped. Sort those on address.
948 */
949
950 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
951 (!(l_map->flags & MAP_SHARED)) &&
952 !l_map->maj && !l_map->min && !l_map->ino &&
953 !l_map->ino_generation) {
954 /* userspace anonymous */
955
956 if (left->thread->pid_ > right->thread->pid_) return -1;
957 if (left->thread->pid_ < right->thread->pid_) return 1;
958 }
959
960addr:
961 /* al_addr does all the right addr - start + offset calculations */
962 l = cl_address(left->mem_info->daddr.al_addr);
963 r = cl_address(right->mem_info->daddr.al_addr);
964
965 if (l > r) return -1;
966 if (l < r) return 1;
967
968 return 0;
969}
970
971static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
972 size_t size, unsigned int width)
973{
974
975 uint64_t addr = 0;
976 struct map *map = NULL;
977 struct symbol *sym = NULL;
978 char level = he->level;
979
980 if (he->mem_info) {
981 addr = cl_address(he->mem_info->daddr.al_addr);
982 map = he->mem_info->daddr.map;
983 sym = he->mem_info->daddr.sym;
984
985 /* print [s] for shared data mmaps */
986 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
987 map && (map->type == MAP__VARIABLE) &&
988 (map->flags & MAP_SHARED) &&
989 (map->maj || map->min || map->ino ||
990 map->ino_generation))
991 level = 's';
992 else if (!map)
993 level = 'X';
994 }
995 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
996 width);
997}
998
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100999struct sort_entry sort_mispredict = {
1000 .se_header = "Branch Mispredicted",
1001 .se_cmp = sort__mispredict_cmp,
1002 .se_snprintf = hist_entry__mispredict_snprintf,
1003 .se_width_idx = HISTC_MISPREDICT,
1004};
1005
Andi Kleen05484292013-01-24 16:10:29 +01001006static u64 he_weight(struct hist_entry *he)
1007{
1008 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1009}
1010
1011static int64_t
1012sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1013{
1014 return he_weight(left) - he_weight(right);
1015}
1016
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001017static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001018 size_t size, unsigned int width)
1019{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001020 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001021}
1022
1023struct sort_entry sort_local_weight = {
1024 .se_header = "Local Weight",
1025 .se_cmp = sort__local_weight_cmp,
1026 .se_snprintf = hist_entry__local_weight_snprintf,
1027 .se_width_idx = HISTC_LOCAL_WEIGHT,
1028};
1029
1030static int64_t
1031sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1032{
1033 return left->stat.weight - right->stat.weight;
1034}
1035
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001036static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001037 size_t size, unsigned int width)
1038{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001039 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001040}
1041
1042struct sort_entry sort_global_weight = {
1043 .se_header = "Weight",
1044 .se_cmp = sort__global_weight_cmp,
1045 .se_snprintf = hist_entry__global_weight_snprintf,
1046 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1047};
1048
Stephane Eranian98a3b322013-01-24 16:10:35 +01001049struct sort_entry sort_mem_daddr_sym = {
1050 .se_header = "Data Symbol",
1051 .se_cmp = sort__daddr_cmp,
1052 .se_snprintf = hist_entry__daddr_snprintf,
1053 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1054};
1055
1056struct sort_entry sort_mem_daddr_dso = {
1057 .se_header = "Data Object",
1058 .se_cmp = sort__dso_daddr_cmp,
1059 .se_snprintf = hist_entry__dso_daddr_snprintf,
1060 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1061};
1062
1063struct sort_entry sort_mem_locked = {
1064 .se_header = "Locked",
1065 .se_cmp = sort__locked_cmp,
1066 .se_snprintf = hist_entry__locked_snprintf,
1067 .se_width_idx = HISTC_MEM_LOCKED,
1068};
1069
1070struct sort_entry sort_mem_tlb = {
1071 .se_header = "TLB access",
1072 .se_cmp = sort__tlb_cmp,
1073 .se_snprintf = hist_entry__tlb_snprintf,
1074 .se_width_idx = HISTC_MEM_TLB,
1075};
1076
1077struct sort_entry sort_mem_lvl = {
1078 .se_header = "Memory access",
1079 .se_cmp = sort__lvl_cmp,
1080 .se_snprintf = hist_entry__lvl_snprintf,
1081 .se_width_idx = HISTC_MEM_LVL,
1082};
1083
1084struct sort_entry sort_mem_snoop = {
1085 .se_header = "Snoop",
1086 .se_cmp = sort__snoop_cmp,
1087 .se_snprintf = hist_entry__snoop_snprintf,
1088 .se_width_idx = HISTC_MEM_SNOOP,
1089};
1090
Don Zickus9b32ba72014-06-01 15:38:29 +02001091struct sort_entry sort_mem_dcacheline = {
1092 .se_header = "Data Cacheline",
1093 .se_cmp = sort__dcacheline_cmp,
1094 .se_snprintf = hist_entry__dcacheline_snprintf,
1095 .se_width_idx = HISTC_MEM_DCACHELINE,
1096};
1097
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001098static int64_t
1099sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1100{
Jiri Olsa49f47442014-10-16 16:07:01 +02001101 if (!left->branch_info || !right->branch_info)
1102 return cmp_null(left->branch_info, right->branch_info);
1103
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001104 return left->branch_info->flags.abort !=
1105 right->branch_info->flags.abort;
1106}
1107
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001108static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001109 size_t size, unsigned int width)
1110{
Jiri Olsa49f47442014-10-16 16:07:01 +02001111 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001112
Jiri Olsa49f47442014-10-16 16:07:01 +02001113 if (he->branch_info) {
1114 if (he->branch_info->flags.abort)
1115 out = "A";
1116 else
1117 out = ".";
1118 }
1119
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001120 return repsep_snprintf(bf, size, "%-*s", width, out);
1121}
1122
1123struct sort_entry sort_abort = {
1124 .se_header = "Transaction abort",
1125 .se_cmp = sort__abort_cmp,
1126 .se_snprintf = hist_entry__abort_snprintf,
1127 .se_width_idx = HISTC_ABORT,
1128};
1129
1130static int64_t
1131sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1132{
Jiri Olsa0199d242014-10-16 16:07:02 +02001133 if (!left->branch_info || !right->branch_info)
1134 return cmp_null(left->branch_info, right->branch_info);
1135
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001136 return left->branch_info->flags.in_tx !=
1137 right->branch_info->flags.in_tx;
1138}
1139
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001140static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001141 size_t size, unsigned int width)
1142{
Jiri Olsa0199d242014-10-16 16:07:02 +02001143 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001144
Jiri Olsa0199d242014-10-16 16:07:02 +02001145 if (he->branch_info) {
1146 if (he->branch_info->flags.in_tx)
1147 out = "T";
1148 else
1149 out = ".";
1150 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001151
1152 return repsep_snprintf(bf, size, "%-*s", width, out);
1153}
1154
1155struct sort_entry sort_in_tx = {
1156 .se_header = "Branch in transaction",
1157 .se_cmp = sort__in_tx_cmp,
1158 .se_snprintf = hist_entry__in_tx_snprintf,
1159 .se_width_idx = HISTC_IN_TX,
1160};
1161
Andi Kleen475eeab2013-09-20 07:40:43 -07001162static int64_t
1163sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1164{
1165 return left->transaction - right->transaction;
1166}
1167
1168static inline char *add_str(char *p, const char *str)
1169{
1170 strcpy(p, str);
1171 return p + strlen(str);
1172}
1173
1174static struct txbit {
1175 unsigned flag;
1176 const char *name;
1177 int skip_for_len;
1178} txbits[] = {
1179 { PERF_TXN_ELISION, "EL ", 0 },
1180 { PERF_TXN_TRANSACTION, "TX ", 1 },
1181 { PERF_TXN_SYNC, "SYNC ", 1 },
1182 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1183 { PERF_TXN_RETRY, "RETRY ", 0 },
1184 { PERF_TXN_CONFLICT, "CON ", 0 },
1185 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1186 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1187 { 0, NULL, 0 }
1188};
1189
1190int hist_entry__transaction_len(void)
1191{
1192 int i;
1193 int len = 0;
1194
1195 for (i = 0; txbits[i].name; i++) {
1196 if (!txbits[i].skip_for_len)
1197 len += strlen(txbits[i].name);
1198 }
1199 len += 4; /* :XX<space> */
1200 return len;
1201}
1202
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001203static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001204 size_t size, unsigned int width)
1205{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001206 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001207 char buf[128];
1208 char *p = buf;
1209 int i;
1210
1211 buf[0] = 0;
1212 for (i = 0; txbits[i].name; i++)
1213 if (txbits[i].flag & t)
1214 p = add_str(p, txbits[i].name);
1215 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1216 p = add_str(p, "NEITHER ");
1217 if (t & PERF_TXN_ABORT_MASK) {
1218 sprintf(p, ":%" PRIx64,
1219 (t & PERF_TXN_ABORT_MASK) >>
1220 PERF_TXN_ABORT_SHIFT);
1221 p += strlen(p);
1222 }
1223
1224 return repsep_snprintf(bf, size, "%-*s", width, buf);
1225}
1226
1227struct sort_entry sort_transaction = {
1228 .se_header = "Transaction ",
1229 .se_cmp = sort__transaction_cmp,
1230 .se_snprintf = hist_entry__transaction_snprintf,
1231 .se_width_idx = HISTC_TRANSACTION,
1232};
1233
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001234struct sort_dimension {
1235 const char *name;
1236 struct sort_entry *entry;
1237 int taken;
1238};
1239
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001240#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1241
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001242static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001243 DIM(SORT_PID, "pid", sort_thread),
1244 DIM(SORT_COMM, "comm", sort_comm),
1245 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001246 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001247 DIM(SORT_PARENT, "parent", sort_parent),
1248 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001249 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001250 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001251 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1252 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001253 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001254};
1255
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001256#undef DIM
1257
1258#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1259
1260static struct sort_dimension bstack_sort_dimensions[] = {
1261 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1262 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1263 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1264 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1265 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001266 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1267 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001268 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001269};
1270
1271#undef DIM
1272
Namhyung Kimafab87b2013-04-03 21:26:11 +09001273#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1274
1275static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001276 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1277 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1278 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1279 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1280 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1281 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001282 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001283};
1284
1285#undef DIM
1286
Namhyung Kima2ce0672014-03-04 09:06:42 +09001287struct hpp_dimension {
1288 const char *name;
1289 struct perf_hpp_fmt *fmt;
1290 int taken;
1291};
1292
1293#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1294
1295static struct hpp_dimension hpp_sort_dimensions[] = {
1296 DIM(PERF_HPP__OVERHEAD, "overhead"),
1297 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1298 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1299 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1300 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001301 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001302 DIM(PERF_HPP__SAMPLES, "sample"),
1303 DIM(PERF_HPP__PERIOD, "period"),
1304};
1305
1306#undef DIM
1307
Namhyung Kim8b536992014-03-03 11:46:55 +09001308struct hpp_sort_entry {
1309 struct perf_hpp_fmt hpp;
1310 struct sort_entry *se;
1311};
1312
Namhyung Kima7d945b2014-03-04 10:46:34 +09001313bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1314{
1315 struct hpp_sort_entry *hse_a;
1316 struct hpp_sort_entry *hse_b;
1317
1318 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1319 return false;
1320
1321 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1322 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1323
1324 return hse_a->se == hse_b->se;
1325}
1326
Namhyung Kime0d66c72014-07-31 14:47:37 +09001327void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001328{
1329 struct hpp_sort_entry *hse;
1330
1331 if (!perf_hpp__is_sort_entry(fmt))
1332 return;
1333
1334 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001335 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001336}
1337
Namhyung Kim8b536992014-03-03 11:46:55 +09001338static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1339 struct perf_evsel *evsel)
1340{
1341 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001342 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001343
1344 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001345
Namhyung Kim5b591662014-07-31 14:47:38 +09001346 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001347 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001348
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001349 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001350}
1351
1352static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1353 struct perf_hpp *hpp __maybe_unused,
1354 struct perf_evsel *evsel)
1355{
1356 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001357 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001358
1359 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1360
Namhyung Kim5b591662014-07-31 14:47:38 +09001361 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001362 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001363
1364 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001365}
1366
1367static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1368 struct hist_entry *he)
1369{
1370 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001371 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001372
1373 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001374
1375 if (!len)
1376 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001377
1378 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1379}
1380
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001381static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1382 struct hist_entry *a, struct hist_entry *b)
1383{
1384 struct hpp_sort_entry *hse;
1385
1386 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1387 return hse->se->se_cmp(a, b);
1388}
1389
1390static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1391 struct hist_entry *a, struct hist_entry *b)
1392{
1393 struct hpp_sort_entry *hse;
1394 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1395
1396 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1397 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1398 return collapse_fn(a, b);
1399}
1400
1401static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1402 struct hist_entry *a, struct hist_entry *b)
1403{
1404 struct hpp_sort_entry *hse;
1405 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1406
1407 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1408 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1409 return sort_fn(a, b);
1410}
1411
Namhyung Kima7d945b2014-03-04 10:46:34 +09001412static struct hpp_sort_entry *
1413__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001414{
1415 struct hpp_sort_entry *hse;
1416
1417 hse = malloc(sizeof(*hse));
1418 if (hse == NULL) {
1419 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001420 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001421 }
1422
1423 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001424 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001425 hse->hpp.header = __sort__hpp_header;
1426 hse->hpp.width = __sort__hpp_width;
1427 hse->hpp.entry = __sort__hpp_entry;
1428 hse->hpp.color = NULL;
1429
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001430 hse->hpp.cmp = __sort__hpp_cmp;
1431 hse->hpp.collapse = __sort__hpp_collapse;
1432 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001433
1434 INIT_LIST_HEAD(&hse->hpp.list);
1435 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001436 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001437 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001438 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001439
Namhyung Kima7d945b2014-03-04 10:46:34 +09001440 return hse;
1441}
1442
1443bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1444{
1445 return format->header == __sort__hpp_header;
1446}
1447
1448static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1449{
1450 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1451
1452 if (hse == NULL)
1453 return -1;
1454
Namhyung Kim8b536992014-03-03 11:46:55 +09001455 perf_hpp__register_sort_field(&hse->hpp);
1456 return 0;
1457}
1458
Namhyung Kima7d945b2014-03-04 10:46:34 +09001459static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1460{
1461 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1462
1463 if (hse == NULL)
1464 return -1;
1465
1466 perf_hpp__column_register(&hse->hpp);
1467 return 0;
1468}
1469
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001470static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001471{
1472 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001473 return 0;
1474
Namhyung Kima7d945b2014-03-04 10:46:34 +09001475 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001476 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001477
1478 if (sd->entry->se_collapse)
1479 sort__need_collapse = 1;
1480
Namhyung Kim2f532d092013-04-03 21:26:10 +09001481 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001482
1483 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001484}
1485
Namhyung Kima2ce0672014-03-04 09:06:42 +09001486static int __hpp_dimension__add(struct hpp_dimension *hd)
1487{
1488 if (!hd->taken) {
1489 hd->taken = 1;
1490
1491 perf_hpp__register_sort_field(hd->fmt);
1492 }
1493 return 0;
1494}
1495
Namhyung Kima7d945b2014-03-04 10:46:34 +09001496static int __sort_dimension__add_output(struct sort_dimension *sd)
1497{
1498 if (sd->taken)
1499 return 0;
1500
1501 if (__sort_dimension__add_hpp_output(sd) < 0)
1502 return -1;
1503
1504 sd->taken = 1;
1505 return 0;
1506}
1507
1508static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1509{
1510 if (!hd->taken) {
1511 hd->taken = 1;
1512
1513 perf_hpp__column_register(hd->fmt);
1514 }
1515 return 0;
1516}
1517
John Kacurdd68ada2009-09-24 18:02:49 +02001518int sort_dimension__add(const char *tok)
1519{
1520 unsigned int i;
1521
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001522 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1523 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001524
John Kacurdd68ada2009-09-24 18:02:49 +02001525 if (strncasecmp(tok, sd->name, strlen(tok)))
1526 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001527
John Kacurdd68ada2009-09-24 18:02:49 +02001528 if (sd->entry == &sort_parent) {
1529 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1530 if (ret) {
1531 char err[BUFSIZ];
1532
1533 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001534 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1535 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001536 }
1537 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001538 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001539 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00001540 /*
1541 * perf diff displays the performance difference amongst
1542 * two or more perf.data files. Those files could come
1543 * from different binaries. So we should not compare
1544 * their ips, but the name of symbol.
1545 */
1546 if (sort__mode == SORT_MODE__DIFF)
1547 sd->entry->se_collapse = sort__sym_sort;
1548
Namhyung Kim68f6d022013-12-18 14:21:10 +09001549 } else if (sd->entry == &sort_dso) {
1550 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001551 }
1552
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001553 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001554 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001555
Namhyung Kima2ce0672014-03-04 09:06:42 +09001556 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1557 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1558
1559 if (strncasecmp(tok, hd->name, strlen(tok)))
1560 continue;
1561
1562 return __hpp_dimension__add(hd);
1563 }
1564
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001565 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1566 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1567
1568 if (strncasecmp(tok, sd->name, strlen(tok)))
1569 continue;
1570
Namhyung Kim55369fc2013-04-01 20:35:20 +09001571 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001572 return -EINVAL;
1573
1574 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1575 sort__has_sym = 1;
1576
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001577 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001578 return 0;
1579 }
1580
Namhyung Kimafab87b2013-04-03 21:26:11 +09001581 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1582 struct sort_dimension *sd = &memory_sort_dimensions[i];
1583
1584 if (strncasecmp(tok, sd->name, strlen(tok)))
1585 continue;
1586
1587 if (sort__mode != SORT_MODE__MEMORY)
1588 return -EINVAL;
1589
1590 if (sd->entry == &sort_mem_daddr_sym)
1591 sort__has_sym = 1;
1592
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001593 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001594 return 0;
1595 }
1596
John Kacurdd68ada2009-09-24 18:02:49 +02001597 return -ESRCH;
1598}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001599
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001600static const char *get_default_sort_order(void)
1601{
1602 const char *default_sort_orders[] = {
1603 default_sort_order,
1604 default_branch_sort_order,
1605 default_mem_sort_order,
1606 default_top_sort_order,
1607 default_diff_sort_order,
1608 };
1609
1610 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1611
1612 return default_sort_orders[sort__mode];
1613}
1614
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001615static int setup_sort_order(void)
1616{
1617 char *new_sort_order;
1618
1619 /*
1620 * Append '+'-prefixed sort order to the default sort
1621 * order string.
1622 */
1623 if (!sort_order || is_strict_order(sort_order))
1624 return 0;
1625
1626 if (sort_order[1] == '\0') {
1627 error("Invalid --sort key: `+'");
1628 return -EINVAL;
1629 }
1630
1631 /*
1632 * We allocate new sort_order string, but we never free it,
1633 * because it's checked over the rest of the code.
1634 */
1635 if (asprintf(&new_sort_order, "%s,%s",
1636 get_default_sort_order(), sort_order + 1) < 0) {
1637 error("Not enough memory to set up --sort");
1638 return -ENOMEM;
1639 }
1640
1641 sort_order = new_sort_order;
1642 return 0;
1643}
1644
Namhyung Kima7d945b2014-03-04 10:46:34 +09001645static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001646{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001647 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001648 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001649 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001650
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001651 ret = setup_sort_order();
1652 if (ret)
1653 return ret;
1654
1655 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001656 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001657 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001658 /*
1659 * If user specified field order but no sort order,
1660 * we'll honor it and not add default sort orders.
1661 */
1662 return 0;
1663 }
1664
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001665 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001666 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001667
1668 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001669 if (str == NULL) {
1670 error("Not enough memory to setup sort keys");
1671 return -ENOMEM;
1672 }
1673
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001674 for (tok = strtok_r(str, ", ", &tmp);
1675 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001676 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001677 if (ret == -EINVAL) {
1678 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001679 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001680 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001681 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001682 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001683 }
1684 }
1685
1686 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001687 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001688}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001689
Jiri Olsaf2998422014-05-23 17:15:47 +02001690void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001691{
Jiri Olsaf2998422014-05-23 17:15:47 +02001692 struct perf_hpp_fmt *fmt;
1693 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001694
Jiri Olsaf2998422014-05-23 17:15:47 +02001695 perf_hpp__for_each_format(fmt) {
1696 if (!perf_hpp__is_sort_entry(fmt))
1697 continue;
1698
1699 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1700 if (hse->se->se_width_idx == idx) {
1701 fmt->elide = elide;
1702 break;
1703 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001704 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001705}
1706
Jiri Olsaf2998422014-05-23 17:15:47 +02001707static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001708{
1709 if (list && strlist__nr_entries(list) == 1) {
1710 if (fp != NULL)
1711 fprintf(fp, "# %s: %s\n", list_name,
1712 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001713 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001714 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001715 return false;
1716}
1717
1718static bool get_elide(int idx, FILE *output)
1719{
1720 switch (idx) {
1721 case HISTC_SYMBOL:
1722 return __get_elide(symbol_conf.sym_list, "symbol", output);
1723 case HISTC_DSO:
1724 return __get_elide(symbol_conf.dso_list, "dso", output);
1725 case HISTC_COMM:
1726 return __get_elide(symbol_conf.comm_list, "comm", output);
1727 default:
1728 break;
1729 }
1730
1731 if (sort__mode != SORT_MODE__BRANCH)
1732 return false;
1733
1734 switch (idx) {
1735 case HISTC_SYMBOL_FROM:
1736 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1737 case HISTC_SYMBOL_TO:
1738 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1739 case HISTC_DSO_FROM:
1740 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1741 case HISTC_DSO_TO:
1742 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1743 default:
1744 break;
1745 }
1746
1747 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001748}
Namhyung Kim08e71542013-04-03 21:26:19 +09001749
1750void sort__setup_elide(FILE *output)
1751{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001752 struct perf_hpp_fmt *fmt;
1753 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001754
Jiri Olsaf2998422014-05-23 17:15:47 +02001755 perf_hpp__for_each_format(fmt) {
1756 if (!perf_hpp__is_sort_entry(fmt))
1757 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001758
Jiri Olsaf2998422014-05-23 17:15:47 +02001759 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1760 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001761 }
1762
Namhyung Kim7524f632013-11-08 17:53:42 +09001763 /*
1764 * It makes no sense to elide all of sort entries.
1765 * Just revert them to show up again.
1766 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001767 perf_hpp__for_each_format(fmt) {
1768 if (!perf_hpp__is_sort_entry(fmt))
1769 continue;
1770
Jiri Olsaf2998422014-05-23 17:15:47 +02001771 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001772 return;
1773 }
1774
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001775 perf_hpp__for_each_format(fmt) {
1776 if (!perf_hpp__is_sort_entry(fmt))
1777 continue;
1778
Jiri Olsaf2998422014-05-23 17:15:47 +02001779 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001780 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001781}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001782
1783static int output_field_add(char *tok)
1784{
1785 unsigned int i;
1786
1787 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1788 struct sort_dimension *sd = &common_sort_dimensions[i];
1789
1790 if (strncasecmp(tok, sd->name, strlen(tok)))
1791 continue;
1792
1793 return __sort_dimension__add_output(sd);
1794 }
1795
1796 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1797 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1798
1799 if (strncasecmp(tok, hd->name, strlen(tok)))
1800 continue;
1801
1802 return __hpp_dimension__add_output(hd);
1803 }
1804
1805 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1806 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1807
1808 if (strncasecmp(tok, sd->name, strlen(tok)))
1809 continue;
1810
1811 return __sort_dimension__add_output(sd);
1812 }
1813
1814 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1815 struct sort_dimension *sd = &memory_sort_dimensions[i];
1816
1817 if (strncasecmp(tok, sd->name, strlen(tok)))
1818 continue;
1819
1820 return __sort_dimension__add_output(sd);
1821 }
1822
1823 return -ESRCH;
1824}
1825
1826static void reset_dimensions(void)
1827{
1828 unsigned int i;
1829
1830 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1831 common_sort_dimensions[i].taken = 0;
1832
1833 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1834 hpp_sort_dimensions[i].taken = 0;
1835
1836 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1837 bstack_sort_dimensions[i].taken = 0;
1838
1839 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1840 memory_sort_dimensions[i].taken = 0;
1841}
1842
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001843bool is_strict_order(const char *order)
1844{
1845 return order && (*order != '+');
1846}
1847
Namhyung Kima7d945b2014-03-04 10:46:34 +09001848static int __setup_output_field(void)
1849{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001850 char *tmp, *tok, *str, *strp;
1851 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001852
1853 if (field_order == NULL)
1854 return 0;
1855
1856 reset_dimensions();
1857
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001858 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001859 if (str == NULL) {
1860 error("Not enough memory to setup output fields");
1861 return -ENOMEM;
1862 }
1863
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001864 if (!is_strict_order(field_order))
1865 strp++;
1866
1867 if (!strlen(strp)) {
1868 error("Invalid --fields key: `+'");
1869 goto out;
1870 }
1871
1872 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001873 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1874 ret = output_field_add(tok);
1875 if (ret == -EINVAL) {
1876 error("Invalid --fields key: `%s'", tok);
1877 break;
1878 } else if (ret == -ESRCH) {
1879 error("Unknown --fields key: `%s'", tok);
1880 break;
1881 }
1882 }
1883
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001884out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001885 free(str);
1886 return ret;
1887}
1888
1889int setup_sorting(void)
1890{
1891 int err;
1892
1893 err = __setup_sorting();
1894 if (err < 0)
1895 return err;
1896
1897 if (parent_pattern != default_parent_pattern) {
1898 err = sort_dimension__add("parent");
1899 if (err < 0)
1900 return err;
1901 }
1902
1903 reset_dimensions();
1904
1905 /*
1906 * perf diff doesn't use default hpp output fields.
1907 */
1908 if (sort__mode != SORT_MODE__DIFF)
1909 perf_hpp__init();
1910
1911 err = __setup_output_field();
1912 if (err < 0)
1913 return err;
1914
1915 /* copy sort keys to output fields */
1916 perf_hpp__setup_output_field();
1917 /* and then copy output fields to sort keys */
1918 perf_hpp__append_sort_keys();
1919
1920 return 0;
1921}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001922
1923void reset_output_field(void)
1924{
1925 sort__need_collapse = 0;
1926 sort__has_parent = 0;
1927 sort__has_sym = 0;
1928 sort__has_dso = 0;
1929
Namhyung Kimd69b2962014-05-23 10:59:01 +09001930 field_order = NULL;
1931 sort_order = NULL;
1932
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001933 reset_dimensions();
1934 perf_hpp__reset_output_field();
1935}