blob: 5177088a71d3848262844b31bdf65247e2a13660 [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
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
Andi Kleen0e332f02015-07-18 08:24:46 -0700529static int64_t
530sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
531{
532 return left->branch_info->flags.cycles -
533 right->branch_info->flags.cycles;
534}
535
536static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
537 size_t size, unsigned int width)
538{
539 if (he->branch_info->flags.cycles == 0)
540 return repsep_snprintf(bf, size, "%-*s", width, "-");
541 return repsep_snprintf(bf, size, "%-*hd", width,
542 he->branch_info->flags.cycles);
543}
544
545struct sort_entry sort_cycles = {
546 .se_header = "Basic Block Cycles",
547 .se_cmp = sort__cycles_cmp,
548 .se_snprintf = hist_entry__cycles_snprintf,
549 .se_width_idx = HISTC_CYCLES,
550};
551
Stephane Eranian98a3b322013-01-24 16:10:35 +0100552/* --sort daddr_sym */
553static int64_t
554sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
555{
556 uint64_t l = 0, r = 0;
557
558 if (left->mem_info)
559 l = left->mem_info->daddr.addr;
560 if (right->mem_info)
561 r = right->mem_info->daddr.addr;
562
563 return (int64_t)(r - l);
564}
565
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300566static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100567 size_t size, unsigned int width)
568{
569 uint64_t addr = 0;
570 struct map *map = NULL;
571 struct symbol *sym = NULL;
572
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300573 if (he->mem_info) {
574 addr = he->mem_info->daddr.addr;
575 map = he->mem_info->daddr.map;
576 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100577 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300578 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100579 width);
580}
581
582static int64_t
583sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
584{
585 struct map *map_l = NULL;
586 struct map *map_r = NULL;
587
588 if (left->mem_info)
589 map_l = left->mem_info->daddr.map;
590 if (right->mem_info)
591 map_r = right->mem_info->daddr.map;
592
593 return _sort__dso_cmp(map_l, map_r);
594}
595
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300596static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100597 size_t size, unsigned int width)
598{
599 struct map *map = NULL;
600
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300601 if (he->mem_info)
602 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100603
604 return _hist_entry__dso_snprintf(map, bf, size, width);
605}
606
607static int64_t
608sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
609{
610 union perf_mem_data_src data_src_l;
611 union perf_mem_data_src data_src_r;
612
613 if (left->mem_info)
614 data_src_l = left->mem_info->data_src;
615 else
616 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
617
618 if (right->mem_info)
619 data_src_r = right->mem_info->data_src;
620 else
621 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
622
623 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
624}
625
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300626static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100627 size_t size, unsigned int width)
628{
629 const char *out;
630 u64 mask = PERF_MEM_LOCK_NA;
631
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300632 if (he->mem_info)
633 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100634
635 if (mask & PERF_MEM_LOCK_NA)
636 out = "N/A";
637 else if (mask & PERF_MEM_LOCK_LOCKED)
638 out = "Yes";
639 else
640 out = "No";
641
642 return repsep_snprintf(bf, size, "%-*s", width, out);
643}
644
645static int64_t
646sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
647{
648 union perf_mem_data_src data_src_l;
649 union perf_mem_data_src data_src_r;
650
651 if (left->mem_info)
652 data_src_l = left->mem_info->data_src;
653 else
654 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
655
656 if (right->mem_info)
657 data_src_r = right->mem_info->data_src;
658 else
659 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
660
661 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
662}
663
664static const char * const tlb_access[] = {
665 "N/A",
666 "HIT",
667 "MISS",
668 "L1",
669 "L2",
670 "Walker",
671 "Fault",
672};
673#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
674
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300675static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100676 size_t size, unsigned int width)
677{
678 char out[64];
679 size_t sz = sizeof(out) - 1; /* -1 for null termination */
680 size_t l = 0, i;
681 u64 m = PERF_MEM_TLB_NA;
682 u64 hit, miss;
683
684 out[0] = '\0';
685
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300686 if (he->mem_info)
687 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100688
689 hit = m & PERF_MEM_TLB_HIT;
690 miss = m & PERF_MEM_TLB_MISS;
691
692 /* already taken care of */
693 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
694
695 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
696 if (!(m & 0x1))
697 continue;
698 if (l) {
699 strcat(out, " or ");
700 l += 4;
701 }
702 strncat(out, tlb_access[i], sz - l);
703 l += strlen(tlb_access[i]);
704 }
705 if (*out == '\0')
706 strcpy(out, "N/A");
707 if (hit)
708 strncat(out, " hit", sz - l);
709 if (miss)
710 strncat(out, " miss", sz - l);
711
712 return repsep_snprintf(bf, size, "%-*s", width, out);
713}
714
715static int64_t
716sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
717{
718 union perf_mem_data_src data_src_l;
719 union perf_mem_data_src data_src_r;
720
721 if (left->mem_info)
722 data_src_l = left->mem_info->data_src;
723 else
724 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
725
726 if (right->mem_info)
727 data_src_r = right->mem_info->data_src;
728 else
729 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
730
731 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
732}
733
734static const char * const mem_lvl[] = {
735 "N/A",
736 "HIT",
737 "MISS",
738 "L1",
739 "LFB",
740 "L2",
741 "L3",
742 "Local RAM",
743 "Remote RAM (1 hop)",
744 "Remote RAM (2 hops)",
745 "Remote Cache (1 hop)",
746 "Remote Cache (2 hops)",
747 "I/O",
748 "Uncached",
749};
750#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
751
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300752static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100753 size_t size, unsigned int width)
754{
755 char out[64];
756 size_t sz = sizeof(out) - 1; /* -1 for null termination */
757 size_t i, l = 0;
758 u64 m = PERF_MEM_LVL_NA;
759 u64 hit, miss;
760
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300761 if (he->mem_info)
762 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100763
764 out[0] = '\0';
765
766 hit = m & PERF_MEM_LVL_HIT;
767 miss = m & PERF_MEM_LVL_MISS;
768
769 /* already taken care of */
770 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
771
772 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
773 if (!(m & 0x1))
774 continue;
775 if (l) {
776 strcat(out, " or ");
777 l += 4;
778 }
779 strncat(out, mem_lvl[i], sz - l);
780 l += strlen(mem_lvl[i]);
781 }
782 if (*out == '\0')
783 strcpy(out, "N/A");
784 if (hit)
785 strncat(out, " hit", sz - l);
786 if (miss)
787 strncat(out, " miss", sz - l);
788
789 return repsep_snprintf(bf, size, "%-*s", width, out);
790}
791
792static int64_t
793sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
794{
795 union perf_mem_data_src data_src_l;
796 union perf_mem_data_src data_src_r;
797
798 if (left->mem_info)
799 data_src_l = left->mem_info->data_src;
800 else
801 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
802
803 if (right->mem_info)
804 data_src_r = right->mem_info->data_src;
805 else
806 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
807
808 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
809}
810
811static const char * const snoop_access[] = {
812 "N/A",
813 "None",
814 "Miss",
815 "Hit",
816 "HitM",
817};
818#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
819
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300820static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100821 size_t size, unsigned int width)
822{
823 char out[64];
824 size_t sz = sizeof(out) - 1; /* -1 for null termination */
825 size_t i, l = 0;
826 u64 m = PERF_MEM_SNOOP_NA;
827
828 out[0] = '\0';
829
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300830 if (he->mem_info)
831 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100832
833 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
834 if (!(m & 0x1))
835 continue;
836 if (l) {
837 strcat(out, " or ");
838 l += 4;
839 }
840 strncat(out, snoop_access[i], sz - l);
841 l += strlen(snoop_access[i]);
842 }
843
844 if (*out == '\0')
845 strcpy(out, "N/A");
846
847 return repsep_snprintf(bf, size, "%-*s", width, out);
848}
849
Don Zickus9b32ba72014-06-01 15:38:29 +0200850static inline u64 cl_address(u64 address)
851{
852 /* return the cacheline of the address */
853 return (address & ~(cacheline_size - 1));
854}
855
856static int64_t
857sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
858{
859 u64 l, r;
860 struct map *l_map, *r_map;
861
862 if (!left->mem_info) return -1;
863 if (!right->mem_info) return 1;
864
865 /* group event types together */
866 if (left->cpumode > right->cpumode) return -1;
867 if (left->cpumode < right->cpumode) return 1;
868
869 l_map = left->mem_info->daddr.map;
870 r_map = right->mem_info->daddr.map;
871
872 /* if both are NULL, jump to sort on al_addr instead */
873 if (!l_map && !r_map)
874 goto addr;
875
876 if (!l_map) return -1;
877 if (!r_map) return 1;
878
879 if (l_map->maj > r_map->maj) return -1;
880 if (l_map->maj < r_map->maj) return 1;
881
882 if (l_map->min > r_map->min) return -1;
883 if (l_map->min < r_map->min) return 1;
884
885 if (l_map->ino > r_map->ino) return -1;
886 if (l_map->ino < r_map->ino) return 1;
887
888 if (l_map->ino_generation > r_map->ino_generation) return -1;
889 if (l_map->ino_generation < r_map->ino_generation) return 1;
890
891 /*
892 * Addresses with no major/minor numbers are assumed to be
893 * anonymous in userspace. Sort those on pid then address.
894 *
895 * The kernel and non-zero major/minor mapped areas are
896 * assumed to be unity mapped. Sort those on address.
897 */
898
899 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
900 (!(l_map->flags & MAP_SHARED)) &&
901 !l_map->maj && !l_map->min && !l_map->ino &&
902 !l_map->ino_generation) {
903 /* userspace anonymous */
904
905 if (left->thread->pid_ > right->thread->pid_) return -1;
906 if (left->thread->pid_ < right->thread->pid_) return 1;
907 }
908
909addr:
910 /* al_addr does all the right addr - start + offset calculations */
911 l = cl_address(left->mem_info->daddr.al_addr);
912 r = cl_address(right->mem_info->daddr.al_addr);
913
914 if (l > r) return -1;
915 if (l < r) return 1;
916
917 return 0;
918}
919
920static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
921 size_t size, unsigned int width)
922{
923
924 uint64_t addr = 0;
925 struct map *map = NULL;
926 struct symbol *sym = NULL;
927 char level = he->level;
928
929 if (he->mem_info) {
930 addr = cl_address(he->mem_info->daddr.al_addr);
931 map = he->mem_info->daddr.map;
932 sym = he->mem_info->daddr.sym;
933
934 /* print [s] for shared data mmaps */
935 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
936 map && (map->type == MAP__VARIABLE) &&
937 (map->flags & MAP_SHARED) &&
938 (map->maj || map->min || map->ino ||
939 map->ino_generation))
940 level = 's';
941 else if (!map)
942 level = 'X';
943 }
944 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
945 width);
946}
947
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100948struct sort_entry sort_mispredict = {
949 .se_header = "Branch Mispredicted",
950 .se_cmp = sort__mispredict_cmp,
951 .se_snprintf = hist_entry__mispredict_snprintf,
952 .se_width_idx = HISTC_MISPREDICT,
953};
954
Andi Kleen05484292013-01-24 16:10:29 +0100955static u64 he_weight(struct hist_entry *he)
956{
957 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
958}
959
960static int64_t
961sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
962{
963 return he_weight(left) - he_weight(right);
964}
965
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300966static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100967 size_t size, unsigned int width)
968{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300969 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100970}
971
972struct sort_entry sort_local_weight = {
973 .se_header = "Local Weight",
974 .se_cmp = sort__local_weight_cmp,
975 .se_snprintf = hist_entry__local_weight_snprintf,
976 .se_width_idx = HISTC_LOCAL_WEIGHT,
977};
978
979static int64_t
980sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
981{
982 return left->stat.weight - right->stat.weight;
983}
984
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300985static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100986 size_t size, unsigned int width)
987{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300988 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100989}
990
991struct sort_entry sort_global_weight = {
992 .se_header = "Weight",
993 .se_cmp = sort__global_weight_cmp,
994 .se_snprintf = hist_entry__global_weight_snprintf,
995 .se_width_idx = HISTC_GLOBAL_WEIGHT,
996};
997
Stephane Eranian98a3b322013-01-24 16:10:35 +0100998struct sort_entry sort_mem_daddr_sym = {
999 .se_header = "Data Symbol",
1000 .se_cmp = sort__daddr_cmp,
1001 .se_snprintf = hist_entry__daddr_snprintf,
1002 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1003};
1004
1005struct sort_entry sort_mem_daddr_dso = {
1006 .se_header = "Data Object",
1007 .se_cmp = sort__dso_daddr_cmp,
1008 .se_snprintf = hist_entry__dso_daddr_snprintf,
1009 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1010};
1011
1012struct sort_entry sort_mem_locked = {
1013 .se_header = "Locked",
1014 .se_cmp = sort__locked_cmp,
1015 .se_snprintf = hist_entry__locked_snprintf,
1016 .se_width_idx = HISTC_MEM_LOCKED,
1017};
1018
1019struct sort_entry sort_mem_tlb = {
1020 .se_header = "TLB access",
1021 .se_cmp = sort__tlb_cmp,
1022 .se_snprintf = hist_entry__tlb_snprintf,
1023 .se_width_idx = HISTC_MEM_TLB,
1024};
1025
1026struct sort_entry sort_mem_lvl = {
1027 .se_header = "Memory access",
1028 .se_cmp = sort__lvl_cmp,
1029 .se_snprintf = hist_entry__lvl_snprintf,
1030 .se_width_idx = HISTC_MEM_LVL,
1031};
1032
1033struct sort_entry sort_mem_snoop = {
1034 .se_header = "Snoop",
1035 .se_cmp = sort__snoop_cmp,
1036 .se_snprintf = hist_entry__snoop_snprintf,
1037 .se_width_idx = HISTC_MEM_SNOOP,
1038};
1039
Don Zickus9b32ba72014-06-01 15:38:29 +02001040struct sort_entry sort_mem_dcacheline = {
1041 .se_header = "Data Cacheline",
1042 .se_cmp = sort__dcacheline_cmp,
1043 .se_snprintf = hist_entry__dcacheline_snprintf,
1044 .se_width_idx = HISTC_MEM_DCACHELINE,
1045};
1046
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001047static int64_t
1048sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1049{
Jiri Olsa49f47442014-10-16 16:07:01 +02001050 if (!left->branch_info || !right->branch_info)
1051 return cmp_null(left->branch_info, right->branch_info);
1052
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001053 return left->branch_info->flags.abort !=
1054 right->branch_info->flags.abort;
1055}
1056
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001057static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001058 size_t size, unsigned int width)
1059{
Jiri Olsa49f47442014-10-16 16:07:01 +02001060 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001061
Jiri Olsa49f47442014-10-16 16:07:01 +02001062 if (he->branch_info) {
1063 if (he->branch_info->flags.abort)
1064 out = "A";
1065 else
1066 out = ".";
1067 }
1068
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001069 return repsep_snprintf(bf, size, "%-*s", width, out);
1070}
1071
1072struct sort_entry sort_abort = {
1073 .se_header = "Transaction abort",
1074 .se_cmp = sort__abort_cmp,
1075 .se_snprintf = hist_entry__abort_snprintf,
1076 .se_width_idx = HISTC_ABORT,
1077};
1078
1079static int64_t
1080sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1081{
Jiri Olsa0199d242014-10-16 16:07:02 +02001082 if (!left->branch_info || !right->branch_info)
1083 return cmp_null(left->branch_info, right->branch_info);
1084
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001085 return left->branch_info->flags.in_tx !=
1086 right->branch_info->flags.in_tx;
1087}
1088
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001089static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001090 size_t size, unsigned int width)
1091{
Jiri Olsa0199d242014-10-16 16:07:02 +02001092 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001093
Jiri Olsa0199d242014-10-16 16:07:02 +02001094 if (he->branch_info) {
1095 if (he->branch_info->flags.in_tx)
1096 out = "T";
1097 else
1098 out = ".";
1099 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001100
1101 return repsep_snprintf(bf, size, "%-*s", width, out);
1102}
1103
1104struct sort_entry sort_in_tx = {
1105 .se_header = "Branch in transaction",
1106 .se_cmp = sort__in_tx_cmp,
1107 .se_snprintf = hist_entry__in_tx_snprintf,
1108 .se_width_idx = HISTC_IN_TX,
1109};
1110
Andi Kleen475eeab2013-09-20 07:40:43 -07001111static int64_t
1112sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1113{
1114 return left->transaction - right->transaction;
1115}
1116
1117static inline char *add_str(char *p, const char *str)
1118{
1119 strcpy(p, str);
1120 return p + strlen(str);
1121}
1122
1123static struct txbit {
1124 unsigned flag;
1125 const char *name;
1126 int skip_for_len;
1127} txbits[] = {
1128 { PERF_TXN_ELISION, "EL ", 0 },
1129 { PERF_TXN_TRANSACTION, "TX ", 1 },
1130 { PERF_TXN_SYNC, "SYNC ", 1 },
1131 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1132 { PERF_TXN_RETRY, "RETRY ", 0 },
1133 { PERF_TXN_CONFLICT, "CON ", 0 },
1134 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1135 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1136 { 0, NULL, 0 }
1137};
1138
1139int hist_entry__transaction_len(void)
1140{
1141 int i;
1142 int len = 0;
1143
1144 for (i = 0; txbits[i].name; i++) {
1145 if (!txbits[i].skip_for_len)
1146 len += strlen(txbits[i].name);
1147 }
1148 len += 4; /* :XX<space> */
1149 return len;
1150}
1151
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001152static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001153 size_t size, unsigned int width)
1154{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001155 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001156 char buf[128];
1157 char *p = buf;
1158 int i;
1159
1160 buf[0] = 0;
1161 for (i = 0; txbits[i].name; i++)
1162 if (txbits[i].flag & t)
1163 p = add_str(p, txbits[i].name);
1164 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1165 p = add_str(p, "NEITHER ");
1166 if (t & PERF_TXN_ABORT_MASK) {
1167 sprintf(p, ":%" PRIx64,
1168 (t & PERF_TXN_ABORT_MASK) >>
1169 PERF_TXN_ABORT_SHIFT);
1170 p += strlen(p);
1171 }
1172
1173 return repsep_snprintf(bf, size, "%-*s", width, buf);
1174}
1175
1176struct sort_entry sort_transaction = {
1177 .se_header = "Transaction ",
1178 .se_cmp = sort__transaction_cmp,
1179 .se_snprintf = hist_entry__transaction_snprintf,
1180 .se_width_idx = HISTC_TRANSACTION,
1181};
1182
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001183struct sort_dimension {
1184 const char *name;
1185 struct sort_entry *entry;
1186 int taken;
1187};
1188
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001189#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1190
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001191static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001192 DIM(SORT_PID, "pid", sort_thread),
1193 DIM(SORT_COMM, "comm", sort_comm),
1194 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001195 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001196 DIM(SORT_PARENT, "parent", sort_parent),
1197 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001198 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001199 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1200 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001201 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001202};
1203
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001204#undef DIM
1205
1206#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1207
1208static struct sort_dimension bstack_sort_dimensions[] = {
1209 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1210 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1211 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1212 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1213 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001214 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1215 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001216 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001217};
1218
1219#undef DIM
1220
Namhyung Kimafab87b2013-04-03 21:26:11 +09001221#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1222
1223static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001224 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1225 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1226 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1227 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1228 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1229 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001230 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001231};
1232
1233#undef DIM
1234
Namhyung Kima2ce0672014-03-04 09:06:42 +09001235struct hpp_dimension {
1236 const char *name;
1237 struct perf_hpp_fmt *fmt;
1238 int taken;
1239};
1240
1241#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1242
1243static struct hpp_dimension hpp_sort_dimensions[] = {
1244 DIM(PERF_HPP__OVERHEAD, "overhead"),
1245 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1246 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1247 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1248 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001249 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001250 DIM(PERF_HPP__SAMPLES, "sample"),
1251 DIM(PERF_HPP__PERIOD, "period"),
1252};
1253
1254#undef DIM
1255
Namhyung Kim8b536992014-03-03 11:46:55 +09001256struct hpp_sort_entry {
1257 struct perf_hpp_fmt hpp;
1258 struct sort_entry *se;
1259};
1260
Namhyung Kima7d945b2014-03-04 10:46:34 +09001261bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1262{
1263 struct hpp_sort_entry *hse_a;
1264 struct hpp_sort_entry *hse_b;
1265
1266 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1267 return false;
1268
1269 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1270 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1271
1272 return hse_a->se == hse_b->se;
1273}
1274
Namhyung Kime0d66c72014-07-31 14:47:37 +09001275void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001276{
1277 struct hpp_sort_entry *hse;
1278
1279 if (!perf_hpp__is_sort_entry(fmt))
1280 return;
1281
1282 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001283 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001284}
1285
Namhyung Kim8b536992014-03-03 11:46:55 +09001286static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1287 struct perf_evsel *evsel)
1288{
1289 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001290 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001291
1292 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001293
Namhyung Kim5b591662014-07-31 14:47:38 +09001294 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001295 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001296
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001297 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001298}
1299
1300static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1301 struct perf_hpp *hpp __maybe_unused,
1302 struct perf_evsel *evsel)
1303{
1304 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001305 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001306
1307 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1308
Namhyung Kim5b591662014-07-31 14:47:38 +09001309 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001310 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001311
1312 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001313}
1314
1315static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1316 struct hist_entry *he)
1317{
1318 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001319 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001320
1321 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001322
1323 if (!len)
1324 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001325
1326 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1327}
1328
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001329static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1330 struct hist_entry *a, struct hist_entry *b)
1331{
1332 struct hpp_sort_entry *hse;
1333
1334 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1335 return hse->se->se_cmp(a, b);
1336}
1337
1338static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1339 struct hist_entry *a, struct hist_entry *b)
1340{
1341 struct hpp_sort_entry *hse;
1342 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1343
1344 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1345 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1346 return collapse_fn(a, b);
1347}
1348
1349static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1350 struct hist_entry *a, struct hist_entry *b)
1351{
1352 struct hpp_sort_entry *hse;
1353 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1354
1355 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1356 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1357 return sort_fn(a, b);
1358}
1359
Namhyung Kima7d945b2014-03-04 10:46:34 +09001360static struct hpp_sort_entry *
1361__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001362{
1363 struct hpp_sort_entry *hse;
1364
1365 hse = malloc(sizeof(*hse));
1366 if (hse == NULL) {
1367 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001368 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001369 }
1370
1371 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001372 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001373 hse->hpp.header = __sort__hpp_header;
1374 hse->hpp.width = __sort__hpp_width;
1375 hse->hpp.entry = __sort__hpp_entry;
1376 hse->hpp.color = NULL;
1377
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001378 hse->hpp.cmp = __sort__hpp_cmp;
1379 hse->hpp.collapse = __sort__hpp_collapse;
1380 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001381
1382 INIT_LIST_HEAD(&hse->hpp.list);
1383 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001384 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001385 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001386 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001387
Namhyung Kima7d945b2014-03-04 10:46:34 +09001388 return hse;
1389}
1390
1391bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1392{
1393 return format->header == __sort__hpp_header;
1394}
1395
1396static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1397{
1398 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1399
1400 if (hse == NULL)
1401 return -1;
1402
Namhyung Kim8b536992014-03-03 11:46:55 +09001403 perf_hpp__register_sort_field(&hse->hpp);
1404 return 0;
1405}
1406
Namhyung Kima7d945b2014-03-04 10:46:34 +09001407static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1408{
1409 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1410
1411 if (hse == NULL)
1412 return -1;
1413
1414 perf_hpp__column_register(&hse->hpp);
1415 return 0;
1416}
1417
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001418static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09001419{
1420 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001421 return 0;
1422
Namhyung Kima7d945b2014-03-04 10:46:34 +09001423 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001424 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001425
1426 if (sd->entry->se_collapse)
1427 sort__need_collapse = 1;
1428
Namhyung Kim2f532d092013-04-03 21:26:10 +09001429 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001430
1431 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09001432}
1433
Namhyung Kima2ce0672014-03-04 09:06:42 +09001434static int __hpp_dimension__add(struct hpp_dimension *hd)
1435{
1436 if (!hd->taken) {
1437 hd->taken = 1;
1438
1439 perf_hpp__register_sort_field(hd->fmt);
1440 }
1441 return 0;
1442}
1443
Namhyung Kima7d945b2014-03-04 10:46:34 +09001444static int __sort_dimension__add_output(struct sort_dimension *sd)
1445{
1446 if (sd->taken)
1447 return 0;
1448
1449 if (__sort_dimension__add_hpp_output(sd) < 0)
1450 return -1;
1451
1452 sd->taken = 1;
1453 return 0;
1454}
1455
1456static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1457{
1458 if (!hd->taken) {
1459 hd->taken = 1;
1460
1461 perf_hpp__column_register(hd->fmt);
1462 }
1463 return 0;
1464}
1465
John Kacurdd68ada2009-09-24 18:02:49 +02001466int sort_dimension__add(const char *tok)
1467{
1468 unsigned int i;
1469
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001470 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1471 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001472
John Kacurdd68ada2009-09-24 18:02:49 +02001473 if (strncasecmp(tok, sd->name, strlen(tok)))
1474 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001475
John Kacurdd68ada2009-09-24 18:02:49 +02001476 if (sd->entry == &sort_parent) {
1477 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1478 if (ret) {
1479 char err[BUFSIZ];
1480
1481 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001482 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1483 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001484 }
1485 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001486 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001487 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00001488 /*
1489 * perf diff displays the performance difference amongst
1490 * two or more perf.data files. Those files could come
1491 * from different binaries. So we should not compare
1492 * their ips, but the name of symbol.
1493 */
1494 if (sort__mode == SORT_MODE__DIFF)
1495 sd->entry->se_collapse = sort__sym_sort;
1496
Namhyung Kim68f6d022013-12-18 14:21:10 +09001497 } else if (sd->entry == &sort_dso) {
1498 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001499 }
1500
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001501 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001502 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001503
Namhyung Kima2ce0672014-03-04 09:06:42 +09001504 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1505 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1506
1507 if (strncasecmp(tok, hd->name, strlen(tok)))
1508 continue;
1509
1510 return __hpp_dimension__add(hd);
1511 }
1512
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001513 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1514 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1515
1516 if (strncasecmp(tok, sd->name, strlen(tok)))
1517 continue;
1518
Namhyung Kim55369fc2013-04-01 20:35:20 +09001519 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001520 return -EINVAL;
1521
1522 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1523 sort__has_sym = 1;
1524
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001525 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001526 return 0;
1527 }
1528
Namhyung Kimafab87b2013-04-03 21:26:11 +09001529 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1530 struct sort_dimension *sd = &memory_sort_dimensions[i];
1531
1532 if (strncasecmp(tok, sd->name, strlen(tok)))
1533 continue;
1534
1535 if (sort__mode != SORT_MODE__MEMORY)
1536 return -EINVAL;
1537
1538 if (sd->entry == &sort_mem_daddr_sym)
1539 sort__has_sym = 1;
1540
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001541 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001542 return 0;
1543 }
1544
John Kacurdd68ada2009-09-24 18:02:49 +02001545 return -ESRCH;
1546}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001547
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001548static const char *get_default_sort_order(void)
1549{
1550 const char *default_sort_orders[] = {
1551 default_sort_order,
1552 default_branch_sort_order,
1553 default_mem_sort_order,
1554 default_top_sort_order,
1555 default_diff_sort_order,
1556 };
1557
1558 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1559
1560 return default_sort_orders[sort__mode];
1561}
1562
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001563static int setup_sort_order(void)
1564{
1565 char *new_sort_order;
1566
1567 /*
1568 * Append '+'-prefixed sort order to the default sort
1569 * order string.
1570 */
1571 if (!sort_order || is_strict_order(sort_order))
1572 return 0;
1573
1574 if (sort_order[1] == '\0') {
1575 error("Invalid --sort key: `+'");
1576 return -EINVAL;
1577 }
1578
1579 /*
1580 * We allocate new sort_order string, but we never free it,
1581 * because it's checked over the rest of the code.
1582 */
1583 if (asprintf(&new_sort_order, "%s,%s",
1584 get_default_sort_order(), sort_order + 1) < 0) {
1585 error("Not enough memory to set up --sort");
1586 return -ENOMEM;
1587 }
1588
1589 sort_order = new_sort_order;
1590 return 0;
1591}
1592
Namhyung Kima7d945b2014-03-04 10:46:34 +09001593static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001594{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001595 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001596 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001597 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001598
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001599 ret = setup_sort_order();
1600 if (ret)
1601 return ret;
1602
1603 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001604 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001605 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001606 /*
1607 * If user specified field order but no sort order,
1608 * we'll honor it and not add default sort orders.
1609 */
1610 return 0;
1611 }
1612
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001613 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001614 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001615
1616 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001617 if (str == NULL) {
1618 error("Not enough memory to setup sort keys");
1619 return -ENOMEM;
1620 }
1621
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001622 for (tok = strtok_r(str, ", ", &tmp);
1623 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001624 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001625 if (ret == -EINVAL) {
1626 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001627 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001628 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001629 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001630 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001631 }
1632 }
1633
1634 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001635 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001636}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001637
Jiri Olsaf2998422014-05-23 17:15:47 +02001638void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001639{
Jiri Olsaf2998422014-05-23 17:15:47 +02001640 struct perf_hpp_fmt *fmt;
1641 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001642
Jiri Olsaf2998422014-05-23 17:15:47 +02001643 perf_hpp__for_each_format(fmt) {
1644 if (!perf_hpp__is_sort_entry(fmt))
1645 continue;
1646
1647 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1648 if (hse->se->se_width_idx == idx) {
1649 fmt->elide = elide;
1650 break;
1651 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001652 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001653}
1654
Jiri Olsaf2998422014-05-23 17:15:47 +02001655static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001656{
1657 if (list && strlist__nr_entries(list) == 1) {
1658 if (fp != NULL)
1659 fprintf(fp, "# %s: %s\n", list_name,
1660 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001661 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001662 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001663 return false;
1664}
1665
1666static bool get_elide(int idx, FILE *output)
1667{
1668 switch (idx) {
1669 case HISTC_SYMBOL:
1670 return __get_elide(symbol_conf.sym_list, "symbol", output);
1671 case HISTC_DSO:
1672 return __get_elide(symbol_conf.dso_list, "dso", output);
1673 case HISTC_COMM:
1674 return __get_elide(symbol_conf.comm_list, "comm", output);
1675 default:
1676 break;
1677 }
1678
1679 if (sort__mode != SORT_MODE__BRANCH)
1680 return false;
1681
1682 switch (idx) {
1683 case HISTC_SYMBOL_FROM:
1684 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1685 case HISTC_SYMBOL_TO:
1686 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1687 case HISTC_DSO_FROM:
1688 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1689 case HISTC_DSO_TO:
1690 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1691 default:
1692 break;
1693 }
1694
1695 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001696}
Namhyung Kim08e71542013-04-03 21:26:19 +09001697
1698void sort__setup_elide(FILE *output)
1699{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001700 struct perf_hpp_fmt *fmt;
1701 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001702
Jiri Olsaf2998422014-05-23 17:15:47 +02001703 perf_hpp__for_each_format(fmt) {
1704 if (!perf_hpp__is_sort_entry(fmt))
1705 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001706
Jiri Olsaf2998422014-05-23 17:15:47 +02001707 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1708 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001709 }
1710
Namhyung Kim7524f632013-11-08 17:53:42 +09001711 /*
1712 * It makes no sense to elide all of sort entries.
1713 * Just revert them to show up again.
1714 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001715 perf_hpp__for_each_format(fmt) {
1716 if (!perf_hpp__is_sort_entry(fmt))
1717 continue;
1718
Jiri Olsaf2998422014-05-23 17:15:47 +02001719 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001720 return;
1721 }
1722
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001723 perf_hpp__for_each_format(fmt) {
1724 if (!perf_hpp__is_sort_entry(fmt))
1725 continue;
1726
Jiri Olsaf2998422014-05-23 17:15:47 +02001727 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001728 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001729}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001730
1731static int output_field_add(char *tok)
1732{
1733 unsigned int i;
1734
1735 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1736 struct sort_dimension *sd = &common_sort_dimensions[i];
1737
1738 if (strncasecmp(tok, sd->name, strlen(tok)))
1739 continue;
1740
1741 return __sort_dimension__add_output(sd);
1742 }
1743
1744 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1745 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1746
1747 if (strncasecmp(tok, hd->name, strlen(tok)))
1748 continue;
1749
1750 return __hpp_dimension__add_output(hd);
1751 }
1752
1753 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1754 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1755
1756 if (strncasecmp(tok, sd->name, strlen(tok)))
1757 continue;
1758
1759 return __sort_dimension__add_output(sd);
1760 }
1761
1762 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1763 struct sort_dimension *sd = &memory_sort_dimensions[i];
1764
1765 if (strncasecmp(tok, sd->name, strlen(tok)))
1766 continue;
1767
1768 return __sort_dimension__add_output(sd);
1769 }
1770
1771 return -ESRCH;
1772}
1773
1774static void reset_dimensions(void)
1775{
1776 unsigned int i;
1777
1778 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1779 common_sort_dimensions[i].taken = 0;
1780
1781 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1782 hpp_sort_dimensions[i].taken = 0;
1783
1784 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1785 bstack_sort_dimensions[i].taken = 0;
1786
1787 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1788 memory_sort_dimensions[i].taken = 0;
1789}
1790
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001791bool is_strict_order(const char *order)
1792{
1793 return order && (*order != '+');
1794}
1795
Namhyung Kima7d945b2014-03-04 10:46:34 +09001796static int __setup_output_field(void)
1797{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001798 char *tmp, *tok, *str, *strp;
1799 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001800
1801 if (field_order == NULL)
1802 return 0;
1803
1804 reset_dimensions();
1805
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001806 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001807 if (str == NULL) {
1808 error("Not enough memory to setup output fields");
1809 return -ENOMEM;
1810 }
1811
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001812 if (!is_strict_order(field_order))
1813 strp++;
1814
1815 if (!strlen(strp)) {
1816 error("Invalid --fields key: `+'");
1817 goto out;
1818 }
1819
1820 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001821 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1822 ret = output_field_add(tok);
1823 if (ret == -EINVAL) {
1824 error("Invalid --fields key: `%s'", tok);
1825 break;
1826 } else if (ret == -ESRCH) {
1827 error("Unknown --fields key: `%s'", tok);
1828 break;
1829 }
1830 }
1831
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001832out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001833 free(str);
1834 return ret;
1835}
1836
1837int setup_sorting(void)
1838{
1839 int err;
1840
1841 err = __setup_sorting();
1842 if (err < 0)
1843 return err;
1844
1845 if (parent_pattern != default_parent_pattern) {
1846 err = sort_dimension__add("parent");
1847 if (err < 0)
1848 return err;
1849 }
1850
1851 reset_dimensions();
1852
1853 /*
1854 * perf diff doesn't use default hpp output fields.
1855 */
1856 if (sort__mode != SORT_MODE__DIFF)
1857 perf_hpp__init();
1858
1859 err = __setup_output_field();
1860 if (err < 0)
1861 return err;
1862
1863 /* copy sort keys to output fields */
1864 perf_hpp__setup_output_field();
1865 /* and then copy output fields to sort keys */
1866 perf_hpp__append_sort_keys();
1867
1868 return 0;
1869}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001870
1871void reset_output_field(void)
1872{
1873 sort__need_collapse = 0;
1874 sort__has_parent = 0;
1875 sort__has_sym = 0;
1876 sort__has_dso = 0;
1877
Namhyung Kimd69b2962014-05-23 10:59:01 +09001878 field_order = NULL;
1879 sort_order = NULL;
1880
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001881 reset_dimensions();
1882 perf_hpp__reset_output_field();
1883}