blob: 6f4605b5beb55bcaee42053f2a7b4819cab10a9d [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>
John Kacurdd68ada2009-09-24 18:02:49 +02009
10regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -030011const char default_parent_pattern[] = "^sys_|^do_page_fault";
12const char *parent_pattern = default_parent_pattern;
13const char default_sort_order[] = "comm,dso,symbol";
Andi Kleen40997d62015-07-18 08:24:53 -070014const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090015const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
16const char default_top_sort_order[] = "dso,symbol";
17const char default_diff_sort_order[] = "dso,symbol";
Namhyung Kimd49dade2015-12-23 02:07:10 +090018const char default_tracepoint_sort_order[] = "trace";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090019const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090020const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080021regex_t ignore_callees_regex;
22int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020023int sort__need_collapse = 0;
24int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090025int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090026int sort__has_dso = 0;
Kan Liang2e7ea3a2015-09-04 10:45:43 -040027int sort__has_socket = 0;
Namhyung Kimcfd92da2016-01-21 19:13:24 -030028int sort__has_thread = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090029enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020030
Arnaldo Carvalho de Melo37d9bb52016-02-12 11:27:51 -030031/*
32 * Replaces all occurrences of a char used with the:
33 *
34 * -t, --field-separator
35 *
36 * option, that uses a special separator character and don't pad with spaces,
37 * replacing all occurances of this separator in symbol names (and other
38 * output) with a '.' character, that thus it's the only non valid separator.
39*/
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030040static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020041{
42 int n;
43 va_list ap;
44
45 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030046 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020047 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030048 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020049
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030050 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020051 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030052 if (sep == NULL)
53 break;
54 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020055 }
John Kacurdd68ada2009-09-24 18:02:49 +020056 }
57 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110058
59 if (n >= (int)size)
60 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020061 return n;
62}
63
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020064static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020065{
66 if (!l && !r)
67 return 0;
68 else if (!l)
69 return -1;
70 else
71 return 1;
72}
73
74/* --sort pid */
75
76static int64_t
77sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
78{
Adrian Hunter38051232013-07-04 16:20:31 +030079 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020080}
81
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030082static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030083 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020084{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020085 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090086
87 width = max(7U, width) - 6;
88 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
89 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020090}
91
Frederic Weisbecker872a8782011-06-29 03:14:52 +020092struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090093 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020094 .se_cmp = sort__thread_cmp,
95 .se_snprintf = hist_entry__thread_snprintf,
96 .se_width_idx = HISTC_THREAD,
97};
98
99/* --sort comm */
100
101static int64_t
102sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
103{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +0200104 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200105 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200106}
107
108static int64_t
109sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
110{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900111 /* 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
Namhyung Kim202e7a62014-03-04 11:01:41 +0900115static int64_t
116sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
117{
118 return strcmp(comm__str(right->comm), comm__str(left->comm));
119}
120
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300121static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300122 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200123{
Namhyung Kim5b591662014-07-31 14:47:38 +0900124 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200125}
126
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900127struct sort_entry sort_comm = {
128 .se_header = "Command",
129 .se_cmp = sort__comm_cmp,
130 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900131 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900132 .se_snprintf = hist_entry__comm_snprintf,
133 .se_width_idx = HISTC_COMM,
134};
135
136/* --sort dso */
137
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100138static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200139{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100140 struct dso *dso_l = map_l ? map_l->dso : NULL;
141 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300142 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200143
144 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900145 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200146
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300147 if (verbose) {
148 dso_name_l = dso_l->long_name;
149 dso_name_r = dso_r->long_name;
150 } else {
151 dso_name_l = dso_l->short_name;
152 dso_name_r = dso_r->short_name;
153 }
154
155 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200156}
157
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100158static int64_t
159sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200160{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900161 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100162}
163
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164static int _hist_entry__dso_snprintf(struct map *map, char *bf,
165 size_t size, unsigned int width)
166{
167 if (map && map->dso) {
168 const char *dso_name = !verbose ? map->dso->short_name :
169 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900170 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300171 }
John Kacurdd68ada2009-09-24 18:02:49 +0200172
Namhyung Kim5b591662014-07-31 14:47:38 +0900173 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200174}
175
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300176static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100177 size_t size, unsigned int width)
178{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300179 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100180}
181
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900182struct sort_entry sort_dso = {
183 .se_header = "Shared Object",
184 .se_cmp = sort__dso_cmp,
185 .se_snprintf = hist_entry__dso_snprintf,
186 .se_width_idx = HISTC_DSO,
187};
188
189/* --sort symbol */
190
Namhyung Kim2037be52013-12-18 14:21:09 +0900191static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
192{
193 return (int64_t)(right_ip - left_ip);
194}
195
Namhyung Kim51f27d12013-02-06 14:57:15 +0900196static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900197{
198 if (!sym_l || !sym_r)
199 return cmp_null(sym_l, sym_r);
200
201 if (sym_l == sym_r)
202 return 0;
203
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700204 if (sym_l->start != sym_r->start)
205 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700207 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900208}
209
210static int64_t
211sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
212{
Namhyung Kim09600e02013-10-15 11:01:56 +0900213 int64_t ret;
214
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900215 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900216 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900217
Namhyung Kim09600e02013-10-15 11:01:56 +0900218 /*
219 * comparing symbol address alone is not enough since it's a
220 * relative address within a dso.
221 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900222 if (!sort__has_dso) {
223 ret = sort__dso_cmp(left, right);
224 if (ret != 0)
225 return ret;
226 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900227
Namhyung Kim51f27d12013-02-06 14:57:15 +0900228 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900229}
230
Namhyung Kim202e7a62014-03-04 11:01:41 +0900231static int64_t
232sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
233{
234 if (!left->ms.sym || !right->ms.sym)
235 return cmp_null(left->ms.sym, right->ms.sym);
236
237 return strcmp(right->ms.sym->name, left->ms.sym->name);
238}
239
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100240static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
241 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900242 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100243{
244 size_t ret = 0;
245
246 if (verbose) {
247 char o = map ? dso__symtab_origin(map->dso) : '!';
248 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900249 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100250 }
251
252 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100253 if (sym && map) {
254 if (map->type == MAP__VARIABLE) {
255 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
256 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100257 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100258 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300259 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
Stephane Eranian98a3b322013-01-24 16:10:35 +0100260 width - ret,
261 sym->name);
262 }
263 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100264 size_t len = BITS_PER_LONG / 4;
265 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
266 len, ip);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100267 }
268
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300269 return ret;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270}
271
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300272static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900273 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100274{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300275 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
276 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100277}
John Kacurdd68ada2009-09-24 18:02:49 +0200278
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200279struct sort_entry sort_sym = {
280 .se_header = "Symbol",
281 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900282 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200283 .se_snprintf = hist_entry__sym_snprintf,
284 .se_width_idx = HISTC_SYMBOL,
285};
John Kacurdd68ada2009-09-24 18:02:49 +0200286
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300287/* --sort srcline */
288
Namhyung Kimcecaec62016-02-22 09:31:51 +0900289static char *hist_entry__get_srcline(struct hist_entry *he)
290{
291 struct map *map = he->ms.map;
292
293 if (!map)
294 return SRCLINE_UNKNOWN;
295
296 return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
297 he->ms.sym, true);
298}
299
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300300static int64_t
301sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
302{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900303 if (!left->srcline)
304 left->srcline = hist_entry__get_srcline(left);
305 if (!right->srcline)
306 right->srcline = hist_entry__get_srcline(right);
307
Namhyung Kim202e7a62014-03-04 11:01:41 +0900308 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300309}
310
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300311static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900312 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900314 if (!he->srcline)
315 he->srcline = hist_entry__get_srcline(he);
316
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300317 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300318}
319
320struct sort_entry sort_srcline = {
321 .se_header = "Source:Line",
322 .se_cmp = sort__srcline_cmp,
323 .se_snprintf = hist_entry__srcline_snprintf,
324 .se_width_idx = HISTC_SRCLINE,
325};
326
Andi Kleen31191a82015-08-07 15:54:24 -0700327/* --sort srcfile */
328
329static char no_srcfile[1];
330
Namhyung Kimcecaec62016-02-22 09:31:51 +0900331static char *hist_entry__get_srcfile(struct hist_entry *e)
Andi Kleen31191a82015-08-07 15:54:24 -0700332{
333 char *sf, *p;
334 struct map *map = e->ms.map;
335
Namhyung Kimcecaec62016-02-22 09:31:51 +0900336 if (!map)
337 return no_srcfile;
338
Andi Kleen2f84b422015-09-01 11:47:19 -0700339 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
340 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700341 if (!strcmp(sf, SRCLINE_UNKNOWN))
342 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700343 p = strchr(sf, ':');
344 if (p && *sf) {
345 *p = 0;
346 return sf;
347 }
348 free(sf);
349 return no_srcfile;
350}
351
352static int64_t
353sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
354{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900355 if (!left->srcfile)
356 left->srcfile = hist_entry__get_srcfile(left);
357 if (!right->srcfile)
358 right->srcfile = hist_entry__get_srcfile(right);
359
Andi Kleen31191a82015-08-07 15:54:24 -0700360 return strcmp(right->srcfile, left->srcfile);
361}
362
363static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
364 size_t size, unsigned int width)
365{
Namhyung Kimcecaec62016-02-22 09:31:51 +0900366 if (!he->srcfile)
367 he->srcfile = hist_entry__get_srcfile(he);
368
Andi Kleen31191a82015-08-07 15:54:24 -0700369 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
370}
371
372struct sort_entry sort_srcfile = {
373 .se_header = "Source File",
374 .se_cmp = sort__srcfile_cmp,
375 .se_snprintf = hist_entry__srcfile_snprintf,
376 .se_width_idx = HISTC_SRCFILE,
377};
378
John Kacurdd68ada2009-09-24 18:02:49 +0200379/* --sort parent */
380
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200381static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200382sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct symbol *sym_l = left->parent;
385 struct symbol *sym_r = right->parent;
386
387 if (!sym_l || !sym_r)
388 return cmp_null(sym_l, sym_r);
389
Namhyung Kim202e7a62014-03-04 11:01:41 +0900390 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200391}
392
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300393static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300394 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200395{
Namhyung Kim5b591662014-07-31 14:47:38 +0900396 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200398}
399
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200400struct sort_entry sort_parent = {
401 .se_header = "Parent symbol",
402 .se_cmp = sort__parent_cmp,
403 .se_snprintf = hist_entry__parent_snprintf,
404 .se_width_idx = HISTC_PARENT,
405};
406
Arun Sharmaf60f3592010-06-04 11:27:10 -0300407/* --sort cpu */
408
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200409static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300410sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
411{
412 return right->cpu - left->cpu;
413}
414
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300415static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
416 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300417{
Namhyung Kim5b591662014-07-31 14:47:38 +0900418 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300419}
420
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200421struct sort_entry sort_cpu = {
422 .se_header = "CPU",
423 .se_cmp = sort__cpu_cmp,
424 .se_snprintf = hist_entry__cpu_snprintf,
425 .se_width_idx = HISTC_CPU,
426};
427
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400428/* --sort socket */
429
430static int64_t
431sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
432{
433 return right->socket - left->socket;
434}
435
436static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
437 size_t size, unsigned int width)
438{
439 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
440}
441
442struct sort_entry sort_socket = {
443 .se_header = "Socket",
444 .se_cmp = sort__socket_cmp,
445 .se_snprintf = hist_entry__socket_snprintf,
446 .se_width_idx = HISTC_SOCKET,
447};
448
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900449/* --sort trace */
450
451static char *get_trace_output(struct hist_entry *he)
452{
453 struct trace_seq seq;
454 struct perf_evsel *evsel;
455 struct pevent_record rec = {
456 .data = he->raw_data,
457 .size = he->raw_size,
458 };
459
460 evsel = hists_to_evsel(he->hists);
461
462 trace_seq_init(&seq);
Namhyung Kim053a3982015-12-23 02:07:05 +0900463 if (symbol_conf.raw_trace) {
464 pevent_print_fields(&seq, he->raw_data, he->raw_size,
465 evsel->tp_format);
466 } else {
467 pevent_event_info(&seq, evsel->tp_format, &rec);
468 }
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900469 return seq.buffer;
470}
471
472static int64_t
473sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 struct perf_evsel *evsel;
476
477 evsel = hists_to_evsel(left->hists);
478 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
479 return 0;
480
481 if (left->trace_output == NULL)
482 left->trace_output = get_trace_output(left);
483 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right);
485
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output);
490}
491
492static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
493 size_t size, unsigned int width)
494{
495 struct perf_evsel *evsel;
496
497 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
500
501 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
504}
505
506struct sort_entry sort_trace = {
507 .se_header = "Trace output",
508 .se_cmp = sort__trace_cmp,
509 .se_snprintf = hist_entry__trace_snprintf,
510 .se_width_idx = HISTC_TRACE,
511};
512
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900513/* sort keys for branch stacks */
514
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100515static int64_t
516sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
517{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200518 if (!left->branch_info || !right->branch_info)
519 return cmp_null(left->branch_info, right->branch_info);
520
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100521 return _sort__dso_cmp(left->branch_info->from.map,
522 right->branch_info->from.map);
523}
524
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300525static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100526 size_t size, unsigned int width)
527{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200528 if (he->branch_info)
529 return _hist_entry__dso_snprintf(he->branch_info->from.map,
530 bf, size, width);
531 else
532 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100533}
534
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100535static int64_t
536sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
537{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200538 if (!left->branch_info || !right->branch_info)
539 return cmp_null(left->branch_info, right->branch_info);
540
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100541 return _sort__dso_cmp(left->branch_info->to.map,
542 right->branch_info->to.map);
543}
544
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300545static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100546 size_t size, unsigned int width)
547{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200548 if (he->branch_info)
549 return _hist_entry__dso_snprintf(he->branch_info->to.map,
550 bf, size, width);
551 else
552 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100553}
554
555static int64_t
556sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
557{
558 struct addr_map_symbol *from_l = &left->branch_info->from;
559 struct addr_map_symbol *from_r = &right->branch_info->from;
560
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200561 if (!left->branch_info || !right->branch_info)
562 return cmp_null(left->branch_info, right->branch_info);
563
564 from_l = &left->branch_info->from;
565 from_r = &right->branch_info->from;
566
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100567 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900568 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100569
Namhyung Kim51f27d12013-02-06 14:57:15 +0900570 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100571}
572
573static int64_t
574sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
575{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200576 struct addr_map_symbol *to_l, *to_r;
577
578 if (!left->branch_info || !right->branch_info)
579 return cmp_null(left->branch_info, right->branch_info);
580
581 to_l = &left->branch_info->to;
582 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100583
584 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900585 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100586
Namhyung Kim51f27d12013-02-06 14:57:15 +0900587 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100588}
589
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300590static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900591 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100592{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200593 if (he->branch_info) {
594 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100595
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200596 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
597 he->level, bf, size, width);
598 }
599
600 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100601}
602
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300603static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900604 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100605{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200606 if (he->branch_info) {
607 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100608
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200609 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
610 he->level, bf, size, width);
611 }
612
613 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100614}
615
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900616struct sort_entry sort_dso_from = {
617 .se_header = "Source Shared Object",
618 .se_cmp = sort__dso_from_cmp,
619 .se_snprintf = hist_entry__dso_from_snprintf,
620 .se_width_idx = HISTC_DSO_FROM,
621};
622
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100623struct sort_entry sort_dso_to = {
624 .se_header = "Target Shared Object",
625 .se_cmp = sort__dso_to_cmp,
626 .se_snprintf = hist_entry__dso_to_snprintf,
627 .se_width_idx = HISTC_DSO_TO,
628};
629
630struct sort_entry sort_sym_from = {
631 .se_header = "Source Symbol",
632 .se_cmp = sort__sym_from_cmp,
633 .se_snprintf = hist_entry__sym_from_snprintf,
634 .se_width_idx = HISTC_SYMBOL_FROM,
635};
636
637struct sort_entry sort_sym_to = {
638 .se_header = "Target Symbol",
639 .se_cmp = sort__sym_to_cmp,
640 .se_snprintf = hist_entry__sym_to_snprintf,
641 .se_width_idx = HISTC_SYMBOL_TO,
642};
643
644static int64_t
645sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
646{
Jiri Olsa428560e2014-10-16 16:07:03 +0200647 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100648
Jiri Olsa428560e2014-10-16 16:07:03 +0200649 if (!left->branch_info || !right->branch_info)
650 return cmp_null(left->branch_info, right->branch_info);
651
652 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
653 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100654 return mp || p;
655}
656
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300657static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100658 size_t size, unsigned int width){
659 static const char *out = "N/A";
660
Jiri Olsa428560e2014-10-16 16:07:03 +0200661 if (he->branch_info) {
662 if (he->branch_info->flags.predicted)
663 out = "N";
664 else if (he->branch_info->flags.mispred)
665 out = "Y";
666 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100667
Namhyung Kim5b591662014-07-31 14:47:38 +0900668 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100669}
670
Andi Kleen0e332f02015-07-18 08:24:46 -0700671static int64_t
672sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
673{
674 return left->branch_info->flags.cycles -
675 right->branch_info->flags.cycles;
676}
677
678static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
679 size_t size, unsigned int width)
680{
681 if (he->branch_info->flags.cycles == 0)
682 return repsep_snprintf(bf, size, "%-*s", width, "-");
683 return repsep_snprintf(bf, size, "%-*hd", width,
684 he->branch_info->flags.cycles);
685}
686
687struct sort_entry sort_cycles = {
688 .se_header = "Basic Block Cycles",
689 .se_cmp = sort__cycles_cmp,
690 .se_snprintf = hist_entry__cycles_snprintf,
691 .se_width_idx = HISTC_CYCLES,
692};
693
Stephane Eranian98a3b322013-01-24 16:10:35 +0100694/* --sort daddr_sym */
695static int64_t
696sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
697{
698 uint64_t l = 0, r = 0;
699
700 if (left->mem_info)
701 l = left->mem_info->daddr.addr;
702 if (right->mem_info)
703 r = right->mem_info->daddr.addr;
704
705 return (int64_t)(r - l);
706}
707
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300708static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100709 size_t size, unsigned int width)
710{
711 uint64_t addr = 0;
712 struct map *map = NULL;
713 struct symbol *sym = NULL;
714
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300715 if (he->mem_info) {
716 addr = he->mem_info->daddr.addr;
717 map = he->mem_info->daddr.map;
718 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100719 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300720 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100721 width);
722}
723
724static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200725sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
726{
727 uint64_t l = 0, r = 0;
728
729 if (left->mem_info)
730 l = left->mem_info->iaddr.addr;
731 if (right->mem_info)
732 r = right->mem_info->iaddr.addr;
733
734 return (int64_t)(r - l);
735}
736
737static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
738 size_t size, unsigned int width)
739{
740 uint64_t addr = 0;
741 struct map *map = NULL;
742 struct symbol *sym = NULL;
743
744 if (he->mem_info) {
745 addr = he->mem_info->iaddr.addr;
746 map = he->mem_info->iaddr.map;
747 sym = he->mem_info->iaddr.sym;
748 }
749 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
750 width);
751}
752
753static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100754sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
755{
756 struct map *map_l = NULL;
757 struct map *map_r = NULL;
758
759 if (left->mem_info)
760 map_l = left->mem_info->daddr.map;
761 if (right->mem_info)
762 map_r = right->mem_info->daddr.map;
763
764 return _sort__dso_cmp(map_l, map_r);
765}
766
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300767static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100768 size_t size, unsigned int width)
769{
770 struct map *map = NULL;
771
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300772 if (he->mem_info)
773 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100774
775 return _hist_entry__dso_snprintf(map, bf, size, width);
776}
777
778static int64_t
779sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
780{
781 union perf_mem_data_src data_src_l;
782 union perf_mem_data_src data_src_r;
783
784 if (left->mem_info)
785 data_src_l = left->mem_info->data_src;
786 else
787 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
788
789 if (right->mem_info)
790 data_src_r = right->mem_info->data_src;
791 else
792 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
793
794 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
795}
796
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300797static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100798 size_t size, unsigned int width)
799{
800 const char *out;
801 u64 mask = PERF_MEM_LOCK_NA;
802
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300803 if (he->mem_info)
804 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100805
806 if (mask & PERF_MEM_LOCK_NA)
807 out = "N/A";
808 else if (mask & PERF_MEM_LOCK_LOCKED)
809 out = "Yes";
810 else
811 out = "No";
812
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300813 return repsep_snprintf(bf, size, "%.*s", width, out);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100814}
815
816static int64_t
817sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
818{
819 union perf_mem_data_src data_src_l;
820 union perf_mem_data_src data_src_r;
821
822 if (left->mem_info)
823 data_src_l = left->mem_info->data_src;
824 else
825 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
826
827 if (right->mem_info)
828 data_src_r = right->mem_info->data_src;
829 else
830 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
831
832 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
833}
834
835static const char * const tlb_access[] = {
836 "N/A",
837 "HIT",
838 "MISS",
839 "L1",
840 "L2",
841 "Walker",
842 "Fault",
843};
844#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
845
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300846static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100847 size_t size, unsigned int width)
848{
849 char out[64];
850 size_t sz = sizeof(out) - 1; /* -1 for null termination */
851 size_t l = 0, i;
852 u64 m = PERF_MEM_TLB_NA;
853 u64 hit, miss;
854
855 out[0] = '\0';
856
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300857 if (he->mem_info)
858 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100859
860 hit = m & PERF_MEM_TLB_HIT;
861 miss = m & PERF_MEM_TLB_MISS;
862
863 /* already taken care of */
864 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
865
866 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
867 if (!(m & 0x1))
868 continue;
869 if (l) {
870 strcat(out, " or ");
871 l += 4;
872 }
873 strncat(out, tlb_access[i], sz - l);
874 l += strlen(tlb_access[i]);
875 }
876 if (*out == '\0')
877 strcpy(out, "N/A");
878 if (hit)
879 strncat(out, " hit", sz - l);
880 if (miss)
881 strncat(out, " miss", sz - l);
882
883 return repsep_snprintf(bf, size, "%-*s", width, out);
884}
885
886static int64_t
887sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
888{
889 union perf_mem_data_src data_src_l;
890 union perf_mem_data_src data_src_r;
891
892 if (left->mem_info)
893 data_src_l = left->mem_info->data_src;
894 else
895 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
896
897 if (right->mem_info)
898 data_src_r = right->mem_info->data_src;
899 else
900 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
901
902 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
903}
904
905static const char * const mem_lvl[] = {
906 "N/A",
907 "HIT",
908 "MISS",
909 "L1",
910 "LFB",
911 "L2",
912 "L3",
913 "Local RAM",
914 "Remote RAM (1 hop)",
915 "Remote RAM (2 hops)",
916 "Remote Cache (1 hop)",
917 "Remote Cache (2 hops)",
918 "I/O",
919 "Uncached",
920};
921#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
922
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300923static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100924 size_t size, unsigned int width)
925{
926 char out[64];
927 size_t sz = sizeof(out) - 1; /* -1 for null termination */
928 size_t i, l = 0;
929 u64 m = PERF_MEM_LVL_NA;
930 u64 hit, miss;
931
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300932 if (he->mem_info)
933 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100934
935 out[0] = '\0';
936
937 hit = m & PERF_MEM_LVL_HIT;
938 miss = m & PERF_MEM_LVL_MISS;
939
940 /* already taken care of */
941 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
942
943 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
944 if (!(m & 0x1))
945 continue;
946 if (l) {
947 strcat(out, " or ");
948 l += 4;
949 }
950 strncat(out, mem_lvl[i], sz - l);
951 l += strlen(mem_lvl[i]);
952 }
953 if (*out == '\0')
954 strcpy(out, "N/A");
955 if (hit)
956 strncat(out, " hit", sz - l);
957 if (miss)
958 strncat(out, " miss", sz - l);
959
960 return repsep_snprintf(bf, size, "%-*s", width, out);
961}
962
963static int64_t
964sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
965{
966 union perf_mem_data_src data_src_l;
967 union perf_mem_data_src data_src_r;
968
969 if (left->mem_info)
970 data_src_l = left->mem_info->data_src;
971 else
972 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
973
974 if (right->mem_info)
975 data_src_r = right->mem_info->data_src;
976 else
977 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
978
979 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
980}
981
982static const char * const snoop_access[] = {
983 "N/A",
984 "None",
985 "Miss",
986 "Hit",
987 "HitM",
988};
989#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
990
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300991static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100992 size_t size, unsigned int width)
993{
994 char out[64];
995 size_t sz = sizeof(out) - 1; /* -1 for null termination */
996 size_t i, l = 0;
997 u64 m = PERF_MEM_SNOOP_NA;
998
999 out[0] = '\0';
1000
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001001 if (he->mem_info)
1002 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +01001003
1004 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1005 if (!(m & 0x1))
1006 continue;
1007 if (l) {
1008 strcat(out, " or ");
1009 l += 4;
1010 }
1011 strncat(out, snoop_access[i], sz - l);
1012 l += strlen(snoop_access[i]);
1013 }
1014
1015 if (*out == '\0')
1016 strcpy(out, "N/A");
1017
1018 return repsep_snprintf(bf, size, "%-*s", width, out);
1019}
1020
Don Zickus9b32ba72014-06-01 15:38:29 +02001021static inline u64 cl_address(u64 address)
1022{
1023 /* return the cacheline of the address */
1024 return (address & ~(cacheline_size - 1));
1025}
1026
1027static int64_t
1028sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1029{
1030 u64 l, r;
1031 struct map *l_map, *r_map;
1032
1033 if (!left->mem_info) return -1;
1034 if (!right->mem_info) return 1;
1035
1036 /* group event types together */
1037 if (left->cpumode > right->cpumode) return -1;
1038 if (left->cpumode < right->cpumode) return 1;
1039
1040 l_map = left->mem_info->daddr.map;
1041 r_map = right->mem_info->daddr.map;
1042
1043 /* if both are NULL, jump to sort on al_addr instead */
1044 if (!l_map && !r_map)
1045 goto addr;
1046
1047 if (!l_map) return -1;
1048 if (!r_map) return 1;
1049
1050 if (l_map->maj > r_map->maj) return -1;
1051 if (l_map->maj < r_map->maj) return 1;
1052
1053 if (l_map->min > r_map->min) return -1;
1054 if (l_map->min < r_map->min) return 1;
1055
1056 if (l_map->ino > r_map->ino) return -1;
1057 if (l_map->ino < r_map->ino) return 1;
1058
1059 if (l_map->ino_generation > r_map->ino_generation) return -1;
1060 if (l_map->ino_generation < r_map->ino_generation) return 1;
1061
1062 /*
1063 * Addresses with no major/minor numbers are assumed to be
1064 * anonymous in userspace. Sort those on pid then address.
1065 *
1066 * The kernel and non-zero major/minor mapped areas are
1067 * assumed to be unity mapped. Sort those on address.
1068 */
1069
1070 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1071 (!(l_map->flags & MAP_SHARED)) &&
1072 !l_map->maj && !l_map->min && !l_map->ino &&
1073 !l_map->ino_generation) {
1074 /* userspace anonymous */
1075
1076 if (left->thread->pid_ > right->thread->pid_) return -1;
1077 if (left->thread->pid_ < right->thread->pid_) return 1;
1078 }
1079
1080addr:
1081 /* al_addr does all the right addr - start + offset calculations */
1082 l = cl_address(left->mem_info->daddr.al_addr);
1083 r = cl_address(right->mem_info->daddr.al_addr);
1084
1085 if (l > r) return -1;
1086 if (l < r) return 1;
1087
1088 return 0;
1089}
1090
1091static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1092 size_t size, unsigned int width)
1093{
1094
1095 uint64_t addr = 0;
1096 struct map *map = NULL;
1097 struct symbol *sym = NULL;
1098 char level = he->level;
1099
1100 if (he->mem_info) {
1101 addr = cl_address(he->mem_info->daddr.al_addr);
1102 map = he->mem_info->daddr.map;
1103 sym = he->mem_info->daddr.sym;
1104
1105 /* print [s] for shared data mmaps */
1106 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1107 map && (map->type == MAP__VARIABLE) &&
1108 (map->flags & MAP_SHARED) &&
1109 (map->maj || map->min || map->ino ||
1110 map->ino_generation))
1111 level = 's';
1112 else if (!map)
1113 level = 'X';
1114 }
1115 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1116 width);
1117}
1118
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001119struct sort_entry sort_mispredict = {
1120 .se_header = "Branch Mispredicted",
1121 .se_cmp = sort__mispredict_cmp,
1122 .se_snprintf = hist_entry__mispredict_snprintf,
1123 .se_width_idx = HISTC_MISPREDICT,
1124};
1125
Andi Kleen05484292013-01-24 16:10:29 +01001126static u64 he_weight(struct hist_entry *he)
1127{
1128 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1129}
1130
1131static int64_t
1132sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1133{
1134 return he_weight(left) - he_weight(right);
1135}
1136
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001137static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001138 size_t size, unsigned int width)
1139{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001140 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001141}
1142
1143struct sort_entry sort_local_weight = {
1144 .se_header = "Local Weight",
1145 .se_cmp = sort__local_weight_cmp,
1146 .se_snprintf = hist_entry__local_weight_snprintf,
1147 .se_width_idx = HISTC_LOCAL_WEIGHT,
1148};
1149
1150static int64_t
1151sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1152{
1153 return left->stat.weight - right->stat.weight;
1154}
1155
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001156static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001157 size_t size, unsigned int width)
1158{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001159 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001160}
1161
1162struct sort_entry sort_global_weight = {
1163 .se_header = "Weight",
1164 .se_cmp = sort__global_weight_cmp,
1165 .se_snprintf = hist_entry__global_weight_snprintf,
1166 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1167};
1168
Stephane Eranian98a3b322013-01-24 16:10:35 +01001169struct sort_entry sort_mem_daddr_sym = {
1170 .se_header = "Data Symbol",
1171 .se_cmp = sort__daddr_cmp,
1172 .se_snprintf = hist_entry__daddr_snprintf,
1173 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1174};
1175
Don Zickus28e6db22015-10-05 20:06:07 +02001176struct sort_entry sort_mem_iaddr_sym = {
1177 .se_header = "Code Symbol",
1178 .se_cmp = sort__iaddr_cmp,
1179 .se_snprintf = hist_entry__iaddr_snprintf,
1180 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1181};
1182
Stephane Eranian98a3b322013-01-24 16:10:35 +01001183struct sort_entry sort_mem_daddr_dso = {
1184 .se_header = "Data Object",
1185 .se_cmp = sort__dso_daddr_cmp,
1186 .se_snprintf = hist_entry__dso_daddr_snprintf,
1187 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1188};
1189
1190struct sort_entry sort_mem_locked = {
1191 .se_header = "Locked",
1192 .se_cmp = sort__locked_cmp,
1193 .se_snprintf = hist_entry__locked_snprintf,
1194 .se_width_idx = HISTC_MEM_LOCKED,
1195};
1196
1197struct sort_entry sort_mem_tlb = {
1198 .se_header = "TLB access",
1199 .se_cmp = sort__tlb_cmp,
1200 .se_snprintf = hist_entry__tlb_snprintf,
1201 .se_width_idx = HISTC_MEM_TLB,
1202};
1203
1204struct sort_entry sort_mem_lvl = {
1205 .se_header = "Memory access",
1206 .se_cmp = sort__lvl_cmp,
1207 .se_snprintf = hist_entry__lvl_snprintf,
1208 .se_width_idx = HISTC_MEM_LVL,
1209};
1210
1211struct sort_entry sort_mem_snoop = {
1212 .se_header = "Snoop",
1213 .se_cmp = sort__snoop_cmp,
1214 .se_snprintf = hist_entry__snoop_snprintf,
1215 .se_width_idx = HISTC_MEM_SNOOP,
1216};
1217
Don Zickus9b32ba72014-06-01 15:38:29 +02001218struct sort_entry sort_mem_dcacheline = {
1219 .se_header = "Data Cacheline",
1220 .se_cmp = sort__dcacheline_cmp,
1221 .se_snprintf = hist_entry__dcacheline_snprintf,
1222 .se_width_idx = HISTC_MEM_DCACHELINE,
1223};
1224
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001225static int64_t
1226sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1227{
Jiri Olsa49f47442014-10-16 16:07:01 +02001228 if (!left->branch_info || !right->branch_info)
1229 return cmp_null(left->branch_info, right->branch_info);
1230
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001231 return left->branch_info->flags.abort !=
1232 right->branch_info->flags.abort;
1233}
1234
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001235static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001236 size_t size, unsigned int width)
1237{
Jiri Olsa49f47442014-10-16 16:07:01 +02001238 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001239
Jiri Olsa49f47442014-10-16 16:07:01 +02001240 if (he->branch_info) {
1241 if (he->branch_info->flags.abort)
1242 out = "A";
1243 else
1244 out = ".";
1245 }
1246
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001247 return repsep_snprintf(bf, size, "%-*s", width, out);
1248}
1249
1250struct sort_entry sort_abort = {
1251 .se_header = "Transaction abort",
1252 .se_cmp = sort__abort_cmp,
1253 .se_snprintf = hist_entry__abort_snprintf,
1254 .se_width_idx = HISTC_ABORT,
1255};
1256
1257static int64_t
1258sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1259{
Jiri Olsa0199d242014-10-16 16:07:02 +02001260 if (!left->branch_info || !right->branch_info)
1261 return cmp_null(left->branch_info, right->branch_info);
1262
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001263 return left->branch_info->flags.in_tx !=
1264 right->branch_info->flags.in_tx;
1265}
1266
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001267static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001268 size_t size, unsigned int width)
1269{
Jiri Olsa0199d242014-10-16 16:07:02 +02001270 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001271
Jiri Olsa0199d242014-10-16 16:07:02 +02001272 if (he->branch_info) {
1273 if (he->branch_info->flags.in_tx)
1274 out = "T";
1275 else
1276 out = ".";
1277 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001278
1279 return repsep_snprintf(bf, size, "%-*s", width, out);
1280}
1281
1282struct sort_entry sort_in_tx = {
1283 .se_header = "Branch in transaction",
1284 .se_cmp = sort__in_tx_cmp,
1285 .se_snprintf = hist_entry__in_tx_snprintf,
1286 .se_width_idx = HISTC_IN_TX,
1287};
1288
Andi Kleen475eeab2013-09-20 07:40:43 -07001289static int64_t
1290sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1291{
1292 return left->transaction - right->transaction;
1293}
1294
1295static inline char *add_str(char *p, const char *str)
1296{
1297 strcpy(p, str);
1298 return p + strlen(str);
1299}
1300
1301static struct txbit {
1302 unsigned flag;
1303 const char *name;
1304 int skip_for_len;
1305} txbits[] = {
1306 { PERF_TXN_ELISION, "EL ", 0 },
1307 { PERF_TXN_TRANSACTION, "TX ", 1 },
1308 { PERF_TXN_SYNC, "SYNC ", 1 },
1309 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1310 { PERF_TXN_RETRY, "RETRY ", 0 },
1311 { PERF_TXN_CONFLICT, "CON ", 0 },
1312 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1313 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1314 { 0, NULL, 0 }
1315};
1316
1317int hist_entry__transaction_len(void)
1318{
1319 int i;
1320 int len = 0;
1321
1322 for (i = 0; txbits[i].name; i++) {
1323 if (!txbits[i].skip_for_len)
1324 len += strlen(txbits[i].name);
1325 }
1326 len += 4; /* :XX<space> */
1327 return len;
1328}
1329
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001330static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001331 size_t size, unsigned int width)
1332{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001333 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001334 char buf[128];
1335 char *p = buf;
1336 int i;
1337
1338 buf[0] = 0;
1339 for (i = 0; txbits[i].name; i++)
1340 if (txbits[i].flag & t)
1341 p = add_str(p, txbits[i].name);
1342 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1343 p = add_str(p, "NEITHER ");
1344 if (t & PERF_TXN_ABORT_MASK) {
1345 sprintf(p, ":%" PRIx64,
1346 (t & PERF_TXN_ABORT_MASK) >>
1347 PERF_TXN_ABORT_SHIFT);
1348 p += strlen(p);
1349 }
1350
1351 return repsep_snprintf(bf, size, "%-*s", width, buf);
1352}
1353
1354struct sort_entry sort_transaction = {
1355 .se_header = "Transaction ",
1356 .se_cmp = sort__transaction_cmp,
1357 .se_snprintf = hist_entry__transaction_snprintf,
1358 .se_width_idx = HISTC_TRANSACTION,
1359};
1360
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001361struct sort_dimension {
1362 const char *name;
1363 struct sort_entry *entry;
1364 int taken;
1365};
1366
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001367#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1368
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001369static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001370 DIM(SORT_PID, "pid", sort_thread),
1371 DIM(SORT_COMM, "comm", sort_comm),
1372 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001373 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001374 DIM(SORT_PARENT, "parent", sort_parent),
1375 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001376 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001377 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001378 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001379 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1380 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001381 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001382 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001383};
1384
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001385#undef DIM
1386
1387#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1388
1389static struct sort_dimension bstack_sort_dimensions[] = {
1390 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1391 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1392 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1393 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1394 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001395 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1396 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001397 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001398};
1399
1400#undef DIM
1401
Namhyung Kimafab87b2013-04-03 21:26:11 +09001402#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1403
1404static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001405 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001406 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001407 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1408 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1409 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1410 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1411 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001412 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001413};
1414
1415#undef DIM
1416
Namhyung Kima2ce0672014-03-04 09:06:42 +09001417struct hpp_dimension {
1418 const char *name;
1419 struct perf_hpp_fmt *fmt;
1420 int taken;
1421};
1422
1423#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1424
1425static struct hpp_dimension hpp_sort_dimensions[] = {
1426 DIM(PERF_HPP__OVERHEAD, "overhead"),
1427 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1428 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1429 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1430 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001431 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001432 DIM(PERF_HPP__SAMPLES, "sample"),
1433 DIM(PERF_HPP__PERIOD, "period"),
1434};
1435
1436#undef DIM
1437
Namhyung Kim8b536992014-03-03 11:46:55 +09001438struct hpp_sort_entry {
1439 struct perf_hpp_fmt hpp;
1440 struct sort_entry *se;
1441};
1442
Namhyung Kime0d66c72014-07-31 14:47:37 +09001443void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001444{
1445 struct hpp_sort_entry *hse;
1446
1447 if (!perf_hpp__is_sort_entry(fmt))
1448 return;
1449
1450 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001451 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001452}
1453
Namhyung Kim8b536992014-03-03 11:46:55 +09001454static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1455 struct perf_evsel *evsel)
1456{
1457 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001458 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001459
1460 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001461
Namhyung Kim5b591662014-07-31 14:47:38 +09001462 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001463 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001464
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001465 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001466}
1467
1468static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1469 struct perf_hpp *hpp __maybe_unused,
1470 struct perf_evsel *evsel)
1471{
1472 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001473 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001474
1475 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1476
Namhyung Kim5b591662014-07-31 14:47:38 +09001477 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001478 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001479
1480 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001481}
1482
1483static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1484 struct hist_entry *he)
1485{
1486 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001487 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001488
1489 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001490
1491 if (!len)
1492 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001493
1494 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1495}
1496
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001497static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1498 struct hist_entry *a, struct hist_entry *b)
1499{
1500 struct hpp_sort_entry *hse;
1501
1502 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1503 return hse->se->se_cmp(a, b);
1504}
1505
1506static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1507 struct hist_entry *a, struct hist_entry *b)
1508{
1509 struct hpp_sort_entry *hse;
1510 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1511
1512 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1513 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1514 return collapse_fn(a, b);
1515}
1516
1517static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1518 struct hist_entry *a, struct hist_entry *b)
1519{
1520 struct hpp_sort_entry *hse;
1521 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1522
1523 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1524 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1525 return sort_fn(a, b);
1526}
1527
Jiri Olsa97358082016-01-18 10:24:03 +01001528bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1529{
1530 return format->header == __sort__hpp_header;
1531}
1532
1533static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1534{
1535 struct hpp_sort_entry *hse_a;
1536 struct hpp_sort_entry *hse_b;
1537
1538 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1539 return false;
1540
1541 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1542 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1543
1544 return hse_a->se == hse_b->se;
1545}
1546
Jiri Olsa564132f2016-01-18 10:24:09 +01001547static void hse_free(struct perf_hpp_fmt *fmt)
1548{
1549 struct hpp_sort_entry *hse;
1550
1551 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1552 free(hse);
1553}
1554
Namhyung Kima7d945b2014-03-04 10:46:34 +09001555static struct hpp_sort_entry *
1556__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001557{
1558 struct hpp_sort_entry *hse;
1559
1560 hse = malloc(sizeof(*hse));
1561 if (hse == NULL) {
1562 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001563 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001564 }
1565
1566 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001567 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001568 hse->hpp.header = __sort__hpp_header;
1569 hse->hpp.width = __sort__hpp_width;
1570 hse->hpp.entry = __sort__hpp_entry;
1571 hse->hpp.color = NULL;
1572
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001573 hse->hpp.cmp = __sort__hpp_cmp;
1574 hse->hpp.collapse = __sort__hpp_collapse;
1575 hse->hpp.sort = __sort__hpp_sort;
Jiri Olsa97358082016-01-18 10:24:03 +01001576 hse->hpp.equal = __sort__hpp_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001577 hse->hpp.free = hse_free;
Namhyung Kim8b536992014-03-03 11:46:55 +09001578
1579 INIT_LIST_HEAD(&hse->hpp.list);
1580 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001581 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001582 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001583 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001584
Namhyung Kima7d945b2014-03-04 10:46:34 +09001585 return hse;
1586}
1587
Jiri Olsa564132f2016-01-18 10:24:09 +01001588static void hpp_free(struct perf_hpp_fmt *fmt)
1589{
1590 free(fmt);
1591}
1592
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001593static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
1594{
1595 struct perf_hpp_fmt *fmt;
1596
1597 fmt = memdup(hd->fmt, sizeof(*fmt));
1598 if (fmt) {
1599 INIT_LIST_HEAD(&fmt->list);
1600 INIT_LIST_HEAD(&fmt->sort_list);
Jiri Olsa564132f2016-01-18 10:24:09 +01001601 fmt->free = hpp_free;
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001602 }
1603
1604 return fmt;
1605}
1606
Namhyung Kima7d945b2014-03-04 10:46:34 +09001607static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1608{
1609 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1610
1611 if (hse == NULL)
1612 return -1;
1613
Namhyung Kim8b536992014-03-03 11:46:55 +09001614 perf_hpp__register_sort_field(&hse->hpp);
1615 return 0;
1616}
1617
Jiri Olsa07600022016-01-18 10:24:16 +01001618static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
1619 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001620{
1621 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1622
1623 if (hse == NULL)
1624 return -1;
1625
Jiri Olsa07600022016-01-18 10:24:16 +01001626 perf_hpp_list__column_register(list, &hse->hpp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001627 return 0;
1628}
1629
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001630struct hpp_dynamic_entry {
1631 struct perf_hpp_fmt hpp;
1632 struct perf_evsel *evsel;
1633 struct format_field *field;
1634 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001635 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001636};
1637
1638static int hde_width(struct hpp_dynamic_entry *hde)
1639{
1640 if (!hde->hpp.len) {
1641 int len = hde->dynamic_len;
1642 int namelen = strlen(hde->field->name);
1643 int fieldlen = hde->field->size;
1644
1645 if (namelen > len)
1646 len = namelen;
1647
1648 if (!(hde->field->flags & FIELD_IS_STRING)) {
1649 /* length for print hex numbers */
1650 fieldlen = hde->field->size * 2 + 2;
1651 }
1652 if (fieldlen > len)
1653 len = fieldlen;
1654
1655 hde->hpp.len = len;
1656 }
1657 return hde->hpp.len;
1658}
1659
Namhyung Kim60517d22015-12-23 02:07:03 +09001660static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1661 struct hist_entry *he)
1662{
1663 char *str, *pos;
1664 struct format_field *field = hde->field;
1665 size_t namelen;
1666 bool last = false;
1667
Namhyung Kim053a3982015-12-23 02:07:05 +09001668 if (hde->raw_trace)
1669 return;
1670
Namhyung Kim60517d22015-12-23 02:07:03 +09001671 /* parse pretty print result and update max length */
1672 if (!he->trace_output)
1673 he->trace_output = get_trace_output(he);
1674
1675 namelen = strlen(field->name);
1676 str = he->trace_output;
1677
1678 while (str) {
1679 pos = strchr(str, ' ');
1680 if (pos == NULL) {
1681 last = true;
1682 pos = str + strlen(str);
1683 }
1684
1685 if (!strncmp(str, field->name, namelen)) {
1686 size_t len;
1687
1688 str += namelen + 1;
1689 len = pos - str;
1690
1691 if (len > hde->dynamic_len)
1692 hde->dynamic_len = len;
1693 break;
1694 }
1695
1696 if (last)
1697 str = NULL;
1698 else
1699 str = pos + 1;
1700 }
1701}
1702
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001703static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1704 struct perf_evsel *evsel __maybe_unused)
1705{
1706 struct hpp_dynamic_entry *hde;
1707 size_t len = fmt->user_len;
1708
1709 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1710
1711 if (!len)
1712 len = hde_width(hde);
1713
1714 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1715}
1716
1717static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1718 struct perf_hpp *hpp __maybe_unused,
1719 struct perf_evsel *evsel __maybe_unused)
1720{
1721 struct hpp_dynamic_entry *hde;
1722 size_t len = fmt->user_len;
1723
1724 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1725
1726 if (!len)
1727 len = hde_width(hde);
1728
1729 return len;
1730}
1731
Namhyung Kim361459f2015-12-23 02:07:08 +09001732bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1733{
1734 struct hpp_dynamic_entry *hde;
1735
1736 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1737
1738 return hists_to_evsel(hists) == hde->evsel;
1739}
1740
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001741static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1742 struct hist_entry *he)
1743{
1744 struct hpp_dynamic_entry *hde;
1745 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001746 char *str, *pos;
1747 struct format_field *field;
1748 size_t namelen;
1749 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001750 int ret;
1751
1752 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1753
1754 if (!len)
1755 len = hde_width(hde);
1756
Namhyung Kim053a3982015-12-23 02:07:05 +09001757 if (hde->raw_trace)
1758 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001759
Namhyung Kim053a3982015-12-23 02:07:05 +09001760 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001761 namelen = strlen(field->name);
1762 str = he->trace_output;
1763
1764 while (str) {
1765 pos = strchr(str, ' ');
1766 if (pos == NULL) {
1767 last = true;
1768 pos = str + strlen(str);
1769 }
1770
1771 if (!strncmp(str, field->name, namelen)) {
1772 str += namelen + 1;
1773 str = strndup(str, pos - str);
1774
1775 if (str == NULL)
1776 return scnprintf(hpp->buf, hpp->size,
1777 "%*.*s", len, len, "ERROR");
1778 break;
1779 }
1780
1781 if (last)
1782 str = NULL;
1783 else
1784 str = pos + 1;
1785 }
1786
1787 if (str == NULL) {
1788 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001789raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001790 trace_seq_init(&seq);
1791 pevent_print_field(&seq, he->raw_data, hde->field);
1792 str = seq.buffer;
1793 }
1794
1795 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1796 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001797 return ret;
1798}
1799
1800static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1801 struct hist_entry *a, struct hist_entry *b)
1802{
1803 struct hpp_dynamic_entry *hde;
1804 struct format_field *field;
1805 unsigned offset, size;
1806
1807 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1808
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001809 field = hde->field;
1810 if (field->flags & FIELD_IS_DYNAMIC) {
1811 unsigned long long dyn;
1812
1813 pevent_read_number_field(field, a->raw_data, &dyn);
1814 offset = dyn & 0xffff;
1815 size = (dyn >> 16) & 0xffff;
1816
1817 /* record max width for output */
1818 if (size > hde->dynamic_len)
1819 hde->dynamic_len = size;
1820 } else {
1821 offset = field->offset;
1822 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001823
1824 update_dynamic_len(hde, a);
1825 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001826 }
1827
1828 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1829}
1830
Namhyung Kim361459f2015-12-23 02:07:08 +09001831bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1832{
1833 return fmt->cmp == __sort__hde_cmp;
1834}
1835
Namhyung Kim665aa752016-02-21 23:22:35 +09001836static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1837{
1838 struct hpp_dynamic_entry *hde_a;
1839 struct hpp_dynamic_entry *hde_b;
1840
1841 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1842 return false;
1843
1844 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1845 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1846
1847 return hde_a->field == hde_b->field;
1848}
1849
Jiri Olsa564132f2016-01-18 10:24:09 +01001850static void hde_free(struct perf_hpp_fmt *fmt)
1851{
1852 struct hpp_dynamic_entry *hde;
1853
1854 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1855 free(hde);
1856}
1857
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001858static struct hpp_dynamic_entry *
1859__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1860{
1861 struct hpp_dynamic_entry *hde;
1862
1863 hde = malloc(sizeof(*hde));
1864 if (hde == NULL) {
1865 pr_debug("Memory allocation failed\n");
1866 return NULL;
1867 }
1868
1869 hde->evsel = evsel;
1870 hde->field = field;
1871 hde->dynamic_len = 0;
1872
1873 hde->hpp.name = field->name;
1874 hde->hpp.header = __sort__hde_header;
1875 hde->hpp.width = __sort__hde_width;
1876 hde->hpp.entry = __sort__hde_entry;
1877 hde->hpp.color = NULL;
1878
1879 hde->hpp.cmp = __sort__hde_cmp;
1880 hde->hpp.collapse = __sort__hde_cmp;
1881 hde->hpp.sort = __sort__hde_cmp;
Namhyung Kim665aa752016-02-21 23:22:35 +09001882 hde->hpp.equal = __sort__hde_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001883 hde->hpp.free = hde_free;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001884
1885 INIT_LIST_HEAD(&hde->hpp.list);
1886 INIT_LIST_HEAD(&hde->hpp.sort_list);
1887 hde->hpp.elide = false;
1888 hde->hpp.len = 0;
1889 hde->hpp.user_len = 0;
1890
1891 return hde;
1892}
1893
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001894static int parse_field_name(char *str, char **event, char **field, char **opt)
1895{
1896 char *event_name, *field_name, *opt_name;
1897
1898 event_name = str;
1899 field_name = strchr(str, '.');
1900
1901 if (field_name) {
1902 *field_name++ = '\0';
1903 } else {
1904 event_name = NULL;
1905 field_name = str;
1906 }
1907
1908 opt_name = strchr(field_name, '/');
1909 if (opt_name)
1910 *opt_name++ = '\0';
1911
1912 *event = event_name;
1913 *field = field_name;
1914 *opt = opt_name;
1915
1916 return 0;
1917}
1918
1919/* find match evsel using a given event name. The event name can be:
Namhyung Kim9735be22016-01-05 19:58:35 +09001920 * 1. '%' + event index (e.g. '%1' for first event)
1921 * 2. full event name (e.g. sched:sched_switch)
1922 * 3. partial event name (should not contain ':')
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001923 */
1924static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1925{
1926 struct perf_evsel *evsel = NULL;
1927 struct perf_evsel *pos;
1928 bool full_name;
1929
1930 /* case 1 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001931 if (event_name[0] == '%') {
1932 int nr = strtol(event_name+1, NULL, 0);
1933
1934 if (nr > evlist->nr_entries)
1935 return NULL;
1936
1937 evsel = perf_evlist__first(evlist);
1938 while (--nr > 0)
1939 evsel = perf_evsel__next(evsel);
1940
1941 return evsel;
1942 }
1943
1944 full_name = !!strchr(event_name, ':');
1945 evlist__for_each(evlist, pos) {
Namhyung Kim9735be22016-01-05 19:58:35 +09001946 /* case 2 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001947 if (full_name && !strcmp(pos->name, event_name))
1948 return pos;
Namhyung Kim9735be22016-01-05 19:58:35 +09001949 /* case 3 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001950 if (!full_name && strstr(pos->name, event_name)) {
1951 if (evsel) {
1952 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1953 event_name, evsel->name, pos->name);
1954 return NULL;
1955 }
1956 evsel = pos;
1957 }
1958 }
1959
1960 return evsel;
1961}
1962
Namhyung Kim3b099bf52015-12-23 02:07:07 +09001963static int __dynamic_dimension__add(struct perf_evsel *evsel,
1964 struct format_field *field,
1965 bool raw_trace)
1966{
1967 struct hpp_dynamic_entry *hde;
1968
1969 hde = __alloc_dynamic_entry(evsel, field);
1970 if (hde == NULL)
1971 return -ENOMEM;
1972
1973 hde->raw_trace = raw_trace;
1974
1975 perf_hpp__register_sort_field(&hde->hpp);
1976 return 0;
1977}
1978
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001979static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1980{
1981 int ret;
1982 struct format_field *field;
1983
1984 field = evsel->tp_format->format.fields;
1985 while (field) {
1986 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1987 if (ret < 0)
1988 return ret;
1989
1990 field = field->next;
1991 }
1992 return 0;
1993}
1994
1995static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1996{
1997 int ret;
1998 struct perf_evsel *evsel;
1999
2000 evlist__for_each(evlist, evsel) {
2001 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2002 continue;
2003
2004 ret = add_evsel_fields(evsel, raw_trace);
2005 if (ret < 0)
2006 return ret;
2007 }
2008 return 0;
2009}
2010
Namhyung Kim9735be22016-01-05 19:58:35 +09002011static int add_all_matching_fields(struct perf_evlist *evlist,
2012 char *field_name, bool raw_trace)
2013{
2014 int ret = -ESRCH;
2015 struct perf_evsel *evsel;
2016 struct format_field *field;
2017
2018 evlist__for_each(evlist, evsel) {
2019 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2020 continue;
2021
2022 field = pevent_find_any_field(evsel->tp_format, field_name);
2023 if (field == NULL)
2024 continue;
2025
2026 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2027 if (ret < 0)
2028 break;
2029 }
2030 return ret;
2031}
2032
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002033static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2034{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002035 char *str, *event_name, *field_name, *opt_name;
2036 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002037 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09002038 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002039 int ret = 0;
2040
2041 if (evlist == NULL)
2042 return -ENOENT;
2043
2044 str = strdup(tok);
2045 if (str == NULL)
2046 return -ENOMEM;
2047
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002048 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002049 ret = -EINVAL;
2050 goto out;
2051 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002052
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002053 if (opt_name) {
2054 if (strcmp(opt_name, "raw")) {
2055 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09002056 ret = -EINVAL;
2057 goto out;
2058 }
2059 raw_trace = true;
2060 }
2061
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002062 if (!strcmp(field_name, "trace_fields")) {
2063 ret = add_all_dynamic_fields(evlist, raw_trace);
2064 goto out;
2065 }
2066
Namhyung Kim9735be22016-01-05 19:58:35 +09002067 if (event_name == NULL) {
2068 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2069 goto out;
2070 }
2071
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002072 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002073 if (evsel == NULL) {
2074 pr_debug("Cannot find event: %s\n", event_name);
2075 ret = -ENOENT;
2076 goto out;
2077 }
2078
2079 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2080 pr_debug("%s is not a tracepoint event\n", event_name);
2081 ret = -EINVAL;
2082 goto out;
2083 }
2084
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002085 if (!strcmp(field_name, "*")) {
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002086 ret = add_evsel_fields(evsel, raw_trace);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002087 } else {
2088 field = pevent_find_any_field(evsel->tp_format, field_name);
2089 if (field == NULL) {
2090 pr_debug("Cannot find event field for %s.%s\n",
2091 event_name, field_name);
2092 return -ENOENT;
2093 }
2094
2095 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2096 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002097
2098out:
2099 free(str);
2100 return ret;
2101}
2102
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002103static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002104{
2105 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002106 return 0;
2107
Namhyung Kima7d945b2014-03-04 10:46:34 +09002108 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002109 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002110
2111 if (sd->entry->se_collapse)
2112 sort__need_collapse = 1;
2113
Namhyung Kim2f532d092013-04-03 21:26:10 +09002114 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002115
2116 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002117}
2118
Namhyung Kima2ce0672014-03-04 09:06:42 +09002119static int __hpp_dimension__add(struct hpp_dimension *hd)
2120{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002121 struct perf_hpp_fmt *fmt;
Namhyung Kima2ce0672014-03-04 09:06:42 +09002122
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002123 if (hd->taken)
2124 return 0;
2125
2126 fmt = __hpp_dimension__alloc_hpp(hd);
2127 if (!fmt)
2128 return -1;
2129
2130 hd->taken = 1;
2131 perf_hpp__register_sort_field(fmt);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002132 return 0;
2133}
2134
Jiri Olsa07600022016-01-18 10:24:16 +01002135static int __sort_dimension__add_output(struct perf_hpp_list *list,
2136 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002137{
2138 if (sd->taken)
2139 return 0;
2140
Jiri Olsa07600022016-01-18 10:24:16 +01002141 if (__sort_dimension__add_hpp_output(list, sd) < 0)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002142 return -1;
2143
2144 sd->taken = 1;
2145 return 0;
2146}
2147
Jiri Olsa07600022016-01-18 10:24:16 +01002148static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2149 struct hpp_dimension *hd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002150{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002151 struct perf_hpp_fmt *fmt;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002152
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002153 if (hd->taken)
2154 return 0;
2155
2156 fmt = __hpp_dimension__alloc_hpp(hd);
2157 if (!fmt)
2158 return -1;
2159
2160 hd->taken = 1;
Jiri Olsa07600022016-01-18 10:24:16 +01002161 perf_hpp_list__column_register(list, fmt);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002162 return 0;
2163}
2164
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002165int hpp_dimension__add_output(unsigned col)
2166{
2167 BUG_ON(col >= PERF_HPP__MAX_INDEX);
Jiri Olsa07600022016-01-18 10:24:16 +01002168 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002169}
2170
Namhyung Kim40184c42015-12-23 02:07:01 +09002171static int sort_dimension__add(const char *tok,
2172 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02002173{
2174 unsigned int i;
2175
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002176 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2177 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002178
John Kacurdd68ada2009-09-24 18:02:49 +02002179 if (strncasecmp(tok, sd->name, strlen(tok)))
2180 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002181
John Kacurdd68ada2009-09-24 18:02:49 +02002182 if (sd->entry == &sort_parent) {
2183 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2184 if (ret) {
2185 char err[BUFSIZ];
2186
2187 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002188 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2189 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002190 }
2191 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002192 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09002193 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002194 /*
2195 * perf diff displays the performance difference amongst
2196 * two or more perf.data files. Those files could come
2197 * from different binaries. So we should not compare
2198 * their ips, but the name of symbol.
2199 */
2200 if (sort__mode == SORT_MODE__DIFF)
2201 sd->entry->se_collapse = sort__sym_sort;
2202
Namhyung Kim68f6d022013-12-18 14:21:10 +09002203 } else if (sd->entry == &sort_dso) {
2204 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002205 } else if (sd->entry == &sort_socket) {
2206 sort__has_socket = 1;
Namhyung Kimcfd92da2016-01-21 19:13:24 -03002207 } else if (sd->entry == &sort_thread) {
2208 sort__has_thread = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002209 }
2210
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002211 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02002212 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002213
Namhyung Kima2ce0672014-03-04 09:06:42 +09002214 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2215 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2216
2217 if (strncasecmp(tok, hd->name, strlen(tok)))
2218 continue;
2219
2220 return __hpp_dimension__add(hd);
2221 }
2222
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002223 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2224 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2225
2226 if (strncasecmp(tok, sd->name, strlen(tok)))
2227 continue;
2228
Namhyung Kim55369fc2013-04-01 20:35:20 +09002229 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002230 return -EINVAL;
2231
2232 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2233 sort__has_sym = 1;
2234
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002235 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002236 return 0;
2237 }
2238
Namhyung Kimafab87b2013-04-03 21:26:11 +09002239 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2240 struct sort_dimension *sd = &memory_sort_dimensions[i];
2241
2242 if (strncasecmp(tok, sd->name, strlen(tok)))
2243 continue;
2244
2245 if (sort__mode != SORT_MODE__MEMORY)
2246 return -EINVAL;
2247
2248 if (sd->entry == &sort_mem_daddr_sym)
2249 sort__has_sym = 1;
2250
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002251 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002252 return 0;
2253 }
2254
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002255 if (!add_dynamic_entry(evlist, tok))
2256 return 0;
2257
John Kacurdd68ada2009-09-24 18:02:49 +02002258 return -ESRCH;
2259}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002260
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002261static int setup_sort_list(char *str, struct perf_evlist *evlist)
2262{
2263 char *tmp, *tok;
2264 int ret = 0;
2265
2266 for (tok = strtok_r(str, ", ", &tmp);
2267 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2268 ret = sort_dimension__add(tok, evlist);
2269 if (ret == -EINVAL) {
2270 error("Invalid --sort key: `%s'", tok);
2271 break;
2272 } else if (ret == -ESRCH) {
2273 error("Unknown --sort key: `%s'", tok);
2274 break;
2275 }
2276 }
2277
2278 return ret;
2279}
2280
Namhyung Kimd49dade2015-12-23 02:07:10 +09002281static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002282{
2283 const char *default_sort_orders[] = {
2284 default_sort_order,
2285 default_branch_sort_order,
2286 default_mem_sort_order,
2287 default_top_sort_order,
2288 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002289 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002290 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002291 bool use_trace = true;
2292 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002293
2294 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2295
Namhyung Kimd49dade2015-12-23 02:07:10 +09002296 if (evlist == NULL)
2297 goto out_no_evlist;
2298
2299 evlist__for_each(evlist, evsel) {
2300 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2301 use_trace = false;
2302 break;
2303 }
2304 }
2305
2306 if (use_trace) {
2307 sort__mode = SORT_MODE__TRACEPOINT;
2308 if (symbol_conf.raw_trace)
2309 return "trace_fields";
2310 }
2311out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002312 return default_sort_orders[sort__mode];
2313}
2314
Namhyung Kimd49dade2015-12-23 02:07:10 +09002315static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002316{
2317 char *new_sort_order;
2318
2319 /*
2320 * Append '+'-prefixed sort order to the default sort
2321 * order string.
2322 */
2323 if (!sort_order || is_strict_order(sort_order))
2324 return 0;
2325
2326 if (sort_order[1] == '\0') {
2327 error("Invalid --sort key: `+'");
2328 return -EINVAL;
2329 }
2330
2331 /*
2332 * We allocate new sort_order string, but we never free it,
2333 * because it's checked over the rest of the code.
2334 */
2335 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002336 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002337 error("Not enough memory to set up --sort");
2338 return -ENOMEM;
2339 }
2340
2341 sort_order = new_sort_order;
2342 return 0;
2343}
2344
Jiri Olsab97511c2016-01-07 10:14:08 +01002345/*
2346 * Adds 'pre,' prefix into 'str' is 'pre' is
2347 * not already part of 'str'.
2348 */
2349static char *prefix_if_not_in(const char *pre, char *str)
2350{
2351 char *n;
2352
2353 if (!str || strstr(str, pre))
2354 return str;
2355
2356 if (asprintf(&n, "%s,%s", pre, str) < 0)
2357 return NULL;
2358
2359 free(str);
2360 return n;
2361}
2362
2363static char *setup_overhead(char *keys)
2364{
2365 keys = prefix_if_not_in("overhead", keys);
2366
2367 if (symbol_conf.cumulate_callchain)
2368 keys = prefix_if_not_in("overhead_children", keys);
2369
2370 return keys;
2371}
2372
Namhyung Kim40184c42015-12-23 02:07:01 +09002373static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002374{
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002375 char *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002376 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002377 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002378
Namhyung Kimd49dade2015-12-23 02:07:10 +09002379 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002380 if (ret)
2381 return ret;
2382
2383 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002384 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002385 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002386 /*
2387 * If user specified field order but no sort order,
2388 * we'll honor it and not add default sort orders.
2389 */
2390 return 0;
2391 }
2392
Namhyung Kimd49dade2015-12-23 02:07:10 +09002393 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002394 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002395
2396 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002397 if (str == NULL) {
2398 error("Not enough memory to setup sort keys");
2399 return -ENOMEM;
2400 }
2401
Jiri Olsab97511c2016-01-07 10:14:08 +01002402 /*
2403 * Prepend overhead fields for backward compatibility.
2404 */
2405 if (!is_strict_order(field_order)) {
2406 str = setup_overhead(str);
2407 if (str == NULL) {
2408 error("Not enough memory to setup overhead keys");
2409 return -ENOMEM;
2410 }
2411 }
2412
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002413 ret = setup_sort_list(str, evlist);
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002414
2415 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002416 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002417}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002418
Jiri Olsaf2998422014-05-23 17:15:47 +02002419void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002420{
Jiri Olsaf2998422014-05-23 17:15:47 +02002421 struct perf_hpp_fmt *fmt;
2422 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002423
Jiri Olsacf094042016-01-18 10:24:17 +01002424 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002425 if (!perf_hpp__is_sort_entry(fmt))
2426 continue;
2427
2428 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2429 if (hse->se->se_width_idx == idx) {
2430 fmt->elide = elide;
2431 break;
2432 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002433 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002434}
2435
Jiri Olsaf2998422014-05-23 17:15:47 +02002436static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002437{
2438 if (list && strlist__nr_entries(list) == 1) {
2439 if (fp != NULL)
2440 fprintf(fp, "# %s: %s\n", list_name,
2441 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002442 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002443 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002444 return false;
2445}
2446
2447static bool get_elide(int idx, FILE *output)
2448{
2449 switch (idx) {
2450 case HISTC_SYMBOL:
2451 return __get_elide(symbol_conf.sym_list, "symbol", output);
2452 case HISTC_DSO:
2453 return __get_elide(symbol_conf.dso_list, "dso", output);
2454 case HISTC_COMM:
2455 return __get_elide(symbol_conf.comm_list, "comm", output);
2456 default:
2457 break;
2458 }
2459
2460 if (sort__mode != SORT_MODE__BRANCH)
2461 return false;
2462
2463 switch (idx) {
2464 case HISTC_SYMBOL_FROM:
2465 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2466 case HISTC_SYMBOL_TO:
2467 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2468 case HISTC_DSO_FROM:
2469 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2470 case HISTC_DSO_TO:
2471 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2472 default:
2473 break;
2474 }
2475
2476 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002477}
Namhyung Kim08e71542013-04-03 21:26:19 +09002478
2479void sort__setup_elide(FILE *output)
2480{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002481 struct perf_hpp_fmt *fmt;
2482 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002483
Jiri Olsacf094042016-01-18 10:24:17 +01002484 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002485 if (!perf_hpp__is_sort_entry(fmt))
2486 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002487
Jiri Olsaf2998422014-05-23 17:15:47 +02002488 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2489 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002490 }
2491
Namhyung Kim7524f632013-11-08 17:53:42 +09002492 /*
2493 * It makes no sense to elide all of sort entries.
2494 * Just revert them to show up again.
2495 */
Jiri Olsacf094042016-01-18 10:24:17 +01002496 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002497 if (!perf_hpp__is_sort_entry(fmt))
2498 continue;
2499
Jiri Olsaf2998422014-05-23 17:15:47 +02002500 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002501 return;
2502 }
2503
Jiri Olsacf094042016-01-18 10:24:17 +01002504 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002505 if (!perf_hpp__is_sort_entry(fmt))
2506 continue;
2507
Jiri Olsaf2998422014-05-23 17:15:47 +02002508 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002509 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002510}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002511
Jiri Olsa07600022016-01-18 10:24:16 +01002512static int output_field_add(struct perf_hpp_list *list, char *tok)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002513{
2514 unsigned int i;
2515
2516 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2517 struct sort_dimension *sd = &common_sort_dimensions[i];
2518
2519 if (strncasecmp(tok, sd->name, strlen(tok)))
2520 continue;
2521
Jiri Olsa07600022016-01-18 10:24:16 +01002522 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002523 }
2524
2525 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2526 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2527
2528 if (strncasecmp(tok, hd->name, strlen(tok)))
2529 continue;
2530
Jiri Olsa07600022016-01-18 10:24:16 +01002531 return __hpp_dimension__add_output(list, hd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002532 }
2533
2534 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2535 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2536
2537 if (strncasecmp(tok, sd->name, strlen(tok)))
2538 continue;
2539
Jiri Olsa07600022016-01-18 10:24:16 +01002540 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002541 }
2542
2543 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2544 struct sort_dimension *sd = &memory_sort_dimensions[i];
2545
2546 if (strncasecmp(tok, sd->name, strlen(tok)))
2547 continue;
2548
Jiri Olsa07600022016-01-18 10:24:16 +01002549 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002550 }
2551
2552 return -ESRCH;
2553}
2554
Jiri Olsa07600022016-01-18 10:24:16 +01002555static int setup_output_list(struct perf_hpp_list *list, char *str)
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002556{
2557 char *tmp, *tok;
2558 int ret = 0;
2559
2560 for (tok = strtok_r(str, ", ", &tmp);
2561 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Jiri Olsa07600022016-01-18 10:24:16 +01002562 ret = output_field_add(list, tok);
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002563 if (ret == -EINVAL) {
2564 error("Invalid --fields key: `%s'", tok);
2565 break;
2566 } else if (ret == -ESRCH) {
2567 error("Unknown --fields key: `%s'", tok);
2568 break;
2569 }
2570 }
2571
2572 return ret;
2573}
2574
Namhyung Kima7d945b2014-03-04 10:46:34 +09002575static void reset_dimensions(void)
2576{
2577 unsigned int i;
2578
2579 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2580 common_sort_dimensions[i].taken = 0;
2581
2582 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2583 hpp_sort_dimensions[i].taken = 0;
2584
2585 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2586 bstack_sort_dimensions[i].taken = 0;
2587
2588 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2589 memory_sort_dimensions[i].taken = 0;
2590}
2591
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002592bool is_strict_order(const char *order)
2593{
2594 return order && (*order != '+');
2595}
2596
Namhyung Kima7d945b2014-03-04 10:46:34 +09002597static int __setup_output_field(void)
2598{
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002599 char *str, *strp;
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002600 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002601
2602 if (field_order == NULL)
2603 return 0;
2604
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002605 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002606 if (str == NULL) {
2607 error("Not enough memory to setup output fields");
2608 return -ENOMEM;
2609 }
2610
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002611 if (!is_strict_order(field_order))
2612 strp++;
2613
2614 if (!strlen(strp)) {
2615 error("Invalid --fields key: `+'");
2616 goto out;
2617 }
2618
Jiri Olsa07600022016-01-18 10:24:16 +01002619 ret = setup_output_list(&perf_hpp_list, strp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002620
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002621out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002622 free(str);
2623 return ret;
2624}
2625
Namhyung Kim40184c42015-12-23 02:07:01 +09002626int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002627{
2628 int err;
2629
Namhyung Kim40184c42015-12-23 02:07:01 +09002630 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002631 if (err < 0)
2632 return err;
2633
2634 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002635 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002636 if (err < 0)
2637 return err;
2638 }
2639
2640 reset_dimensions();
2641
2642 /*
2643 * perf diff doesn't use default hpp output fields.
2644 */
2645 if (sort__mode != SORT_MODE__DIFF)
2646 perf_hpp__init();
2647
2648 err = __setup_output_field();
2649 if (err < 0)
2650 return err;
2651
2652 /* copy sort keys to output fields */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002653 perf_hpp__setup_output_field(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002654 /* and then copy output fields to sort keys */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002655 perf_hpp__append_sort_keys(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002656
2657 return 0;
2658}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002659
2660void reset_output_field(void)
2661{
2662 sort__need_collapse = 0;
2663 sort__has_parent = 0;
2664 sort__has_sym = 0;
2665 sort__has_dso = 0;
2666
Namhyung Kimd69b2962014-05-23 10:59:01 +09002667 field_order = NULL;
2668 sort_order = NULL;
2669
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002670 reset_dimensions();
Jiri Olsa43e0a682016-01-18 10:24:21 +01002671 perf_hpp__reset_output_field(&perf_hpp_list);
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002672}