blob: 000d6e901841e63abd6a85ce23047774cc46a830 [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"
Namhyung Kim40184c42015-12-23 02:07:01 +09007#include "evlist.h"
8#include <traceevent/event-parse.h>
Jiri Olsa0c877d72016-02-24 09:46:46 +01009#include "mem-events.h"
John Kacurdd68ada2009-09-24 18:02:49 +020010
11regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -030012const char default_parent_pattern[] = "^sys_|^do_page_fault";
13const char *parent_pattern = default_parent_pattern;
14const char default_sort_order[] = "comm,dso,symbol";
Andi Kleen40997d62015-07-18 08:24:53 -070015const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090016const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
17const char default_top_sort_order[] = "dso,symbol";
18const char default_diff_sort_order[] = "dso,symbol";
Namhyung Kimd49dade2015-12-23 02:07:10 +090019const char default_tracepoint_sort_order[] = "trace";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090020const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090021const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080022regex_t ignore_callees_regex;
23int have_ignore_callees = 0;
Namhyung Kim078b8d42016-03-09 23:20:51 +090024int sort__has_comm = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090025enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020026
Arnaldo Carvalho de Melo37d9bb52016-02-12 11:27:51 -030027/*
28 * Replaces all occurrences of a char used with the:
29 *
30 * -t, --field-separator
31 *
32 * option, that uses a special separator character and don't pad with spaces,
33 * replacing all occurances of this separator in symbol names (and other
34 * output) with a '.' character, that thus it's the only non valid separator.
35*/
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030036static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020037{
38 int n;
39 va_list ap;
40
41 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030042 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020043 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030044 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020045
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030046 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020047 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030048 if (sep == NULL)
49 break;
50 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020051 }
John Kacurdd68ada2009-09-24 18:02:49 +020052 }
53 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110054
55 if (n >= (int)size)
56 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020057 return n;
58}
59
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020060static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020061{
62 if (!l && !r)
63 return 0;
64 else if (!l)
65 return -1;
66 else
67 return 1;
68}
69
70/* --sort pid */
71
72static int64_t
73sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
74{
Adrian Hunter38051232013-07-04 16:20:31 +030075 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020076}
77
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030078static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030079 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020080{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020081 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090082
83 width = max(7U, width) - 6;
84 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
85 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020086}
87
Namhyung Kim54430102016-02-25 00:13:37 +090088static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
89{
90 const struct thread *th = arg;
91
92 if (type != HIST_FILTER__THREAD)
93 return -1;
94
95 return th && he->thread != th;
96}
97
Frederic Weisbecker872a8782011-06-29 03:14:52 +020098struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090099 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200100 .se_cmp = sort__thread_cmp,
101 .se_snprintf = hist_entry__thread_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900102 .se_filter = hist_entry__thread_filter,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200103 .se_width_idx = HISTC_THREAD,
104};
105
106/* --sort comm */
107
108static int64_t
109sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
110{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +0200111 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200112 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200113}
114
115static int64_t
116sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
117{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900118 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200119 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200120}
121
Namhyung Kim202e7a62014-03-04 11:01:41 +0900122static int64_t
123sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
124{
125 return strcmp(comm__str(right->comm), comm__str(left->comm));
126}
127
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300128static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300129 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200130{
Namhyung Kim5b591662014-07-31 14:47:38 +0900131 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200132}
133
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900134struct sort_entry sort_comm = {
135 .se_header = "Command",
136 .se_cmp = sort__comm_cmp,
137 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900138 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900139 .se_snprintf = hist_entry__comm_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900140 .se_filter = hist_entry__thread_filter,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900141 .se_width_idx = HISTC_COMM,
142};
143
144/* --sort dso */
145
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100146static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200147{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100148 struct dso *dso_l = map_l ? map_l->dso : NULL;
149 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300150 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200151
152 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900153 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200154
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300155 if (verbose) {
156 dso_name_l = dso_l->long_name;
157 dso_name_r = dso_r->long_name;
158 } else {
159 dso_name_l = dso_l->short_name;
160 dso_name_r = dso_r->short_name;
161 }
162
163 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200164}
165
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100166static int64_t
167sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200168{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900169 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100170}
171
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100172static int _hist_entry__dso_snprintf(struct map *map, char *bf,
173 size_t size, unsigned int width)
174{
175 if (map && map->dso) {
176 const char *dso_name = !verbose ? map->dso->short_name :
177 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900178 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300179 }
John Kacurdd68ada2009-09-24 18:02:49 +0200180
Namhyung Kim5b591662014-07-31 14:47:38 +0900181 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200182}
183
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300184static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100185 size_t size, unsigned int width)
186{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300187 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100188}
189
Namhyung Kim54430102016-02-25 00:13:37 +0900190static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
191{
192 const struct dso *dso = arg;
193
194 if (type != HIST_FILTER__DSO)
195 return -1;
196
197 return dso && (!he->ms.map || he->ms.map->dso != dso);
198}
199
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900200struct sort_entry sort_dso = {
201 .se_header = "Shared Object",
202 .se_cmp = sort__dso_cmp,
203 .se_snprintf = hist_entry__dso_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900204 .se_filter = hist_entry__dso_filter,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900205 .se_width_idx = HISTC_DSO,
206};
207
208/* --sort symbol */
209
Namhyung Kim2037be52013-12-18 14:21:09 +0900210static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
211{
212 return (int64_t)(right_ip - left_ip);
213}
214
Namhyung Kim51f27d12013-02-06 14:57:15 +0900215static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900216{
217 if (!sym_l || !sym_r)
218 return cmp_null(sym_l, sym_r);
219
220 if (sym_l == sym_r)
221 return 0;
222
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700223 if (sym_l->start != sym_r->start)
224 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900225
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700226 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900227}
228
229static int64_t
230sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
231{
Namhyung Kim09600e02013-10-15 11:01:56 +0900232 int64_t ret;
233
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900234 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900235 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900236
Namhyung Kim09600e02013-10-15 11:01:56 +0900237 /*
238 * comparing symbol address alone is not enough since it's a
239 * relative address within a dso.
240 */
Jiri Olsa69849fc2016-05-03 13:54:45 +0200241 if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) {
Namhyung Kim68f6d022013-12-18 14:21:10 +0900242 ret = sort__dso_cmp(left, right);
243 if (ret != 0)
244 return ret;
245 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900246
Namhyung Kim51f27d12013-02-06 14:57:15 +0900247 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900248}
249
Namhyung Kim202e7a62014-03-04 11:01:41 +0900250static int64_t
251sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
252{
253 if (!left->ms.sym || !right->ms.sym)
254 return cmp_null(left->ms.sym, right->ms.sym);
255
256 return strcmp(right->ms.sym->name, left->ms.sym->name);
257}
258
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100259static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
260 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900261 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100262{
263 size_t ret = 0;
264
265 if (verbose) {
266 char o = map ? dso__symtab_origin(map->dso) : '!';
267 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900268 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100269 }
270
271 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100272 if (sym && map) {
273 if (map->type == MAP__VARIABLE) {
274 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
275 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100276 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100277 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300278 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
Stephane Eranian98a3b322013-01-24 16:10:35 +0100279 width - ret,
280 sym->name);
281 }
282 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100283 size_t len = BITS_PER_LONG / 4;
284 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
285 len, ip);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100286 }
287
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300288 return ret;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100289}
290
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300291static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900292 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100293{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300294 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
295 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100296}
John Kacurdd68ada2009-09-24 18:02:49 +0200297
Namhyung Kim54430102016-02-25 00:13:37 +0900298static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
299{
300 const char *sym = arg;
301
302 if (type != HIST_FILTER__SYMBOL)
303 return -1;
304
305 return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
306}
307
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200308struct sort_entry sort_sym = {
309 .se_header = "Symbol",
310 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900311 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200312 .se_snprintf = hist_entry__sym_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900313 .se_filter = hist_entry__sym_filter,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200314 .se_width_idx = HISTC_SYMBOL,
315};
John Kacurdd68ada2009-09-24 18:02:49 +0200316
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300317/* --sort srcline */
318
Namhyung Kimcecaec62016-02-22 09:31:51 +0900319static char *hist_entry__get_srcline(struct hist_entry *he)
320{
321 struct map *map = he->ms.map;
322
323 if (!map)
324 return SRCLINE_UNKNOWN;
325
326 return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
327 he->ms.sym, true);
328}
329
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300330static int64_t
331sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
332{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900333 if (!left->srcline)
334 left->srcline = hist_entry__get_srcline(left);
335 if (!right->srcline)
336 right->srcline = hist_entry__get_srcline(right);
337
Namhyung Kim202e7a62014-03-04 11:01:41 +0900338 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300339}
340
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300341static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900342 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300343{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900344 if (!he->srcline)
345 he->srcline = hist_entry__get_srcline(he);
346
Namhyung Kim2960ed62016-02-22 09:32:33 +0900347 return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300348}
349
350struct sort_entry sort_srcline = {
351 .se_header = "Source:Line",
352 .se_cmp = sort__srcline_cmp,
353 .se_snprintf = hist_entry__srcline_snprintf,
354 .se_width_idx = HISTC_SRCLINE,
355};
356
Andi Kleen31191a82015-08-07 15:54:24 -0700357/* --sort srcfile */
358
359static char no_srcfile[1];
360
Namhyung Kimcecaec62016-02-22 09:31:51 +0900361static char *hist_entry__get_srcfile(struct hist_entry *e)
Andi Kleen31191a82015-08-07 15:54:24 -0700362{
363 char *sf, *p;
364 struct map *map = e->ms.map;
365
Namhyung Kimcecaec62016-02-22 09:31:51 +0900366 if (!map)
367 return no_srcfile;
368
Andi Kleen2f84b422015-09-01 11:47:19 -0700369 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
370 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700371 if (!strcmp(sf, SRCLINE_UNKNOWN))
372 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700373 p = strchr(sf, ':');
374 if (p && *sf) {
375 *p = 0;
376 return sf;
377 }
378 free(sf);
379 return no_srcfile;
380}
381
382static int64_t
383sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
384{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900385 if (!left->srcfile)
386 left->srcfile = hist_entry__get_srcfile(left);
387 if (!right->srcfile)
388 right->srcfile = hist_entry__get_srcfile(right);
389
Andi Kleen31191a82015-08-07 15:54:24 -0700390 return strcmp(right->srcfile, left->srcfile);
391}
392
393static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
394 size_t size, unsigned int width)
395{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900396 if (!he->srcfile)
397 he->srcfile = hist_entry__get_srcfile(he);
398
Namhyung Kim2960ed62016-02-22 09:32:33 +0900399 return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
Andi Kleen31191a82015-08-07 15:54:24 -0700400}
401
402struct sort_entry sort_srcfile = {
403 .se_header = "Source File",
404 .se_cmp = sort__srcfile_cmp,
405 .se_snprintf = hist_entry__srcfile_snprintf,
406 .se_width_idx = HISTC_SRCFILE,
407};
408
John Kacurdd68ada2009-09-24 18:02:49 +0200409/* --sort parent */
410
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200411static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200412sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
413{
414 struct symbol *sym_l = left->parent;
415 struct symbol *sym_r = right->parent;
416
417 if (!sym_l || !sym_r)
418 return cmp_null(sym_l, sym_r);
419
Namhyung Kim202e7a62014-03-04 11:01:41 +0900420 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200421}
422
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300423static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300424 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200425{
Namhyung Kim5b591662014-07-31 14:47:38 +0900426 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300427 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200428}
429
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200430struct sort_entry sort_parent = {
431 .se_header = "Parent symbol",
432 .se_cmp = sort__parent_cmp,
433 .se_snprintf = hist_entry__parent_snprintf,
434 .se_width_idx = HISTC_PARENT,
435};
436
Arun Sharmaf60f3592010-06-04 11:27:10 -0300437/* --sort cpu */
438
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200439static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300440sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
441{
442 return right->cpu - left->cpu;
443}
444
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300445static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
446 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300447{
Namhyung Kim5b591662014-07-31 14:47:38 +0900448 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300449}
450
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200451struct sort_entry sort_cpu = {
452 .se_header = "CPU",
453 .se_cmp = sort__cpu_cmp,
454 .se_snprintf = hist_entry__cpu_snprintf,
455 .se_width_idx = HISTC_CPU,
456};
457
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400458/* --sort socket */
459
460static int64_t
461sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
462{
463 return right->socket - left->socket;
464}
465
466static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
467 size_t size, unsigned int width)
468{
469 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
470}
471
Namhyung Kim54430102016-02-25 00:13:37 +0900472static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
473{
474 int sk = *(const int *)arg;
475
476 if (type != HIST_FILTER__SOCKET)
477 return -1;
478
479 return sk >= 0 && he->socket != sk;
480}
481
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400482struct sort_entry sort_socket = {
483 .se_header = "Socket",
484 .se_cmp = sort__socket_cmp,
485 .se_snprintf = hist_entry__socket_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900486 .se_filter = hist_entry__socket_filter,
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400487 .se_width_idx = HISTC_SOCKET,
488};
489
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900490/* --sort trace */
491
492static char *get_trace_output(struct hist_entry *he)
493{
494 struct trace_seq seq;
495 struct perf_evsel *evsel;
496 struct pevent_record rec = {
497 .data = he->raw_data,
498 .size = he->raw_size,
499 };
500
501 evsel = hists_to_evsel(he->hists);
502
503 trace_seq_init(&seq);
Namhyung Kim053a3982015-12-23 02:07:05 +0900504 if (symbol_conf.raw_trace) {
505 pevent_print_fields(&seq, he->raw_data, he->raw_size,
506 evsel->tp_format);
507 } else {
508 pevent_event_info(&seq, evsel->tp_format, &rec);
509 }
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900510 return seq.buffer;
511}
512
513static int64_t
514sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
515{
516 struct perf_evsel *evsel;
517
518 evsel = hists_to_evsel(left->hists);
519 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
520 return 0;
521
522 if (left->trace_output == NULL)
523 left->trace_output = get_trace_output(left);
524 if (right->trace_output == NULL)
525 right->trace_output = get_trace_output(right);
526
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900527 return strcmp(right->trace_output, left->trace_output);
528}
529
530static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
531 size_t size, unsigned int width)
532{
533 struct perf_evsel *evsel;
534
535 evsel = hists_to_evsel(he->hists);
536 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
Namhyung Kim2960ed62016-02-22 09:32:33 +0900537 return scnprintf(bf, size, "%-.*s", width, "N/A");
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900538
539 if (he->trace_output == NULL)
540 he->trace_output = get_trace_output(he);
Namhyung Kim2960ed62016-02-22 09:32:33 +0900541 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900542}
543
544struct sort_entry sort_trace = {
545 .se_header = "Trace output",
546 .se_cmp = sort__trace_cmp,
547 .se_snprintf = hist_entry__trace_snprintf,
548 .se_width_idx = HISTC_TRACE,
549};
550
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900551/* sort keys for branch stacks */
552
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100553static int64_t
554sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
555{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200556 if (!left->branch_info || !right->branch_info)
557 return cmp_null(left->branch_info, right->branch_info);
558
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100559 return _sort__dso_cmp(left->branch_info->from.map,
560 right->branch_info->from.map);
561}
562
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300563static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100564 size_t size, unsigned int width)
565{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200566 if (he->branch_info)
567 return _hist_entry__dso_snprintf(he->branch_info->from.map,
568 bf, size, width);
569 else
570 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100571}
572
Namhyung Kim54430102016-02-25 00:13:37 +0900573static int hist_entry__dso_from_filter(struct hist_entry *he, int type,
574 const void *arg)
575{
576 const struct dso *dso = arg;
577
578 if (type != HIST_FILTER__DSO)
579 return -1;
580
581 return dso && (!he->branch_info || !he->branch_info->from.map ||
582 he->branch_info->from.map->dso != dso);
583}
584
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100585static int64_t
586sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
587{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200588 if (!left->branch_info || !right->branch_info)
589 return cmp_null(left->branch_info, right->branch_info);
590
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100591 return _sort__dso_cmp(left->branch_info->to.map,
592 right->branch_info->to.map);
593}
594
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300595static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100596 size_t size, unsigned int width)
597{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200598 if (he->branch_info)
599 return _hist_entry__dso_snprintf(he->branch_info->to.map,
600 bf, size, width);
601 else
602 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100603}
604
Namhyung Kim54430102016-02-25 00:13:37 +0900605static int hist_entry__dso_to_filter(struct hist_entry *he, int type,
606 const void *arg)
607{
608 const struct dso *dso = arg;
609
610 if (type != HIST_FILTER__DSO)
611 return -1;
612
613 return dso && (!he->branch_info || !he->branch_info->to.map ||
614 he->branch_info->to.map->dso != dso);
615}
616
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100617static int64_t
618sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
619{
620 struct addr_map_symbol *from_l = &left->branch_info->from;
621 struct addr_map_symbol *from_r = &right->branch_info->from;
622
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200623 if (!left->branch_info || !right->branch_info)
624 return cmp_null(left->branch_info, right->branch_info);
625
626 from_l = &left->branch_info->from;
627 from_r = &right->branch_info->from;
628
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100629 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900630 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100631
Namhyung Kim51f27d12013-02-06 14:57:15 +0900632 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100633}
634
635static int64_t
636sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
637{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200638 struct addr_map_symbol *to_l, *to_r;
639
640 if (!left->branch_info || !right->branch_info)
641 return cmp_null(left->branch_info, right->branch_info);
642
643 to_l = &left->branch_info->to;
644 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100645
646 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900647 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100648
Namhyung Kim51f27d12013-02-06 14:57:15 +0900649 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100650}
651
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300652static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900653 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100654{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200655 if (he->branch_info) {
656 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100657
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200658 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
659 he->level, bf, size, width);
660 }
661
662 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100663}
664
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300665static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900666 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100667{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200668 if (he->branch_info) {
669 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100670
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200671 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
672 he->level, bf, size, width);
673 }
674
675 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100676}
677
Namhyung Kim54430102016-02-25 00:13:37 +0900678static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
679 const void *arg)
680{
681 const char *sym = arg;
682
683 if (type != HIST_FILTER__SYMBOL)
684 return -1;
685
686 return sym && !(he->branch_info && he->branch_info->from.sym &&
687 strstr(he->branch_info->from.sym->name, sym));
688}
689
690static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
691 const void *arg)
692{
693 const char *sym = arg;
694
695 if (type != HIST_FILTER__SYMBOL)
696 return -1;
697
698 return sym && !(he->branch_info && he->branch_info->to.sym &&
699 strstr(he->branch_info->to.sym->name, sym));
700}
701
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900702struct sort_entry sort_dso_from = {
703 .se_header = "Source Shared Object",
704 .se_cmp = sort__dso_from_cmp,
705 .se_snprintf = hist_entry__dso_from_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900706 .se_filter = hist_entry__dso_from_filter,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900707 .se_width_idx = HISTC_DSO_FROM,
708};
709
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100710struct sort_entry sort_dso_to = {
711 .se_header = "Target Shared Object",
712 .se_cmp = sort__dso_to_cmp,
713 .se_snprintf = hist_entry__dso_to_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900714 .se_filter = hist_entry__dso_to_filter,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100715 .se_width_idx = HISTC_DSO_TO,
716};
717
718struct sort_entry sort_sym_from = {
719 .se_header = "Source Symbol",
720 .se_cmp = sort__sym_from_cmp,
721 .se_snprintf = hist_entry__sym_from_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900722 .se_filter = hist_entry__sym_from_filter,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100723 .se_width_idx = HISTC_SYMBOL_FROM,
724};
725
726struct sort_entry sort_sym_to = {
727 .se_header = "Target Symbol",
728 .se_cmp = sort__sym_to_cmp,
729 .se_snprintf = hist_entry__sym_to_snprintf,
Namhyung Kim54430102016-02-25 00:13:37 +0900730 .se_filter = hist_entry__sym_to_filter,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100731 .se_width_idx = HISTC_SYMBOL_TO,
732};
733
734static int64_t
735sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
736{
Jiri Olsa428560e2014-10-16 16:07:03 +0200737 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100738
Jiri Olsa428560e2014-10-16 16:07:03 +0200739 if (!left->branch_info || !right->branch_info)
740 return cmp_null(left->branch_info, right->branch_info);
741
742 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
743 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100744 return mp || p;
745}
746
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300747static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100748 size_t size, unsigned int width){
749 static const char *out = "N/A";
750
Jiri Olsa428560e2014-10-16 16:07:03 +0200751 if (he->branch_info) {
752 if (he->branch_info->flags.predicted)
753 out = "N";
754 else if (he->branch_info->flags.mispred)
755 out = "Y";
756 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100757
Namhyung Kim5b591662014-07-31 14:47:38 +0900758 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100759}
760
Andi Kleen0e332f02015-07-18 08:24:46 -0700761static int64_t
762sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
763{
764 return left->branch_info->flags.cycles -
765 right->branch_info->flags.cycles;
766}
767
768static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
769 size_t size, unsigned int width)
770{
771 if (he->branch_info->flags.cycles == 0)
772 return repsep_snprintf(bf, size, "%-*s", width, "-");
773 return repsep_snprintf(bf, size, "%-*hd", width,
774 he->branch_info->flags.cycles);
775}
776
777struct sort_entry sort_cycles = {
778 .se_header = "Basic Block Cycles",
779 .se_cmp = sort__cycles_cmp,
780 .se_snprintf = hist_entry__cycles_snprintf,
781 .se_width_idx = HISTC_CYCLES,
782};
783
Stephane Eranian98a3b322013-01-24 16:10:35 +0100784/* --sort daddr_sym */
785static int64_t
786sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
787{
788 uint64_t l = 0, r = 0;
789
790 if (left->mem_info)
791 l = left->mem_info->daddr.addr;
792 if (right->mem_info)
793 r = right->mem_info->daddr.addr;
794
795 return (int64_t)(r - l);
796}
797
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300798static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100799 size_t size, unsigned int width)
800{
801 uint64_t addr = 0;
802 struct map *map = NULL;
803 struct symbol *sym = NULL;
804
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300805 if (he->mem_info) {
806 addr = he->mem_info->daddr.addr;
807 map = he->mem_info->daddr.map;
808 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100809 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300810 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100811 width);
812}
813
814static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200815sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
816{
817 uint64_t l = 0, r = 0;
818
819 if (left->mem_info)
820 l = left->mem_info->iaddr.addr;
821 if (right->mem_info)
822 r = right->mem_info->iaddr.addr;
823
824 return (int64_t)(r - l);
825}
826
827static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
828 size_t size, unsigned int width)
829{
830 uint64_t addr = 0;
831 struct map *map = NULL;
832 struct symbol *sym = NULL;
833
834 if (he->mem_info) {
835 addr = he->mem_info->iaddr.addr;
836 map = he->mem_info->iaddr.map;
837 sym = he->mem_info->iaddr.sym;
838 }
839 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
840 width);
841}
842
843static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100844sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
845{
846 struct map *map_l = NULL;
847 struct map *map_r = NULL;
848
849 if (left->mem_info)
850 map_l = left->mem_info->daddr.map;
851 if (right->mem_info)
852 map_r = right->mem_info->daddr.map;
853
854 return _sort__dso_cmp(map_l, map_r);
855}
856
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300857static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100858 size_t size, unsigned int width)
859{
860 struct map *map = NULL;
861
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300862 if (he->mem_info)
863 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100864
865 return _hist_entry__dso_snprintf(map, bf, size, width);
866}
867
868static int64_t
869sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
870{
871 union perf_mem_data_src data_src_l;
872 union perf_mem_data_src data_src_r;
873
874 if (left->mem_info)
875 data_src_l = left->mem_info->data_src;
876 else
877 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
878
879 if (right->mem_info)
880 data_src_r = right->mem_info->data_src;
881 else
882 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
883
884 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
885}
886
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300887static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100888 size_t size, unsigned int width)
889{
Jiri Olsa69a77272016-02-24 09:46:49 +0100890 char out[10];
Stephane Eranian98a3b322013-01-24 16:10:35 +0100891
Jiri Olsa69a77272016-02-24 09:46:49 +0100892 perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300893 return repsep_snprintf(bf, size, "%.*s", width, out);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100894}
895
896static int64_t
897sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
898{
899 union perf_mem_data_src data_src_l;
900 union perf_mem_data_src data_src_r;
901
902 if (left->mem_info)
903 data_src_l = left->mem_info->data_src;
904 else
905 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
906
907 if (right->mem_info)
908 data_src_r = right->mem_info->data_src;
909 else
910 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
911
912 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
913}
914
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300915static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100916 size_t size, unsigned int width)
917{
918 char out[64];
Stephane Eranian98a3b322013-01-24 16:10:35 +0100919
Jiri Olsa0c877d72016-02-24 09:46:46 +0100920 perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100921 return repsep_snprintf(bf, size, "%-*s", width, out);
922}
923
924static int64_t
925sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
926{
927 union perf_mem_data_src data_src_l;
928 union perf_mem_data_src data_src_r;
929
930 if (left->mem_info)
931 data_src_l = left->mem_info->data_src;
932 else
933 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
934
935 if (right->mem_info)
936 data_src_r = right->mem_info->data_src;
937 else
938 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
939
940 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
941}
942
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300943static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100944 size_t size, unsigned int width)
945{
946 char out[64];
Stephane Eranian98a3b322013-01-24 16:10:35 +0100947
Jiri Olsa071e9a12016-02-24 09:46:47 +0100948 perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100949 return repsep_snprintf(bf, size, "%-*s", width, out);
950}
951
952static int64_t
953sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
954{
955 union perf_mem_data_src data_src_l;
956 union perf_mem_data_src data_src_r;
957
958 if (left->mem_info)
959 data_src_l = left->mem_info->data_src;
960 else
961 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
962
963 if (right->mem_info)
964 data_src_r = right->mem_info->data_src;
965 else
966 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
967
968 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
969}
970
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300971static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100972 size_t size, unsigned int width)
973{
974 char out[64];
Stephane Eranian98a3b322013-01-24 16:10:35 +0100975
Jiri Olsa2c07af12016-02-24 09:46:48 +0100976 perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100977 return repsep_snprintf(bf, size, "%-*s", width, out);
978}
979
Don Zickus9b32ba72014-06-01 15:38:29 +0200980static int64_t
981sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
982{
983 u64 l, r;
984 struct map *l_map, *r_map;
985
986 if (!left->mem_info) return -1;
987 if (!right->mem_info) return 1;
988
989 /* group event types together */
990 if (left->cpumode > right->cpumode) return -1;
991 if (left->cpumode < right->cpumode) return 1;
992
993 l_map = left->mem_info->daddr.map;
994 r_map = right->mem_info->daddr.map;
995
996 /* if both are NULL, jump to sort on al_addr instead */
997 if (!l_map && !r_map)
998 goto addr;
999
1000 if (!l_map) return -1;
1001 if (!r_map) return 1;
1002
1003 if (l_map->maj > r_map->maj) return -1;
1004 if (l_map->maj < r_map->maj) return 1;
1005
1006 if (l_map->min > r_map->min) return -1;
1007 if (l_map->min < r_map->min) return 1;
1008
1009 if (l_map->ino > r_map->ino) return -1;
1010 if (l_map->ino < r_map->ino) return 1;
1011
1012 if (l_map->ino_generation > r_map->ino_generation) return -1;
1013 if (l_map->ino_generation < r_map->ino_generation) return 1;
1014
1015 /*
1016 * Addresses with no major/minor numbers are assumed to be
1017 * anonymous in userspace. Sort those on pid then address.
1018 *
1019 * The kernel and non-zero major/minor mapped areas are
1020 * assumed to be unity mapped. Sort those on address.
1021 */
1022
1023 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1024 (!(l_map->flags & MAP_SHARED)) &&
1025 !l_map->maj && !l_map->min && !l_map->ino &&
1026 !l_map->ino_generation) {
1027 /* userspace anonymous */
1028
1029 if (left->thread->pid_ > right->thread->pid_) return -1;
1030 if (left->thread->pid_ < right->thread->pid_) return 1;
1031 }
1032
1033addr:
1034 /* al_addr does all the right addr - start + offset calculations */
1035 l = cl_address(left->mem_info->daddr.al_addr);
1036 r = cl_address(right->mem_info->daddr.al_addr);
1037
1038 if (l > r) return -1;
1039 if (l < r) return 1;
1040
1041 return 0;
1042}
1043
1044static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1045 size_t size, unsigned int width)
1046{
1047
1048 uint64_t addr = 0;
1049 struct map *map = NULL;
1050 struct symbol *sym = NULL;
1051 char level = he->level;
1052
1053 if (he->mem_info) {
1054 addr = cl_address(he->mem_info->daddr.al_addr);
1055 map = he->mem_info->daddr.map;
1056 sym = he->mem_info->daddr.sym;
1057
1058 /* print [s] for shared data mmaps */
1059 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1060 map && (map->type == MAP__VARIABLE) &&
1061 (map->flags & MAP_SHARED) &&
1062 (map->maj || map->min || map->ino ||
1063 map->ino_generation))
1064 level = 's';
1065 else if (!map)
1066 level = 'X';
1067 }
1068 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1069 width);
1070}
1071
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001072struct sort_entry sort_mispredict = {
1073 .se_header = "Branch Mispredicted",
1074 .se_cmp = sort__mispredict_cmp,
1075 .se_snprintf = hist_entry__mispredict_snprintf,
1076 .se_width_idx = HISTC_MISPREDICT,
1077};
1078
Andi Kleen05484292013-01-24 16:10:29 +01001079static u64 he_weight(struct hist_entry *he)
1080{
1081 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1082}
1083
1084static int64_t
1085sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1086{
1087 return he_weight(left) - he_weight(right);
1088}
1089
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001090static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001091 size_t size, unsigned int width)
1092{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001093 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001094}
1095
1096struct sort_entry sort_local_weight = {
1097 .se_header = "Local Weight",
1098 .se_cmp = sort__local_weight_cmp,
1099 .se_snprintf = hist_entry__local_weight_snprintf,
1100 .se_width_idx = HISTC_LOCAL_WEIGHT,
1101};
1102
1103static int64_t
1104sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1105{
1106 return left->stat.weight - right->stat.weight;
1107}
1108
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001109static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001110 size_t size, unsigned int width)
1111{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001112 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001113}
1114
1115struct sort_entry sort_global_weight = {
1116 .se_header = "Weight",
1117 .se_cmp = sort__global_weight_cmp,
1118 .se_snprintf = hist_entry__global_weight_snprintf,
1119 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1120};
1121
Stephane Eranian98a3b322013-01-24 16:10:35 +01001122struct sort_entry sort_mem_daddr_sym = {
1123 .se_header = "Data Symbol",
1124 .se_cmp = sort__daddr_cmp,
1125 .se_snprintf = hist_entry__daddr_snprintf,
1126 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1127};
1128
Don Zickus28e6db22015-10-05 20:06:07 +02001129struct sort_entry sort_mem_iaddr_sym = {
1130 .se_header = "Code Symbol",
1131 .se_cmp = sort__iaddr_cmp,
1132 .se_snprintf = hist_entry__iaddr_snprintf,
1133 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1134};
1135
Stephane Eranian98a3b322013-01-24 16:10:35 +01001136struct sort_entry sort_mem_daddr_dso = {
1137 .se_header = "Data Object",
1138 .se_cmp = sort__dso_daddr_cmp,
1139 .se_snprintf = hist_entry__dso_daddr_snprintf,
1140 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1141};
1142
1143struct sort_entry sort_mem_locked = {
1144 .se_header = "Locked",
1145 .se_cmp = sort__locked_cmp,
1146 .se_snprintf = hist_entry__locked_snprintf,
1147 .se_width_idx = HISTC_MEM_LOCKED,
1148};
1149
1150struct sort_entry sort_mem_tlb = {
1151 .se_header = "TLB access",
1152 .se_cmp = sort__tlb_cmp,
1153 .se_snprintf = hist_entry__tlb_snprintf,
1154 .se_width_idx = HISTC_MEM_TLB,
1155};
1156
1157struct sort_entry sort_mem_lvl = {
1158 .se_header = "Memory access",
1159 .se_cmp = sort__lvl_cmp,
1160 .se_snprintf = hist_entry__lvl_snprintf,
1161 .se_width_idx = HISTC_MEM_LVL,
1162};
1163
1164struct sort_entry sort_mem_snoop = {
1165 .se_header = "Snoop",
1166 .se_cmp = sort__snoop_cmp,
1167 .se_snprintf = hist_entry__snoop_snprintf,
1168 .se_width_idx = HISTC_MEM_SNOOP,
1169};
1170
Don Zickus9b32ba72014-06-01 15:38:29 +02001171struct sort_entry sort_mem_dcacheline = {
1172 .se_header = "Data Cacheline",
1173 .se_cmp = sort__dcacheline_cmp,
1174 .se_snprintf = hist_entry__dcacheline_snprintf,
1175 .se_width_idx = HISTC_MEM_DCACHELINE,
1176};
1177
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001178static int64_t
1179sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1180{
Jiri Olsa49f47442014-10-16 16:07:01 +02001181 if (!left->branch_info || !right->branch_info)
1182 return cmp_null(left->branch_info, right->branch_info);
1183
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001184 return left->branch_info->flags.abort !=
1185 right->branch_info->flags.abort;
1186}
1187
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001188static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001189 size_t size, unsigned int width)
1190{
Jiri Olsa49f47442014-10-16 16:07:01 +02001191 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001192
Jiri Olsa49f47442014-10-16 16:07:01 +02001193 if (he->branch_info) {
1194 if (he->branch_info->flags.abort)
1195 out = "A";
1196 else
1197 out = ".";
1198 }
1199
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001200 return repsep_snprintf(bf, size, "%-*s", width, out);
1201}
1202
1203struct sort_entry sort_abort = {
1204 .se_header = "Transaction abort",
1205 .se_cmp = sort__abort_cmp,
1206 .se_snprintf = hist_entry__abort_snprintf,
1207 .se_width_idx = HISTC_ABORT,
1208};
1209
1210static int64_t
1211sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1212{
Jiri Olsa0199d242014-10-16 16:07:02 +02001213 if (!left->branch_info || !right->branch_info)
1214 return cmp_null(left->branch_info, right->branch_info);
1215
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001216 return left->branch_info->flags.in_tx !=
1217 right->branch_info->flags.in_tx;
1218}
1219
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001220static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001221 size_t size, unsigned int width)
1222{
Jiri Olsa0199d242014-10-16 16:07:02 +02001223 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001224
Jiri Olsa0199d242014-10-16 16:07:02 +02001225 if (he->branch_info) {
1226 if (he->branch_info->flags.in_tx)
1227 out = "T";
1228 else
1229 out = ".";
1230 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001231
1232 return repsep_snprintf(bf, size, "%-*s", width, out);
1233}
1234
1235struct sort_entry sort_in_tx = {
1236 .se_header = "Branch in transaction",
1237 .se_cmp = sort__in_tx_cmp,
1238 .se_snprintf = hist_entry__in_tx_snprintf,
1239 .se_width_idx = HISTC_IN_TX,
1240};
1241
Andi Kleen475eeab2013-09-20 07:40:43 -07001242static int64_t
1243sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1244{
1245 return left->transaction - right->transaction;
1246}
1247
1248static inline char *add_str(char *p, const char *str)
1249{
1250 strcpy(p, str);
1251 return p + strlen(str);
1252}
1253
1254static struct txbit {
1255 unsigned flag;
1256 const char *name;
1257 int skip_for_len;
1258} txbits[] = {
1259 { PERF_TXN_ELISION, "EL ", 0 },
1260 { PERF_TXN_TRANSACTION, "TX ", 1 },
1261 { PERF_TXN_SYNC, "SYNC ", 1 },
1262 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1263 { PERF_TXN_RETRY, "RETRY ", 0 },
1264 { PERF_TXN_CONFLICT, "CON ", 0 },
1265 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1266 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1267 { 0, NULL, 0 }
1268};
1269
1270int hist_entry__transaction_len(void)
1271{
1272 int i;
1273 int len = 0;
1274
1275 for (i = 0; txbits[i].name; i++) {
1276 if (!txbits[i].skip_for_len)
1277 len += strlen(txbits[i].name);
1278 }
1279 len += 4; /* :XX<space> */
1280 return len;
1281}
1282
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001283static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001284 size_t size, unsigned int width)
1285{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001286 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001287 char buf[128];
1288 char *p = buf;
1289 int i;
1290
1291 buf[0] = 0;
1292 for (i = 0; txbits[i].name; i++)
1293 if (txbits[i].flag & t)
1294 p = add_str(p, txbits[i].name);
1295 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1296 p = add_str(p, "NEITHER ");
1297 if (t & PERF_TXN_ABORT_MASK) {
1298 sprintf(p, ":%" PRIx64,
1299 (t & PERF_TXN_ABORT_MASK) >>
1300 PERF_TXN_ABORT_SHIFT);
1301 p += strlen(p);
1302 }
1303
1304 return repsep_snprintf(bf, size, "%-*s", width, buf);
1305}
1306
1307struct sort_entry sort_transaction = {
1308 .se_header = "Transaction ",
1309 .se_cmp = sort__transaction_cmp,
1310 .se_snprintf = hist_entry__transaction_snprintf,
1311 .se_width_idx = HISTC_TRANSACTION,
1312};
1313
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001314struct sort_dimension {
1315 const char *name;
1316 struct sort_entry *entry;
1317 int taken;
1318};
1319
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001320#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1321
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001322static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001323 DIM(SORT_PID, "pid", sort_thread),
1324 DIM(SORT_COMM, "comm", sort_comm),
1325 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001326 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001327 DIM(SORT_PARENT, "parent", sort_parent),
1328 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001329 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001330 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001331 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001332 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1333 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001334 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001335 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001336};
1337
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001338#undef DIM
1339
1340#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1341
1342static struct sort_dimension bstack_sort_dimensions[] = {
1343 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1344 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1345 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1346 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1347 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001348 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1349 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001350 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001351};
1352
1353#undef DIM
1354
Namhyung Kimafab87b2013-04-03 21:26:11 +09001355#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1356
1357static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001358 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001359 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001360 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1361 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1362 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1363 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1364 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001365 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001366};
1367
1368#undef DIM
1369
Namhyung Kima2ce0672014-03-04 09:06:42 +09001370struct hpp_dimension {
1371 const char *name;
1372 struct perf_hpp_fmt *fmt;
1373 int taken;
1374};
1375
1376#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1377
1378static struct hpp_dimension hpp_sort_dimensions[] = {
1379 DIM(PERF_HPP__OVERHEAD, "overhead"),
1380 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1381 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1382 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1383 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001384 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001385 DIM(PERF_HPP__SAMPLES, "sample"),
1386 DIM(PERF_HPP__PERIOD, "period"),
1387};
1388
1389#undef DIM
1390
Namhyung Kim8b536992014-03-03 11:46:55 +09001391struct hpp_sort_entry {
1392 struct perf_hpp_fmt hpp;
1393 struct sort_entry *se;
1394};
1395
Namhyung Kime0d66c72014-07-31 14:47:37 +09001396void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001397{
1398 struct hpp_sort_entry *hse;
1399
1400 if (!perf_hpp__is_sort_entry(fmt))
1401 return;
1402
1403 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001404 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001405}
1406
Namhyung Kim8b536992014-03-03 11:46:55 +09001407static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1408 struct perf_evsel *evsel)
1409{
1410 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001411 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001412
1413 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001414
Namhyung Kim5b591662014-07-31 14:47:38 +09001415 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001416 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001417
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001418 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001419}
1420
1421static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1422 struct perf_hpp *hpp __maybe_unused,
1423 struct perf_evsel *evsel)
1424{
1425 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001426 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001427
1428 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1429
Namhyung Kim5b591662014-07-31 14:47:38 +09001430 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001431 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001432
1433 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001434}
1435
1436static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1437 struct hist_entry *he)
1438{
1439 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001440 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001441
1442 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001443
1444 if (!len)
1445 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001446
1447 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1448}
1449
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001450static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1451 struct hist_entry *a, struct hist_entry *b)
1452{
1453 struct hpp_sort_entry *hse;
1454
1455 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1456 return hse->se->se_cmp(a, b);
1457}
1458
1459static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1460 struct hist_entry *a, struct hist_entry *b)
1461{
1462 struct hpp_sort_entry *hse;
1463 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1464
1465 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1466 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1467 return collapse_fn(a, b);
1468}
1469
1470static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1471 struct hist_entry *a, struct hist_entry *b)
1472{
1473 struct hpp_sort_entry *hse;
1474 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1475
1476 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1477 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1478 return sort_fn(a, b);
1479}
1480
Jiri Olsa97358082016-01-18 10:24:03 +01001481bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1482{
1483 return format->header == __sort__hpp_header;
1484}
1485
Namhyung Kim4945cf22016-03-09 22:46:57 +09001486#define MK_SORT_ENTRY_CHK(key) \
1487bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt) \
1488{ \
1489 struct hpp_sort_entry *hse; \
1490 \
1491 if (!perf_hpp__is_sort_entry(fmt)) \
1492 return false; \
1493 \
1494 hse = container_of(fmt, struct hpp_sort_entry, hpp); \
1495 return hse->se == &sort_ ## key ; \
Namhyung Kima9c6e462016-02-25 00:13:33 +09001496}
1497
Namhyung Kim4945cf22016-03-09 22:46:57 +09001498MK_SORT_ENTRY_CHK(trace)
1499MK_SORT_ENTRY_CHK(srcline)
1500MK_SORT_ENTRY_CHK(srcfile)
1501MK_SORT_ENTRY_CHK(thread)
1502MK_SORT_ENTRY_CHK(comm)
1503MK_SORT_ENTRY_CHK(dso)
1504MK_SORT_ENTRY_CHK(sym)
Namhyung Kima9c6e462016-02-25 00:13:33 +09001505
Namhyung Kima9c6e462016-02-25 00:13:33 +09001506
Jiri Olsa97358082016-01-18 10:24:03 +01001507static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1508{
1509 struct hpp_sort_entry *hse_a;
1510 struct hpp_sort_entry *hse_b;
1511
1512 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1513 return false;
1514
1515 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1516 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1517
1518 return hse_a->se == hse_b->se;
1519}
1520
Jiri Olsa564132f2016-01-18 10:24:09 +01001521static void hse_free(struct perf_hpp_fmt *fmt)
1522{
1523 struct hpp_sort_entry *hse;
1524
1525 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1526 free(hse);
1527}
1528
Namhyung Kima7d945b2014-03-04 10:46:34 +09001529static struct hpp_sort_entry *
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001530__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
Namhyung Kim8b536992014-03-03 11:46:55 +09001531{
1532 struct hpp_sort_entry *hse;
1533
1534 hse = malloc(sizeof(*hse));
1535 if (hse == NULL) {
1536 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001537 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001538 }
1539
1540 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001541 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001542 hse->hpp.header = __sort__hpp_header;
1543 hse->hpp.width = __sort__hpp_width;
1544 hse->hpp.entry = __sort__hpp_entry;
1545 hse->hpp.color = NULL;
1546
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001547 hse->hpp.cmp = __sort__hpp_cmp;
1548 hse->hpp.collapse = __sort__hpp_collapse;
1549 hse->hpp.sort = __sort__hpp_sort;
Jiri Olsa97358082016-01-18 10:24:03 +01001550 hse->hpp.equal = __sort__hpp_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001551 hse->hpp.free = hse_free;
Namhyung Kim8b536992014-03-03 11:46:55 +09001552
1553 INIT_LIST_HEAD(&hse->hpp.list);
1554 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001555 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001556 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001557 hse->hpp.user_len = 0;
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001558 hse->hpp.level = level;
Namhyung Kim8b536992014-03-03 11:46:55 +09001559
Namhyung Kima7d945b2014-03-04 10:46:34 +09001560 return hse;
1561}
1562
Jiri Olsa564132f2016-01-18 10:24:09 +01001563static void hpp_free(struct perf_hpp_fmt *fmt)
1564{
1565 free(fmt);
1566}
1567
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001568static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
1569 int level)
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001570{
1571 struct perf_hpp_fmt *fmt;
1572
1573 fmt = memdup(hd->fmt, sizeof(*fmt));
1574 if (fmt) {
1575 INIT_LIST_HEAD(&fmt->list);
1576 INIT_LIST_HEAD(&fmt->sort_list);
Jiri Olsa564132f2016-01-18 10:24:09 +01001577 fmt->free = hpp_free;
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001578 fmt->level = level;
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001579 }
1580
1581 return fmt;
1582}
1583
Namhyung Kim54430102016-02-25 00:13:37 +09001584int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
1585{
1586 struct perf_hpp_fmt *fmt;
1587 struct hpp_sort_entry *hse;
Namhyung Kimf4954cf2016-03-09 22:46:56 +09001588 int ret = -1;
1589 int r;
Namhyung Kim54430102016-02-25 00:13:37 +09001590
Namhyung Kimf4954cf2016-03-09 22:46:56 +09001591 perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1592 if (!perf_hpp__is_sort_entry(fmt))
1593 continue;
Namhyung Kim54430102016-02-25 00:13:37 +09001594
Namhyung Kimf4954cf2016-03-09 22:46:56 +09001595 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1596 if (hse->se->se_filter == NULL)
1597 continue;
Namhyung Kim54430102016-02-25 00:13:37 +09001598
Namhyung Kimf4954cf2016-03-09 22:46:56 +09001599 /*
1600 * hist entry is filtered if any of sort key in the hpp list
1601 * is applied. But it should skip non-matched filter types.
1602 */
1603 r = hse->se->se_filter(he, type, arg);
1604 if (r >= 0) {
1605 if (ret < 0)
1606 ret = 0;
1607 ret |= r;
1608 }
1609 }
1610
1611 return ret;
Namhyung Kim54430102016-02-25 00:13:37 +09001612}
1613
Jiri Olsad7b617f2016-03-09 11:04:17 +01001614static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
1615 struct perf_hpp_list *list,
1616 int level)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001617{
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001618 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001619
1620 if (hse == NULL)
1621 return -1;
1622
Jiri Olsad7b617f2016-03-09 11:04:17 +01001623 perf_hpp_list__register_sort_field(list, &hse->hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001624 return 0;
1625}
1626
Jiri Olsad7b617f2016-03-09 11:04:17 +01001627static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
1628 struct perf_hpp_list *list)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001629{
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001630 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001631
1632 if (hse == NULL)
1633 return -1;
1634
Jiri Olsa07600022016-01-18 10:24:16 +01001635 perf_hpp_list__column_register(list, &hse->hpp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001636 return 0;
1637}
1638
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001639struct hpp_dynamic_entry {
1640 struct perf_hpp_fmt hpp;
1641 struct perf_evsel *evsel;
1642 struct format_field *field;
1643 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001644 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001645};
1646
1647static int hde_width(struct hpp_dynamic_entry *hde)
1648{
1649 if (!hde->hpp.len) {
1650 int len = hde->dynamic_len;
1651 int namelen = strlen(hde->field->name);
1652 int fieldlen = hde->field->size;
1653
1654 if (namelen > len)
1655 len = namelen;
1656
1657 if (!(hde->field->flags & FIELD_IS_STRING)) {
1658 /* length for print hex numbers */
1659 fieldlen = hde->field->size * 2 + 2;
1660 }
1661 if (fieldlen > len)
1662 len = fieldlen;
1663
1664 hde->hpp.len = len;
1665 }
1666 return hde->hpp.len;
1667}
1668
Namhyung Kim60517d22015-12-23 02:07:03 +09001669static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1670 struct hist_entry *he)
1671{
1672 char *str, *pos;
1673 struct format_field *field = hde->field;
1674 size_t namelen;
1675 bool last = false;
1676
Namhyung Kim053a3982015-12-23 02:07:05 +09001677 if (hde->raw_trace)
1678 return;
1679
Namhyung Kim60517d22015-12-23 02:07:03 +09001680 /* parse pretty print result and update max length */
1681 if (!he->trace_output)
1682 he->trace_output = get_trace_output(he);
1683
1684 namelen = strlen(field->name);
1685 str = he->trace_output;
1686
1687 while (str) {
1688 pos = strchr(str, ' ');
1689 if (pos == NULL) {
1690 last = true;
1691 pos = str + strlen(str);
1692 }
1693
1694 if (!strncmp(str, field->name, namelen)) {
1695 size_t len;
1696
1697 str += namelen + 1;
1698 len = pos - str;
1699
1700 if (len > hde->dynamic_len)
1701 hde->dynamic_len = len;
1702 break;
1703 }
1704
1705 if (last)
1706 str = NULL;
1707 else
1708 str = pos + 1;
1709 }
1710}
1711
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001712static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1713 struct perf_evsel *evsel __maybe_unused)
1714{
1715 struct hpp_dynamic_entry *hde;
1716 size_t len = fmt->user_len;
1717
1718 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1719
1720 if (!len)
1721 len = hde_width(hde);
1722
1723 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1724}
1725
1726static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1727 struct perf_hpp *hpp __maybe_unused,
1728 struct perf_evsel *evsel __maybe_unused)
1729{
1730 struct hpp_dynamic_entry *hde;
1731 size_t len = fmt->user_len;
1732
1733 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1734
1735 if (!len)
1736 len = hde_width(hde);
1737
1738 return len;
1739}
1740
Namhyung Kim361459f2015-12-23 02:07:08 +09001741bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1742{
1743 struct hpp_dynamic_entry *hde;
1744
1745 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1746
1747 return hists_to_evsel(hists) == hde->evsel;
1748}
1749
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001750static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1751 struct hist_entry *he)
1752{
1753 struct hpp_dynamic_entry *hde;
1754 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001755 char *str, *pos;
1756 struct format_field *field;
1757 size_t namelen;
1758 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001759 int ret;
1760
1761 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1762
1763 if (!len)
1764 len = hde_width(hde);
1765
Namhyung Kim053a3982015-12-23 02:07:05 +09001766 if (hde->raw_trace)
1767 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001768
Namhyung Kime049d4a2016-02-27 03:52:46 +09001769 if (!he->trace_output)
1770 he->trace_output = get_trace_output(he);
1771
Namhyung Kim053a3982015-12-23 02:07:05 +09001772 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001773 namelen = strlen(field->name);
1774 str = he->trace_output;
1775
1776 while (str) {
1777 pos = strchr(str, ' ');
1778 if (pos == NULL) {
1779 last = true;
1780 pos = str + strlen(str);
1781 }
1782
1783 if (!strncmp(str, field->name, namelen)) {
1784 str += namelen + 1;
1785 str = strndup(str, pos - str);
1786
1787 if (str == NULL)
1788 return scnprintf(hpp->buf, hpp->size,
1789 "%*.*s", len, len, "ERROR");
1790 break;
1791 }
1792
1793 if (last)
1794 str = NULL;
1795 else
1796 str = pos + 1;
1797 }
1798
1799 if (str == NULL) {
1800 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001801raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001802 trace_seq_init(&seq);
1803 pevent_print_field(&seq, he->raw_data, hde->field);
1804 str = seq.buffer;
1805 }
1806
1807 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1808 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001809 return ret;
1810}
1811
1812static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1813 struct hist_entry *a, struct hist_entry *b)
1814{
1815 struct hpp_dynamic_entry *hde;
1816 struct format_field *field;
1817 unsigned offset, size;
1818
1819 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1820
Namhyung Kimabab5e72016-02-27 03:52:47 +09001821 if (b == NULL) {
1822 update_dynamic_len(hde, a);
1823 return 0;
1824 }
1825
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001826 field = hde->field;
1827 if (field->flags & FIELD_IS_DYNAMIC) {
1828 unsigned long long dyn;
1829
1830 pevent_read_number_field(field, a->raw_data, &dyn);
1831 offset = dyn & 0xffff;
1832 size = (dyn >> 16) & 0xffff;
1833
1834 /* record max width for output */
1835 if (size > hde->dynamic_len)
1836 hde->dynamic_len = size;
1837 } else {
1838 offset = field->offset;
1839 size = field->size;
1840 }
1841
1842 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1843}
1844
Namhyung Kim361459f2015-12-23 02:07:08 +09001845bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1846{
1847 return fmt->cmp == __sort__hde_cmp;
1848}
1849
Namhyung Kim665aa752016-02-21 23:22:35 +09001850static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1851{
1852 struct hpp_dynamic_entry *hde_a;
1853 struct hpp_dynamic_entry *hde_b;
1854
1855 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1856 return false;
1857
1858 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1859 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1860
1861 return hde_a->field == hde_b->field;
1862}
1863
Jiri Olsa564132f2016-01-18 10:24:09 +01001864static void hde_free(struct perf_hpp_fmt *fmt)
1865{
1866 struct hpp_dynamic_entry *hde;
1867
1868 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1869 free(hde);
1870}
1871
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001872static struct hpp_dynamic_entry *
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001873__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field,
1874 int level)
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001875{
1876 struct hpp_dynamic_entry *hde;
1877
1878 hde = malloc(sizeof(*hde));
1879 if (hde == NULL) {
1880 pr_debug("Memory allocation failed\n");
1881 return NULL;
1882 }
1883
1884 hde->evsel = evsel;
1885 hde->field = field;
1886 hde->dynamic_len = 0;
1887
1888 hde->hpp.name = field->name;
1889 hde->hpp.header = __sort__hde_header;
1890 hde->hpp.width = __sort__hde_width;
1891 hde->hpp.entry = __sort__hde_entry;
1892 hde->hpp.color = NULL;
1893
1894 hde->hpp.cmp = __sort__hde_cmp;
1895 hde->hpp.collapse = __sort__hde_cmp;
1896 hde->hpp.sort = __sort__hde_cmp;
Namhyung Kim665aa752016-02-21 23:22:35 +09001897 hde->hpp.equal = __sort__hde_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001898 hde->hpp.free = hde_free;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001899
1900 INIT_LIST_HEAD(&hde->hpp.list);
1901 INIT_LIST_HEAD(&hde->hpp.sort_list);
1902 hde->hpp.elide = false;
1903 hde->hpp.len = 0;
1904 hde->hpp.user_len = 0;
Namhyung Kim4b633eb2016-03-07 16:44:43 -03001905 hde->hpp.level = level;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001906
1907 return hde;
1908}
1909
Namhyung Kimc3bc0c42016-03-07 16:44:45 -03001910struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
1911{
1912 struct perf_hpp_fmt *new_fmt = NULL;
1913
1914 if (perf_hpp__is_sort_entry(fmt)) {
1915 struct hpp_sort_entry *hse, *new_hse;
1916
1917 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1918 new_hse = memdup(hse, sizeof(*hse));
1919 if (new_hse)
1920 new_fmt = &new_hse->hpp;
1921 } else if (perf_hpp__is_dynamic_entry(fmt)) {
1922 struct hpp_dynamic_entry *hde, *new_hde;
1923
1924 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1925 new_hde = memdup(hde, sizeof(*hde));
1926 if (new_hde)
1927 new_fmt = &new_hde->hpp;
1928 } else {
1929 new_fmt = memdup(fmt, sizeof(*fmt));
1930 }
1931
1932 INIT_LIST_HEAD(&new_fmt->list);
1933 INIT_LIST_HEAD(&new_fmt->sort_list);
1934
1935 return new_fmt;
1936}
1937
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001938static int parse_field_name(char *str, char **event, char **field, char **opt)
1939{
1940 char *event_name, *field_name, *opt_name;
1941
1942 event_name = str;
1943 field_name = strchr(str, '.');
1944
1945 if (field_name) {
1946 *field_name++ = '\0';
1947 } else {
1948 event_name = NULL;
1949 field_name = str;
1950 }
1951
1952 opt_name = strchr(field_name, '/');
1953 if (opt_name)
1954 *opt_name++ = '\0';
1955
1956 *event = event_name;
1957 *field = field_name;
1958 *opt = opt_name;
1959
1960 return 0;
1961}
1962
1963/* find match evsel using a given event name. The event name can be:
Namhyung Kim9735be22016-01-05 19:58:35 +09001964 * 1. '%' + event index (e.g. '%1' for first event)
1965 * 2. full event name (e.g. sched:sched_switch)
1966 * 3. partial event name (should not contain ':')
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001967 */
1968static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1969{
1970 struct perf_evsel *evsel = NULL;
1971 struct perf_evsel *pos;
1972 bool full_name;
1973
1974 /* case 1 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001975 if (event_name[0] == '%') {
1976 int nr = strtol(event_name+1, NULL, 0);
1977
1978 if (nr > evlist->nr_entries)
1979 return NULL;
1980
1981 evsel = perf_evlist__first(evlist);
1982 while (--nr > 0)
1983 evsel = perf_evsel__next(evsel);
1984
1985 return evsel;
1986 }
1987
1988 full_name = !!strchr(event_name, ':');
1989 evlist__for_each(evlist, pos) {
Namhyung Kim9735be22016-01-05 19:58:35 +09001990 /* case 2 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001991 if (full_name && !strcmp(pos->name, event_name))
1992 return pos;
Namhyung Kim9735be22016-01-05 19:58:35 +09001993 /* case 3 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001994 if (!full_name && strstr(pos->name, event_name)) {
1995 if (evsel) {
1996 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1997 event_name, evsel->name, pos->name);
1998 return NULL;
1999 }
2000 evsel = pos;
2001 }
2002 }
2003
2004 return evsel;
2005}
2006
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002007static int __dynamic_dimension__add(struct perf_evsel *evsel,
2008 struct format_field *field,
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002009 bool raw_trace, int level)
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002010{
2011 struct hpp_dynamic_entry *hde;
2012
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002013 hde = __alloc_dynamic_entry(evsel, field, level);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002014 if (hde == NULL)
2015 return -ENOMEM;
2016
2017 hde->raw_trace = raw_trace;
2018
2019 perf_hpp__register_sort_field(&hde->hpp);
2020 return 0;
2021}
2022
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002023static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002024{
2025 int ret;
2026 struct format_field *field;
2027
2028 field = evsel->tp_format->format.fields;
2029 while (field) {
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002030 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002031 if (ret < 0)
2032 return ret;
2033
2034 field = field->next;
2035 }
2036 return 0;
2037}
2038
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002039static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
2040 int level)
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002041{
2042 int ret;
2043 struct perf_evsel *evsel;
2044
2045 evlist__for_each(evlist, evsel) {
2046 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2047 continue;
2048
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002049 ret = add_evsel_fields(evsel, raw_trace, level);
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002050 if (ret < 0)
2051 return ret;
2052 }
2053 return 0;
2054}
2055
Namhyung Kim9735be22016-01-05 19:58:35 +09002056static int add_all_matching_fields(struct perf_evlist *evlist,
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002057 char *field_name, bool raw_trace, int level)
Namhyung Kim9735be22016-01-05 19:58:35 +09002058{
2059 int ret = -ESRCH;
2060 struct perf_evsel *evsel;
2061 struct format_field *field;
2062
2063 evlist__for_each(evlist, evsel) {
2064 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2065 continue;
2066
2067 field = pevent_find_any_field(evsel->tp_format, field_name);
2068 if (field == NULL)
2069 continue;
2070
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002071 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
Namhyung Kim9735be22016-01-05 19:58:35 +09002072 if (ret < 0)
2073 break;
2074 }
2075 return ret;
2076}
2077
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002078static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2079 int level)
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002080{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002081 char *str, *event_name, *field_name, *opt_name;
2082 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002083 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09002084 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002085 int ret = 0;
2086
2087 if (evlist == NULL)
2088 return -ENOENT;
2089
2090 str = strdup(tok);
2091 if (str == NULL)
2092 return -ENOMEM;
2093
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002094 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002095 ret = -EINVAL;
2096 goto out;
2097 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002098
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002099 if (opt_name) {
2100 if (strcmp(opt_name, "raw")) {
2101 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09002102 ret = -EINVAL;
2103 goto out;
2104 }
2105 raw_trace = true;
2106 }
2107
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002108 if (!strcmp(field_name, "trace_fields")) {
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002109 ret = add_all_dynamic_fields(evlist, raw_trace, level);
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002110 goto out;
2111 }
2112
Namhyung Kim9735be22016-01-05 19:58:35 +09002113 if (event_name == NULL) {
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002114 ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
Namhyung Kim9735be22016-01-05 19:58:35 +09002115 goto out;
2116 }
2117
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002118 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002119 if (evsel == NULL) {
2120 pr_debug("Cannot find event: %s\n", event_name);
2121 ret = -ENOENT;
2122 goto out;
2123 }
2124
2125 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2126 pr_debug("%s is not a tracepoint event\n", event_name);
2127 ret = -EINVAL;
2128 goto out;
2129 }
2130
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002131 if (!strcmp(field_name, "*")) {
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002132 ret = add_evsel_fields(evsel, raw_trace, level);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002133 } else {
2134 field = pevent_find_any_field(evsel->tp_format, field_name);
2135 if (field == NULL) {
2136 pr_debug("Cannot find event field for %s.%s\n",
2137 event_name, field_name);
2138 return -ENOENT;
2139 }
2140
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002141 ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002142 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002143
2144out:
2145 free(str);
2146 return ret;
2147}
2148
Jiri Olsad7b617f2016-03-09 11:04:17 +01002149static int __sort_dimension__add(struct sort_dimension *sd,
2150 struct perf_hpp_list *list,
2151 int level)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002152{
2153 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002154 return 0;
2155
Jiri Olsad7b617f2016-03-09 11:04:17 +01002156 if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002157 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002158
2159 if (sd->entry->se_collapse)
Jiri Olsa52225032016-05-03 13:54:42 +02002160 list->need_collapse = 1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002161
Namhyung Kim2f532d092013-04-03 21:26:10 +09002162 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002163
2164 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002165}
2166
Jiri Olsad7b617f2016-03-09 11:04:17 +01002167static int __hpp_dimension__add(struct hpp_dimension *hd,
2168 struct perf_hpp_list *list,
2169 int level)
Namhyung Kima2ce0672014-03-04 09:06:42 +09002170{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002171 struct perf_hpp_fmt *fmt;
Namhyung Kima2ce0672014-03-04 09:06:42 +09002172
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002173 if (hd->taken)
2174 return 0;
2175
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002176 fmt = __hpp_dimension__alloc_hpp(hd, level);
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002177 if (!fmt)
2178 return -1;
2179
2180 hd->taken = 1;
Jiri Olsad7b617f2016-03-09 11:04:17 +01002181 perf_hpp_list__register_sort_field(list, fmt);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002182 return 0;
2183}
2184
Jiri Olsa07600022016-01-18 10:24:16 +01002185static int __sort_dimension__add_output(struct perf_hpp_list *list,
2186 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002187{
2188 if (sd->taken)
2189 return 0;
2190
Jiri Olsad7b617f2016-03-09 11:04:17 +01002191 if (__sort_dimension__add_hpp_output(sd, list) < 0)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002192 return -1;
2193
2194 sd->taken = 1;
2195 return 0;
2196}
2197
Jiri Olsa07600022016-01-18 10:24:16 +01002198static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2199 struct hpp_dimension *hd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002200{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002201 struct perf_hpp_fmt *fmt;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002202
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002203 if (hd->taken)
2204 return 0;
2205
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002206 fmt = __hpp_dimension__alloc_hpp(hd, 0);
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002207 if (!fmt)
2208 return -1;
2209
2210 hd->taken = 1;
Jiri Olsa07600022016-01-18 10:24:16 +01002211 perf_hpp_list__column_register(list, fmt);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002212 return 0;
2213}
2214
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002215int hpp_dimension__add_output(unsigned col)
2216{
2217 BUG_ON(col >= PERF_HPP__MAX_INDEX);
Jiri Olsa07600022016-01-18 10:24:16 +01002218 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002219}
2220
Jiri Olsad7b617f2016-03-09 11:04:17 +01002221static int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -03002222 struct perf_evlist *evlist,
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002223 int level)
John Kacurdd68ada2009-09-24 18:02:49 +02002224{
2225 unsigned int i;
2226
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002227 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2228 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002229
John Kacurdd68ada2009-09-24 18:02:49 +02002230 if (strncasecmp(tok, sd->name, strlen(tok)))
2231 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002232
John Kacurdd68ada2009-09-24 18:02:49 +02002233 if (sd->entry == &sort_parent) {
2234 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2235 if (ret) {
2236 char err[BUFSIZ];
2237
2238 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002239 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2240 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002241 }
Jiri Olsade7e6a72016-05-03 13:54:43 +02002242 list->parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002243 } else if (sd->entry == &sort_sym) {
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002244 list->sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002245 /*
2246 * perf diff displays the performance difference amongst
2247 * two or more perf.data files. Those files could come
2248 * from different binaries. So we should not compare
2249 * their ips, but the name of symbol.
2250 */
2251 if (sort__mode == SORT_MODE__DIFF)
2252 sd->entry->se_collapse = sort__sym_sort;
2253
Namhyung Kim68f6d022013-12-18 14:21:10 +09002254 } else if (sd->entry == &sort_dso) {
Jiri Olsa69849fc2016-05-03 13:54:45 +02002255 list->dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002256 } else if (sd->entry == &sort_socket) {
Jiri Olsa35a634f2016-05-03 13:54:46 +02002257 list->socket = 1;
Namhyung Kimcfd92da2016-01-21 19:13:24 -03002258 } else if (sd->entry == &sort_thread) {
Jiri Olsafa829112016-05-03 13:54:47 +02002259 list->thread = 1;
Namhyung Kim078b8d42016-03-09 23:20:51 +09002260 } else if (sd->entry == &sort_comm) {
2261 sort__has_comm = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002262 }
2263
Jiri Olsad7b617f2016-03-09 11:04:17 +01002264 return __sort_dimension__add(sd, list, level);
John Kacurdd68ada2009-09-24 18:02:49 +02002265 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002266
Namhyung Kima2ce0672014-03-04 09:06:42 +09002267 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2268 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2269
2270 if (strncasecmp(tok, hd->name, strlen(tok)))
2271 continue;
2272
Jiri Olsad7b617f2016-03-09 11:04:17 +01002273 return __hpp_dimension__add(hd, list, level);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002274 }
2275
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002276 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2277 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2278
2279 if (strncasecmp(tok, sd->name, strlen(tok)))
2280 continue;
2281
Namhyung Kim55369fc2013-04-01 20:35:20 +09002282 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002283 return -EINVAL;
2284
2285 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002286 list->sym = 1;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002287
Jiri Olsad7b617f2016-03-09 11:04:17 +01002288 __sort_dimension__add(sd, list, level);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002289 return 0;
2290 }
2291
Namhyung Kimafab87b2013-04-03 21:26:11 +09002292 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2293 struct sort_dimension *sd = &memory_sort_dimensions[i];
2294
2295 if (strncasecmp(tok, sd->name, strlen(tok)))
2296 continue;
2297
2298 if (sort__mode != SORT_MODE__MEMORY)
2299 return -EINVAL;
2300
2301 if (sd->entry == &sort_mem_daddr_sym)
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002302 list->sym = 1;
Namhyung Kimafab87b2013-04-03 21:26:11 +09002303
Jiri Olsad7b617f2016-03-09 11:04:17 +01002304 __sort_dimension__add(sd, list, level);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002305 return 0;
2306 }
2307
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002308 if (!add_dynamic_entry(evlist, tok, level))
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002309 return 0;
2310
John Kacurdd68ada2009-09-24 18:02:49 +02002311 return -ESRCH;
2312}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002313
Jiri Olsad7b617f2016-03-09 11:04:17 +01002314static int setup_sort_list(struct perf_hpp_list *list, char *str,
2315 struct perf_evlist *evlist)
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002316{
2317 char *tmp, *tok;
2318 int ret = 0;
Namhyung Kim4b633eb2016-03-07 16:44:43 -03002319 int level = 0;
Namhyung Kima23f37e2016-03-07 16:44:47 -03002320 int next_level = 1;
2321 bool in_group = false;
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002322
Namhyung Kima23f37e2016-03-07 16:44:47 -03002323 do {
2324 tok = str;
2325 tmp = strpbrk(str, "{}, ");
2326 if (tmp) {
2327 if (in_group)
2328 next_level = level;
2329 else
2330 next_level = level + 1;
2331
2332 if (*tmp == '{')
2333 in_group = true;
2334 else if (*tmp == '}')
2335 in_group = false;
2336
2337 *tmp = '\0';
2338 str = tmp + 1;
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002339 }
Namhyung Kima23f37e2016-03-07 16:44:47 -03002340
2341 if (*tok) {
Jiri Olsad7b617f2016-03-09 11:04:17 +01002342 ret = sort_dimension__add(list, tok, evlist, level);
Namhyung Kima23f37e2016-03-07 16:44:47 -03002343 if (ret == -EINVAL) {
2344 error("Invalid --sort key: `%s'", tok);
2345 break;
2346 } else if (ret == -ESRCH) {
2347 error("Unknown --sort key: `%s'", tok);
2348 break;
2349 }
2350 }
2351
2352 level = next_level;
2353 } while (tmp);
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002354
2355 return ret;
2356}
2357
Namhyung Kimd49dade2015-12-23 02:07:10 +09002358static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002359{
2360 const char *default_sort_orders[] = {
2361 default_sort_order,
2362 default_branch_sort_order,
2363 default_mem_sort_order,
2364 default_top_sort_order,
2365 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002366 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002367 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002368 bool use_trace = true;
2369 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002370
2371 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2372
Namhyung Kimd49dade2015-12-23 02:07:10 +09002373 if (evlist == NULL)
2374 goto out_no_evlist;
2375
2376 evlist__for_each(evlist, evsel) {
2377 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2378 use_trace = false;
2379 break;
2380 }
2381 }
2382
2383 if (use_trace) {
2384 sort__mode = SORT_MODE__TRACEPOINT;
2385 if (symbol_conf.raw_trace)
2386 return "trace_fields";
2387 }
2388out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002389 return default_sort_orders[sort__mode];
2390}
2391
Namhyung Kimd49dade2015-12-23 02:07:10 +09002392static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002393{
2394 char *new_sort_order;
2395
2396 /*
2397 * Append '+'-prefixed sort order to the default sort
2398 * order string.
2399 */
2400 if (!sort_order || is_strict_order(sort_order))
2401 return 0;
2402
2403 if (sort_order[1] == '\0') {
2404 error("Invalid --sort key: `+'");
2405 return -EINVAL;
2406 }
2407
2408 /*
2409 * We allocate new sort_order string, but we never free it,
2410 * because it's checked over the rest of the code.
2411 */
2412 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002413 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002414 error("Not enough memory to set up --sort");
2415 return -ENOMEM;
2416 }
2417
2418 sort_order = new_sort_order;
2419 return 0;
2420}
2421
Jiri Olsab97511c2016-01-07 10:14:08 +01002422/*
2423 * Adds 'pre,' prefix into 'str' is 'pre' is
2424 * not already part of 'str'.
2425 */
2426static char *prefix_if_not_in(const char *pre, char *str)
2427{
2428 char *n;
2429
2430 if (!str || strstr(str, pre))
2431 return str;
2432
2433 if (asprintf(&n, "%s,%s", pre, str) < 0)
2434 return NULL;
2435
2436 free(str);
2437 return n;
2438}
2439
2440static char *setup_overhead(char *keys)
2441{
2442 keys = prefix_if_not_in("overhead", keys);
2443
2444 if (symbol_conf.cumulate_callchain)
2445 keys = prefix_if_not_in("overhead_children", keys);
2446
2447 return keys;
2448}
2449
Namhyung Kim40184c42015-12-23 02:07:01 +09002450static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002451{
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002452 char *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002453 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002454 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002455
Namhyung Kimd49dade2015-12-23 02:07:10 +09002456 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002457 if (ret)
2458 return ret;
2459
2460 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002461 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002462 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002463 /*
2464 * If user specified field order but no sort order,
2465 * we'll honor it and not add default sort orders.
2466 */
2467 return 0;
2468 }
2469
Namhyung Kimd49dade2015-12-23 02:07:10 +09002470 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002471 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002472
2473 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002474 if (str == NULL) {
2475 error("Not enough memory to setup sort keys");
2476 return -ENOMEM;
2477 }
2478
Jiri Olsab97511c2016-01-07 10:14:08 +01002479 /*
2480 * Prepend overhead fields for backward compatibility.
2481 */
2482 if (!is_strict_order(field_order)) {
2483 str = setup_overhead(str);
2484 if (str == NULL) {
2485 error("Not enough memory to setup overhead keys");
2486 return -ENOMEM;
2487 }
2488 }
2489
Jiri Olsad7b617f2016-03-09 11:04:17 +01002490 ret = setup_sort_list(&perf_hpp_list, str, evlist);
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002491
2492 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002493 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002494}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002495
Jiri Olsaf2998422014-05-23 17:15:47 +02002496void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002497{
Jiri Olsaf2998422014-05-23 17:15:47 +02002498 struct perf_hpp_fmt *fmt;
2499 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002500
Jiri Olsacf094042016-01-18 10:24:17 +01002501 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002502 if (!perf_hpp__is_sort_entry(fmt))
2503 continue;
2504
2505 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2506 if (hse->se->se_width_idx == idx) {
2507 fmt->elide = elide;
2508 break;
2509 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002510 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002511}
2512
Jiri Olsaf2998422014-05-23 17:15:47 +02002513static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002514{
2515 if (list && strlist__nr_entries(list) == 1) {
2516 if (fp != NULL)
2517 fprintf(fp, "# %s: %s\n", list_name,
2518 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002519 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002520 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002521 return false;
2522}
2523
2524static bool get_elide(int idx, FILE *output)
2525{
2526 switch (idx) {
2527 case HISTC_SYMBOL:
2528 return __get_elide(symbol_conf.sym_list, "symbol", output);
2529 case HISTC_DSO:
2530 return __get_elide(symbol_conf.dso_list, "dso", output);
2531 case HISTC_COMM:
2532 return __get_elide(symbol_conf.comm_list, "comm", output);
2533 default:
2534 break;
2535 }
2536
2537 if (sort__mode != SORT_MODE__BRANCH)
2538 return false;
2539
2540 switch (idx) {
2541 case HISTC_SYMBOL_FROM:
2542 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2543 case HISTC_SYMBOL_TO:
2544 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2545 case HISTC_DSO_FROM:
2546 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2547 case HISTC_DSO_TO:
2548 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2549 default:
2550 break;
2551 }
2552
2553 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002554}
Namhyung Kim08e71542013-04-03 21:26:19 +09002555
2556void sort__setup_elide(FILE *output)
2557{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002558 struct perf_hpp_fmt *fmt;
2559 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002560
Jiri Olsacf094042016-01-18 10:24:17 +01002561 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002562 if (!perf_hpp__is_sort_entry(fmt))
2563 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002564
Jiri Olsaf2998422014-05-23 17:15:47 +02002565 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2566 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002567 }
2568
Namhyung Kim7524f632013-11-08 17:53:42 +09002569 /*
2570 * It makes no sense to elide all of sort entries.
2571 * Just revert them to show up again.
2572 */
Jiri Olsacf094042016-01-18 10:24:17 +01002573 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002574 if (!perf_hpp__is_sort_entry(fmt))
2575 continue;
2576
Jiri Olsaf2998422014-05-23 17:15:47 +02002577 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002578 return;
2579 }
2580
Jiri Olsacf094042016-01-18 10:24:17 +01002581 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002582 if (!perf_hpp__is_sort_entry(fmt))
2583 continue;
2584
Jiri Olsaf2998422014-05-23 17:15:47 +02002585 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002586 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002587}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002588
Jiri Olsa07600022016-01-18 10:24:16 +01002589static int output_field_add(struct perf_hpp_list *list, char *tok)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002590{
2591 unsigned int i;
2592
2593 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2594 struct sort_dimension *sd = &common_sort_dimensions[i];
2595
2596 if (strncasecmp(tok, sd->name, strlen(tok)))
2597 continue;
2598
Jiri Olsa07600022016-01-18 10:24:16 +01002599 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002600 }
2601
2602 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2603 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2604
2605 if (strncasecmp(tok, hd->name, strlen(tok)))
2606 continue;
2607
Jiri Olsa07600022016-01-18 10:24:16 +01002608 return __hpp_dimension__add_output(list, hd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002609 }
2610
2611 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2612 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2613
2614 if (strncasecmp(tok, sd->name, strlen(tok)))
2615 continue;
2616
Jiri Olsa07600022016-01-18 10:24:16 +01002617 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002618 }
2619
2620 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2621 struct sort_dimension *sd = &memory_sort_dimensions[i];
2622
2623 if (strncasecmp(tok, sd->name, strlen(tok)))
2624 continue;
2625
Jiri Olsa07600022016-01-18 10:24:16 +01002626 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002627 }
2628
2629 return -ESRCH;
2630}
2631
Jiri Olsa07600022016-01-18 10:24:16 +01002632static int setup_output_list(struct perf_hpp_list *list, char *str)
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002633{
2634 char *tmp, *tok;
2635 int ret = 0;
2636
2637 for (tok = strtok_r(str, ", ", &tmp);
2638 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Jiri Olsa07600022016-01-18 10:24:16 +01002639 ret = output_field_add(list, tok);
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002640 if (ret == -EINVAL) {
2641 error("Invalid --fields key: `%s'", tok);
2642 break;
2643 } else if (ret == -ESRCH) {
2644 error("Unknown --fields key: `%s'", tok);
2645 break;
2646 }
2647 }
2648
2649 return ret;
2650}
2651
Namhyung Kima7d945b2014-03-04 10:46:34 +09002652static void reset_dimensions(void)
2653{
2654 unsigned int i;
2655
2656 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2657 common_sort_dimensions[i].taken = 0;
2658
2659 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2660 hpp_sort_dimensions[i].taken = 0;
2661
2662 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2663 bstack_sort_dimensions[i].taken = 0;
2664
2665 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2666 memory_sort_dimensions[i].taken = 0;
2667}
2668
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002669bool is_strict_order(const char *order)
2670{
2671 return order && (*order != '+');
2672}
2673
Namhyung Kima7d945b2014-03-04 10:46:34 +09002674static int __setup_output_field(void)
2675{
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002676 char *str, *strp;
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002677 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002678
2679 if (field_order == NULL)
2680 return 0;
2681
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002682 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002683 if (str == NULL) {
2684 error("Not enough memory to setup output fields");
2685 return -ENOMEM;
2686 }
2687
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002688 if (!is_strict_order(field_order))
2689 strp++;
2690
2691 if (!strlen(strp)) {
2692 error("Invalid --fields key: `+'");
2693 goto out;
2694 }
2695
Jiri Olsa07600022016-01-18 10:24:16 +01002696 ret = setup_output_list(&perf_hpp_list, strp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002697
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002698out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002699 free(str);
2700 return ret;
2701}
2702
Arnaldo Carvalho de Melo9b240632016-03-02 09:58:00 -03002703int setup_sorting(struct perf_evlist *evlist)
2704{
2705 int err;
2706
2707 err = __setup_sorting(evlist);
2708 if (err < 0)
2709 return err;
2710
2711 if (parent_pattern != default_parent_pattern) {
Jiri Olsad7b617f2016-03-09 11:04:17 +01002712 err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
Arnaldo Carvalho de Melo9b240632016-03-02 09:58:00 -03002713 if (err < 0)
2714 return err;
2715 }
2716
Namhyung Kima7d945b2014-03-04 10:46:34 +09002717 reset_dimensions();
2718
2719 /*
2720 * perf diff doesn't use default hpp output fields.
2721 */
2722 if (sort__mode != SORT_MODE__DIFF)
2723 perf_hpp__init();
2724
2725 err = __setup_output_field();
2726 if (err < 0)
2727 return err;
2728
2729 /* copy sort keys to output fields */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002730 perf_hpp__setup_output_field(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002731 /* and then copy output fields to sort keys */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002732 perf_hpp__append_sort_keys(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002733
Namhyung Kimc3bc0c42016-03-07 16:44:45 -03002734 /* setup hists-specific output fields */
2735 if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
2736 return -1;
2737
Namhyung Kima7d945b2014-03-04 10:46:34 +09002738 return 0;
2739}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002740
2741void reset_output_field(void)
2742{
Jiri Olsa52225032016-05-03 13:54:42 +02002743 perf_hpp_list.need_collapse = 0;
Jiri Olsade7e6a72016-05-03 13:54:43 +02002744 perf_hpp_list.parent = 0;
Jiri Olsa2e0453a2016-05-03 13:54:44 +02002745 perf_hpp_list.sym = 0;
Jiri Olsa69849fc2016-05-03 13:54:45 +02002746 perf_hpp_list.dso = 0;
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002747
Namhyung Kimd69b2962014-05-23 10:59:01 +09002748 field_order = NULL;
2749 sort_order = NULL;
2750
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002751 reset_dimensions();
Jiri Olsa43e0a682016-01-18 10:24:21 +01002752 perf_hpp__reset_output_field(&perf_hpp_list);
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002753}