blob: 5f94ee740c5b928772b221f2973954208aff41ec [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
Namhyung Kim2960ed62016-02-22 09:32:33 +0900317 return repsep_snprintf(bf, size, "%-.*s", 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
Namhyung Kim2960ed62016-02-22 09:32:33 +0900369 return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
Andi Kleen31191a82015-08-07 15:54:24 -0700370}
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
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900486 return strcmp(right->trace_output, left->trace_output);
487}
488
489static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
490 size_t size, unsigned int width)
491{
492 struct perf_evsel *evsel;
493
494 evsel = hists_to_evsel(he->hists);
495 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
Namhyung Kim2960ed62016-02-22 09:32:33 +0900496 return scnprintf(bf, size, "%-.*s", width, "N/A");
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900497
498 if (he->trace_output == NULL)
499 he->trace_output = get_trace_output(he);
Namhyung Kim2960ed62016-02-22 09:32:33 +0900500 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900501}
502
503struct sort_entry sort_trace = {
504 .se_header = "Trace output",
505 .se_cmp = sort__trace_cmp,
506 .se_snprintf = hist_entry__trace_snprintf,
507 .se_width_idx = HISTC_TRACE,
508};
509
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900510/* sort keys for branch stacks */
511
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100512static int64_t
513sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
514{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200515 if (!left->branch_info || !right->branch_info)
516 return cmp_null(left->branch_info, right->branch_info);
517
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100518 return _sort__dso_cmp(left->branch_info->from.map,
519 right->branch_info->from.map);
520}
521
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300522static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100523 size_t size, unsigned int width)
524{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200525 if (he->branch_info)
526 return _hist_entry__dso_snprintf(he->branch_info->from.map,
527 bf, size, width);
528 else
529 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100530}
531
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100532static int64_t
533sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
534{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200535 if (!left->branch_info || !right->branch_info)
536 return cmp_null(left->branch_info, right->branch_info);
537
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100538 return _sort__dso_cmp(left->branch_info->to.map,
539 right->branch_info->to.map);
540}
541
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300542static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100543 size_t size, unsigned int width)
544{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200545 if (he->branch_info)
546 return _hist_entry__dso_snprintf(he->branch_info->to.map,
547 bf, size, width);
548 else
549 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100550}
551
552static int64_t
553sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
554{
555 struct addr_map_symbol *from_l = &left->branch_info->from;
556 struct addr_map_symbol *from_r = &right->branch_info->from;
557
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200558 if (!left->branch_info || !right->branch_info)
559 return cmp_null(left->branch_info, right->branch_info);
560
561 from_l = &left->branch_info->from;
562 from_r = &right->branch_info->from;
563
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100564 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900565 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100566
Namhyung Kim51f27d12013-02-06 14:57:15 +0900567 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100568}
569
570static int64_t
571sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
572{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200573 struct addr_map_symbol *to_l, *to_r;
574
575 if (!left->branch_info || !right->branch_info)
576 return cmp_null(left->branch_info, right->branch_info);
577
578 to_l = &left->branch_info->to;
579 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100580
581 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900582 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100583
Namhyung Kim51f27d12013-02-06 14:57:15 +0900584 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100585}
586
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300587static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900588 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100589{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200590 if (he->branch_info) {
591 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100592
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200593 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
594 he->level, bf, size, width);
595 }
596
597 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100598}
599
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300600static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900601 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100602{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200603 if (he->branch_info) {
604 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100605
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200606 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
607 he->level, bf, size, width);
608 }
609
610 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100611}
612
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900613struct sort_entry sort_dso_from = {
614 .se_header = "Source Shared Object",
615 .se_cmp = sort__dso_from_cmp,
616 .se_snprintf = hist_entry__dso_from_snprintf,
617 .se_width_idx = HISTC_DSO_FROM,
618};
619
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100620struct sort_entry sort_dso_to = {
621 .se_header = "Target Shared Object",
622 .se_cmp = sort__dso_to_cmp,
623 .se_snprintf = hist_entry__dso_to_snprintf,
624 .se_width_idx = HISTC_DSO_TO,
625};
626
627struct sort_entry sort_sym_from = {
628 .se_header = "Source Symbol",
629 .se_cmp = sort__sym_from_cmp,
630 .se_snprintf = hist_entry__sym_from_snprintf,
631 .se_width_idx = HISTC_SYMBOL_FROM,
632};
633
634struct sort_entry sort_sym_to = {
635 .se_header = "Target Symbol",
636 .se_cmp = sort__sym_to_cmp,
637 .se_snprintf = hist_entry__sym_to_snprintf,
638 .se_width_idx = HISTC_SYMBOL_TO,
639};
640
641static int64_t
642sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
643{
Jiri Olsa428560e2014-10-16 16:07:03 +0200644 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100645
Jiri Olsa428560e2014-10-16 16:07:03 +0200646 if (!left->branch_info || !right->branch_info)
647 return cmp_null(left->branch_info, right->branch_info);
648
649 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
650 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100651 return mp || p;
652}
653
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300654static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100655 size_t size, unsigned int width){
656 static const char *out = "N/A";
657
Jiri Olsa428560e2014-10-16 16:07:03 +0200658 if (he->branch_info) {
659 if (he->branch_info->flags.predicted)
660 out = "N";
661 else if (he->branch_info->flags.mispred)
662 out = "Y";
663 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100664
Namhyung Kim5b591662014-07-31 14:47:38 +0900665 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100666}
667
Andi Kleen0e332f02015-07-18 08:24:46 -0700668static int64_t
669sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
670{
671 return left->branch_info->flags.cycles -
672 right->branch_info->flags.cycles;
673}
674
675static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
676 size_t size, unsigned int width)
677{
678 if (he->branch_info->flags.cycles == 0)
679 return repsep_snprintf(bf, size, "%-*s", width, "-");
680 return repsep_snprintf(bf, size, "%-*hd", width,
681 he->branch_info->flags.cycles);
682}
683
684struct sort_entry sort_cycles = {
685 .se_header = "Basic Block Cycles",
686 .se_cmp = sort__cycles_cmp,
687 .se_snprintf = hist_entry__cycles_snprintf,
688 .se_width_idx = HISTC_CYCLES,
689};
690
Stephane Eranian98a3b322013-01-24 16:10:35 +0100691/* --sort daddr_sym */
692static int64_t
693sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
694{
695 uint64_t l = 0, r = 0;
696
697 if (left->mem_info)
698 l = left->mem_info->daddr.addr;
699 if (right->mem_info)
700 r = right->mem_info->daddr.addr;
701
702 return (int64_t)(r - l);
703}
704
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300705static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100706 size_t size, unsigned int width)
707{
708 uint64_t addr = 0;
709 struct map *map = NULL;
710 struct symbol *sym = NULL;
711
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300712 if (he->mem_info) {
713 addr = he->mem_info->daddr.addr;
714 map = he->mem_info->daddr.map;
715 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100716 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300717 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100718 width);
719}
720
721static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200722sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
723{
724 uint64_t l = 0, r = 0;
725
726 if (left->mem_info)
727 l = left->mem_info->iaddr.addr;
728 if (right->mem_info)
729 r = right->mem_info->iaddr.addr;
730
731 return (int64_t)(r - l);
732}
733
734static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
735 size_t size, unsigned int width)
736{
737 uint64_t addr = 0;
738 struct map *map = NULL;
739 struct symbol *sym = NULL;
740
741 if (he->mem_info) {
742 addr = he->mem_info->iaddr.addr;
743 map = he->mem_info->iaddr.map;
744 sym = he->mem_info->iaddr.sym;
745 }
746 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
747 width);
748}
749
750static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100751sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
752{
753 struct map *map_l = NULL;
754 struct map *map_r = NULL;
755
756 if (left->mem_info)
757 map_l = left->mem_info->daddr.map;
758 if (right->mem_info)
759 map_r = right->mem_info->daddr.map;
760
761 return _sort__dso_cmp(map_l, map_r);
762}
763
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300764static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100765 size_t size, unsigned int width)
766{
767 struct map *map = NULL;
768
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300769 if (he->mem_info)
770 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100771
772 return _hist_entry__dso_snprintf(map, bf, size, width);
773}
774
775static int64_t
776sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
777{
778 union perf_mem_data_src data_src_l;
779 union perf_mem_data_src data_src_r;
780
781 if (left->mem_info)
782 data_src_l = left->mem_info->data_src;
783 else
784 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
785
786 if (right->mem_info)
787 data_src_r = right->mem_info->data_src;
788 else
789 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
790
791 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
792}
793
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300794static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100795 size_t size, unsigned int width)
796{
797 const char *out;
798 u64 mask = PERF_MEM_LOCK_NA;
799
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300800 if (he->mem_info)
801 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100802
803 if (mask & PERF_MEM_LOCK_NA)
804 out = "N/A";
805 else if (mask & PERF_MEM_LOCK_LOCKED)
806 out = "Yes";
807 else
808 out = "No";
809
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300810 return repsep_snprintf(bf, size, "%.*s", width, out);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100811}
812
813static int64_t
814sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
815{
816 union perf_mem_data_src data_src_l;
817 union perf_mem_data_src data_src_r;
818
819 if (left->mem_info)
820 data_src_l = left->mem_info->data_src;
821 else
822 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
823
824 if (right->mem_info)
825 data_src_r = right->mem_info->data_src;
826 else
827 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
828
829 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
830}
831
832static const char * const tlb_access[] = {
833 "N/A",
834 "HIT",
835 "MISS",
836 "L1",
837 "L2",
838 "Walker",
839 "Fault",
840};
841#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
842
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300843static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100844 size_t size, unsigned int width)
845{
846 char out[64];
847 size_t sz = sizeof(out) - 1; /* -1 for null termination */
848 size_t l = 0, i;
849 u64 m = PERF_MEM_TLB_NA;
850 u64 hit, miss;
851
852 out[0] = '\0';
853
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300854 if (he->mem_info)
855 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100856
857 hit = m & PERF_MEM_TLB_HIT;
858 miss = m & PERF_MEM_TLB_MISS;
859
860 /* already taken care of */
861 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
862
863 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
864 if (!(m & 0x1))
865 continue;
866 if (l) {
867 strcat(out, " or ");
868 l += 4;
869 }
870 strncat(out, tlb_access[i], sz - l);
871 l += strlen(tlb_access[i]);
872 }
873 if (*out == '\0')
874 strcpy(out, "N/A");
875 if (hit)
876 strncat(out, " hit", sz - l);
877 if (miss)
878 strncat(out, " miss", sz - l);
879
880 return repsep_snprintf(bf, size, "%-*s", width, out);
881}
882
883static int64_t
884sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
885{
886 union perf_mem_data_src data_src_l;
887 union perf_mem_data_src data_src_r;
888
889 if (left->mem_info)
890 data_src_l = left->mem_info->data_src;
891 else
892 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
893
894 if (right->mem_info)
895 data_src_r = right->mem_info->data_src;
896 else
897 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
898
899 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
900}
901
902static const char * const mem_lvl[] = {
903 "N/A",
904 "HIT",
905 "MISS",
906 "L1",
907 "LFB",
908 "L2",
909 "L3",
910 "Local RAM",
911 "Remote RAM (1 hop)",
912 "Remote RAM (2 hops)",
913 "Remote Cache (1 hop)",
914 "Remote Cache (2 hops)",
915 "I/O",
916 "Uncached",
917};
918#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
919
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300920static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100921 size_t size, unsigned int width)
922{
923 char out[64];
924 size_t sz = sizeof(out) - 1; /* -1 for null termination */
925 size_t i, l = 0;
926 u64 m = PERF_MEM_LVL_NA;
927 u64 hit, miss;
928
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300929 if (he->mem_info)
930 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100931
932 out[0] = '\0';
933
934 hit = m & PERF_MEM_LVL_HIT;
935 miss = m & PERF_MEM_LVL_MISS;
936
937 /* already taken care of */
938 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
939
940 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
941 if (!(m & 0x1))
942 continue;
943 if (l) {
944 strcat(out, " or ");
945 l += 4;
946 }
947 strncat(out, mem_lvl[i], sz - l);
948 l += strlen(mem_lvl[i]);
949 }
950 if (*out == '\0')
951 strcpy(out, "N/A");
952 if (hit)
953 strncat(out, " hit", sz - l);
954 if (miss)
955 strncat(out, " miss", sz - l);
956
957 return repsep_snprintf(bf, size, "%-*s", width, out);
958}
959
960static int64_t
961sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
962{
963 union perf_mem_data_src data_src_l;
964 union perf_mem_data_src data_src_r;
965
966 if (left->mem_info)
967 data_src_l = left->mem_info->data_src;
968 else
969 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
970
971 if (right->mem_info)
972 data_src_r = right->mem_info->data_src;
973 else
974 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
975
976 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
977}
978
979static const char * const snoop_access[] = {
980 "N/A",
981 "None",
982 "Miss",
983 "Hit",
984 "HitM",
985};
986#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
987
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300988static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100989 size_t size, unsigned int width)
990{
991 char out[64];
992 size_t sz = sizeof(out) - 1; /* -1 for null termination */
993 size_t i, l = 0;
994 u64 m = PERF_MEM_SNOOP_NA;
995
996 out[0] = '\0';
997
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300998 if (he->mem_info)
999 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +01001000
1001 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1002 if (!(m & 0x1))
1003 continue;
1004 if (l) {
1005 strcat(out, " or ");
1006 l += 4;
1007 }
1008 strncat(out, snoop_access[i], sz - l);
1009 l += strlen(snoop_access[i]);
1010 }
1011
1012 if (*out == '\0')
1013 strcpy(out, "N/A");
1014
1015 return repsep_snprintf(bf, size, "%-*s", width, out);
1016}
1017
Don Zickus9b32ba72014-06-01 15:38:29 +02001018static int64_t
1019sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1020{
1021 u64 l, r;
1022 struct map *l_map, *r_map;
1023
1024 if (!left->mem_info) return -1;
1025 if (!right->mem_info) return 1;
1026
1027 /* group event types together */
1028 if (left->cpumode > right->cpumode) return -1;
1029 if (left->cpumode < right->cpumode) return 1;
1030
1031 l_map = left->mem_info->daddr.map;
1032 r_map = right->mem_info->daddr.map;
1033
1034 /* if both are NULL, jump to sort on al_addr instead */
1035 if (!l_map && !r_map)
1036 goto addr;
1037
1038 if (!l_map) return -1;
1039 if (!r_map) return 1;
1040
1041 if (l_map->maj > r_map->maj) return -1;
1042 if (l_map->maj < r_map->maj) return 1;
1043
1044 if (l_map->min > r_map->min) return -1;
1045 if (l_map->min < r_map->min) return 1;
1046
1047 if (l_map->ino > r_map->ino) return -1;
1048 if (l_map->ino < r_map->ino) return 1;
1049
1050 if (l_map->ino_generation > r_map->ino_generation) return -1;
1051 if (l_map->ino_generation < r_map->ino_generation) return 1;
1052
1053 /*
1054 * Addresses with no major/minor numbers are assumed to be
1055 * anonymous in userspace. Sort those on pid then address.
1056 *
1057 * The kernel and non-zero major/minor mapped areas are
1058 * assumed to be unity mapped. Sort those on address.
1059 */
1060
1061 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1062 (!(l_map->flags & MAP_SHARED)) &&
1063 !l_map->maj && !l_map->min && !l_map->ino &&
1064 !l_map->ino_generation) {
1065 /* userspace anonymous */
1066
1067 if (left->thread->pid_ > right->thread->pid_) return -1;
1068 if (left->thread->pid_ < right->thread->pid_) return 1;
1069 }
1070
1071addr:
1072 /* al_addr does all the right addr - start + offset calculations */
1073 l = cl_address(left->mem_info->daddr.al_addr);
1074 r = cl_address(right->mem_info->daddr.al_addr);
1075
1076 if (l > r) return -1;
1077 if (l < r) return 1;
1078
1079 return 0;
1080}
1081
1082static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1083 size_t size, unsigned int width)
1084{
1085
1086 uint64_t addr = 0;
1087 struct map *map = NULL;
1088 struct symbol *sym = NULL;
1089 char level = he->level;
1090
1091 if (he->mem_info) {
1092 addr = cl_address(he->mem_info->daddr.al_addr);
1093 map = he->mem_info->daddr.map;
1094 sym = he->mem_info->daddr.sym;
1095
1096 /* print [s] for shared data mmaps */
1097 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1098 map && (map->type == MAP__VARIABLE) &&
1099 (map->flags & MAP_SHARED) &&
1100 (map->maj || map->min || map->ino ||
1101 map->ino_generation))
1102 level = 's';
1103 else if (!map)
1104 level = 'X';
1105 }
1106 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1107 width);
1108}
1109
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001110struct sort_entry sort_mispredict = {
1111 .se_header = "Branch Mispredicted",
1112 .se_cmp = sort__mispredict_cmp,
1113 .se_snprintf = hist_entry__mispredict_snprintf,
1114 .se_width_idx = HISTC_MISPREDICT,
1115};
1116
Andi Kleen05484292013-01-24 16:10:29 +01001117static u64 he_weight(struct hist_entry *he)
1118{
1119 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1120}
1121
1122static int64_t
1123sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1124{
1125 return he_weight(left) - he_weight(right);
1126}
1127
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001128static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001129 size_t size, unsigned int width)
1130{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001131 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001132}
1133
1134struct sort_entry sort_local_weight = {
1135 .se_header = "Local Weight",
1136 .se_cmp = sort__local_weight_cmp,
1137 .se_snprintf = hist_entry__local_weight_snprintf,
1138 .se_width_idx = HISTC_LOCAL_WEIGHT,
1139};
1140
1141static int64_t
1142sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1143{
1144 return left->stat.weight - right->stat.weight;
1145}
1146
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001147static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001148 size_t size, unsigned int width)
1149{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001150 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001151}
1152
1153struct sort_entry sort_global_weight = {
1154 .se_header = "Weight",
1155 .se_cmp = sort__global_weight_cmp,
1156 .se_snprintf = hist_entry__global_weight_snprintf,
1157 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1158};
1159
Stephane Eranian98a3b322013-01-24 16:10:35 +01001160struct sort_entry sort_mem_daddr_sym = {
1161 .se_header = "Data Symbol",
1162 .se_cmp = sort__daddr_cmp,
1163 .se_snprintf = hist_entry__daddr_snprintf,
1164 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1165};
1166
Don Zickus28e6db22015-10-05 20:06:07 +02001167struct sort_entry sort_mem_iaddr_sym = {
1168 .se_header = "Code Symbol",
1169 .se_cmp = sort__iaddr_cmp,
1170 .se_snprintf = hist_entry__iaddr_snprintf,
1171 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1172};
1173
Stephane Eranian98a3b322013-01-24 16:10:35 +01001174struct sort_entry sort_mem_daddr_dso = {
1175 .se_header = "Data Object",
1176 .se_cmp = sort__dso_daddr_cmp,
1177 .se_snprintf = hist_entry__dso_daddr_snprintf,
1178 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1179};
1180
1181struct sort_entry sort_mem_locked = {
1182 .se_header = "Locked",
1183 .se_cmp = sort__locked_cmp,
1184 .se_snprintf = hist_entry__locked_snprintf,
1185 .se_width_idx = HISTC_MEM_LOCKED,
1186};
1187
1188struct sort_entry sort_mem_tlb = {
1189 .se_header = "TLB access",
1190 .se_cmp = sort__tlb_cmp,
1191 .se_snprintf = hist_entry__tlb_snprintf,
1192 .se_width_idx = HISTC_MEM_TLB,
1193};
1194
1195struct sort_entry sort_mem_lvl = {
1196 .se_header = "Memory access",
1197 .se_cmp = sort__lvl_cmp,
1198 .se_snprintf = hist_entry__lvl_snprintf,
1199 .se_width_idx = HISTC_MEM_LVL,
1200};
1201
1202struct sort_entry sort_mem_snoop = {
1203 .se_header = "Snoop",
1204 .se_cmp = sort__snoop_cmp,
1205 .se_snprintf = hist_entry__snoop_snprintf,
1206 .se_width_idx = HISTC_MEM_SNOOP,
1207};
1208
Don Zickus9b32ba72014-06-01 15:38:29 +02001209struct sort_entry sort_mem_dcacheline = {
1210 .se_header = "Data Cacheline",
1211 .se_cmp = sort__dcacheline_cmp,
1212 .se_snprintf = hist_entry__dcacheline_snprintf,
1213 .se_width_idx = HISTC_MEM_DCACHELINE,
1214};
1215
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001216static int64_t
1217sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1218{
Jiri Olsa49f47442014-10-16 16:07:01 +02001219 if (!left->branch_info || !right->branch_info)
1220 return cmp_null(left->branch_info, right->branch_info);
1221
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001222 return left->branch_info->flags.abort !=
1223 right->branch_info->flags.abort;
1224}
1225
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001226static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001227 size_t size, unsigned int width)
1228{
Jiri Olsa49f47442014-10-16 16:07:01 +02001229 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001230
Jiri Olsa49f47442014-10-16 16:07:01 +02001231 if (he->branch_info) {
1232 if (he->branch_info->flags.abort)
1233 out = "A";
1234 else
1235 out = ".";
1236 }
1237
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001238 return repsep_snprintf(bf, size, "%-*s", width, out);
1239}
1240
1241struct sort_entry sort_abort = {
1242 .se_header = "Transaction abort",
1243 .se_cmp = sort__abort_cmp,
1244 .se_snprintf = hist_entry__abort_snprintf,
1245 .se_width_idx = HISTC_ABORT,
1246};
1247
1248static int64_t
1249sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1250{
Jiri Olsa0199d242014-10-16 16:07:02 +02001251 if (!left->branch_info || !right->branch_info)
1252 return cmp_null(left->branch_info, right->branch_info);
1253
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001254 return left->branch_info->flags.in_tx !=
1255 right->branch_info->flags.in_tx;
1256}
1257
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001258static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001259 size_t size, unsigned int width)
1260{
Jiri Olsa0199d242014-10-16 16:07:02 +02001261 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001262
Jiri Olsa0199d242014-10-16 16:07:02 +02001263 if (he->branch_info) {
1264 if (he->branch_info->flags.in_tx)
1265 out = "T";
1266 else
1267 out = ".";
1268 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001269
1270 return repsep_snprintf(bf, size, "%-*s", width, out);
1271}
1272
1273struct sort_entry sort_in_tx = {
1274 .se_header = "Branch in transaction",
1275 .se_cmp = sort__in_tx_cmp,
1276 .se_snprintf = hist_entry__in_tx_snprintf,
1277 .se_width_idx = HISTC_IN_TX,
1278};
1279
Andi Kleen475eeab2013-09-20 07:40:43 -07001280static int64_t
1281sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1282{
1283 return left->transaction - right->transaction;
1284}
1285
1286static inline char *add_str(char *p, const char *str)
1287{
1288 strcpy(p, str);
1289 return p + strlen(str);
1290}
1291
1292static struct txbit {
1293 unsigned flag;
1294 const char *name;
1295 int skip_for_len;
1296} txbits[] = {
1297 { PERF_TXN_ELISION, "EL ", 0 },
1298 { PERF_TXN_TRANSACTION, "TX ", 1 },
1299 { PERF_TXN_SYNC, "SYNC ", 1 },
1300 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1301 { PERF_TXN_RETRY, "RETRY ", 0 },
1302 { PERF_TXN_CONFLICT, "CON ", 0 },
1303 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1304 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1305 { 0, NULL, 0 }
1306};
1307
1308int hist_entry__transaction_len(void)
1309{
1310 int i;
1311 int len = 0;
1312
1313 for (i = 0; txbits[i].name; i++) {
1314 if (!txbits[i].skip_for_len)
1315 len += strlen(txbits[i].name);
1316 }
1317 len += 4; /* :XX<space> */
1318 return len;
1319}
1320
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001321static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001322 size_t size, unsigned int width)
1323{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001324 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001325 char buf[128];
1326 char *p = buf;
1327 int i;
1328
1329 buf[0] = 0;
1330 for (i = 0; txbits[i].name; i++)
1331 if (txbits[i].flag & t)
1332 p = add_str(p, txbits[i].name);
1333 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1334 p = add_str(p, "NEITHER ");
1335 if (t & PERF_TXN_ABORT_MASK) {
1336 sprintf(p, ":%" PRIx64,
1337 (t & PERF_TXN_ABORT_MASK) >>
1338 PERF_TXN_ABORT_SHIFT);
1339 p += strlen(p);
1340 }
1341
1342 return repsep_snprintf(bf, size, "%-*s", width, buf);
1343}
1344
1345struct sort_entry sort_transaction = {
1346 .se_header = "Transaction ",
1347 .se_cmp = sort__transaction_cmp,
1348 .se_snprintf = hist_entry__transaction_snprintf,
1349 .se_width_idx = HISTC_TRANSACTION,
1350};
1351
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001352struct sort_dimension {
1353 const char *name;
1354 struct sort_entry *entry;
1355 int taken;
1356};
1357
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001358#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1359
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001360static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001361 DIM(SORT_PID, "pid", sort_thread),
1362 DIM(SORT_COMM, "comm", sort_comm),
1363 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001364 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001365 DIM(SORT_PARENT, "parent", sort_parent),
1366 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001367 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001368 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001369 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001370 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1371 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001372 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001373 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001374};
1375
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001376#undef DIM
1377
1378#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1379
1380static struct sort_dimension bstack_sort_dimensions[] = {
1381 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1382 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1383 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1384 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1385 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001386 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1387 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001388 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001389};
1390
1391#undef DIM
1392
Namhyung Kimafab87b2013-04-03 21:26:11 +09001393#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1394
1395static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001396 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001397 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001398 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1399 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1400 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1401 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1402 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001403 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001404};
1405
1406#undef DIM
1407
Namhyung Kima2ce0672014-03-04 09:06:42 +09001408struct hpp_dimension {
1409 const char *name;
1410 struct perf_hpp_fmt *fmt;
1411 int taken;
1412};
1413
1414#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1415
1416static struct hpp_dimension hpp_sort_dimensions[] = {
1417 DIM(PERF_HPP__OVERHEAD, "overhead"),
1418 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1419 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1420 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1421 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001422 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001423 DIM(PERF_HPP__SAMPLES, "sample"),
1424 DIM(PERF_HPP__PERIOD, "period"),
1425};
1426
1427#undef DIM
1428
Namhyung Kim8b536992014-03-03 11:46:55 +09001429struct hpp_sort_entry {
1430 struct perf_hpp_fmt hpp;
1431 struct sort_entry *se;
1432};
1433
Namhyung Kime0d66c72014-07-31 14:47:37 +09001434void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001435{
1436 struct hpp_sort_entry *hse;
1437
1438 if (!perf_hpp__is_sort_entry(fmt))
1439 return;
1440
1441 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001442 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001443}
1444
Namhyung Kim8b536992014-03-03 11:46:55 +09001445static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1446 struct perf_evsel *evsel)
1447{
1448 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001449 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001450
1451 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001452
Namhyung Kim5b591662014-07-31 14:47:38 +09001453 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001454 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001455
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001456 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001457}
1458
1459static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1460 struct perf_hpp *hpp __maybe_unused,
1461 struct perf_evsel *evsel)
1462{
1463 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001464 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001465
1466 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1467
Namhyung Kim5b591662014-07-31 14:47:38 +09001468 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001469 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001470
1471 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001472}
1473
1474static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1475 struct hist_entry *he)
1476{
1477 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001478 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001479
1480 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001481
1482 if (!len)
1483 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001484
1485 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1486}
1487
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001488static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1489 struct hist_entry *a, struct hist_entry *b)
1490{
1491 struct hpp_sort_entry *hse;
1492
1493 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1494 return hse->se->se_cmp(a, b);
1495}
1496
1497static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1498 struct hist_entry *a, struct hist_entry *b)
1499{
1500 struct hpp_sort_entry *hse;
1501 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1502
1503 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1504 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1505 return collapse_fn(a, b);
1506}
1507
1508static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1509 struct hist_entry *a, struct hist_entry *b)
1510{
1511 struct hpp_sort_entry *hse;
1512 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1513
1514 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1515 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1516 return sort_fn(a, b);
1517}
1518
Jiri Olsa97358082016-01-18 10:24:03 +01001519bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1520{
1521 return format->header == __sort__hpp_header;
1522}
1523
1524static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1525{
1526 struct hpp_sort_entry *hse_a;
1527 struct hpp_sort_entry *hse_b;
1528
1529 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1530 return false;
1531
1532 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1533 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1534
1535 return hse_a->se == hse_b->se;
1536}
1537
Jiri Olsa564132f2016-01-18 10:24:09 +01001538static void hse_free(struct perf_hpp_fmt *fmt)
1539{
1540 struct hpp_sort_entry *hse;
1541
1542 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1543 free(hse);
1544}
1545
Namhyung Kima7d945b2014-03-04 10:46:34 +09001546static struct hpp_sort_entry *
1547__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001548{
1549 struct hpp_sort_entry *hse;
1550
1551 hse = malloc(sizeof(*hse));
1552 if (hse == NULL) {
1553 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001554 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001555 }
1556
1557 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001558 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001559 hse->hpp.header = __sort__hpp_header;
1560 hse->hpp.width = __sort__hpp_width;
1561 hse->hpp.entry = __sort__hpp_entry;
1562 hse->hpp.color = NULL;
1563
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001564 hse->hpp.cmp = __sort__hpp_cmp;
1565 hse->hpp.collapse = __sort__hpp_collapse;
1566 hse->hpp.sort = __sort__hpp_sort;
Jiri Olsa97358082016-01-18 10:24:03 +01001567 hse->hpp.equal = __sort__hpp_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001568 hse->hpp.free = hse_free;
Namhyung Kim8b536992014-03-03 11:46:55 +09001569
1570 INIT_LIST_HEAD(&hse->hpp.list);
1571 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001572 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001573 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001574 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001575
Namhyung Kima7d945b2014-03-04 10:46:34 +09001576 return hse;
1577}
1578
Jiri Olsa564132f2016-01-18 10:24:09 +01001579static void hpp_free(struct perf_hpp_fmt *fmt)
1580{
1581 free(fmt);
1582}
1583
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001584static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
1585{
1586 struct perf_hpp_fmt *fmt;
1587
1588 fmt = memdup(hd->fmt, sizeof(*fmt));
1589 if (fmt) {
1590 INIT_LIST_HEAD(&fmt->list);
1591 INIT_LIST_HEAD(&fmt->sort_list);
Jiri Olsa564132f2016-01-18 10:24:09 +01001592 fmt->free = hpp_free;
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001593 }
1594
1595 return fmt;
1596}
1597
Namhyung Kima7d945b2014-03-04 10:46:34 +09001598static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1599{
1600 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1601
1602 if (hse == NULL)
1603 return -1;
1604
Namhyung Kim8b536992014-03-03 11:46:55 +09001605 perf_hpp__register_sort_field(&hse->hpp);
1606 return 0;
1607}
1608
Jiri Olsa07600022016-01-18 10:24:16 +01001609static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
1610 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001611{
1612 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1613
1614 if (hse == NULL)
1615 return -1;
1616
Jiri Olsa07600022016-01-18 10:24:16 +01001617 perf_hpp_list__column_register(list, &hse->hpp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001618 return 0;
1619}
1620
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001621struct hpp_dynamic_entry {
1622 struct perf_hpp_fmt hpp;
1623 struct perf_evsel *evsel;
1624 struct format_field *field;
1625 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001626 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001627};
1628
1629static int hde_width(struct hpp_dynamic_entry *hde)
1630{
1631 if (!hde->hpp.len) {
1632 int len = hde->dynamic_len;
1633 int namelen = strlen(hde->field->name);
1634 int fieldlen = hde->field->size;
1635
1636 if (namelen > len)
1637 len = namelen;
1638
1639 if (!(hde->field->flags & FIELD_IS_STRING)) {
1640 /* length for print hex numbers */
1641 fieldlen = hde->field->size * 2 + 2;
1642 }
1643 if (fieldlen > len)
1644 len = fieldlen;
1645
1646 hde->hpp.len = len;
1647 }
1648 return hde->hpp.len;
1649}
1650
Namhyung Kim60517d22015-12-23 02:07:03 +09001651static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1652 struct hist_entry *he)
1653{
1654 char *str, *pos;
1655 struct format_field *field = hde->field;
1656 size_t namelen;
1657 bool last = false;
1658
Namhyung Kim053a3982015-12-23 02:07:05 +09001659 if (hde->raw_trace)
1660 return;
1661
Namhyung Kim60517d22015-12-23 02:07:03 +09001662 /* parse pretty print result and update max length */
1663 if (!he->trace_output)
1664 he->trace_output = get_trace_output(he);
1665
1666 namelen = strlen(field->name);
1667 str = he->trace_output;
1668
1669 while (str) {
1670 pos = strchr(str, ' ');
1671 if (pos == NULL) {
1672 last = true;
1673 pos = str + strlen(str);
1674 }
1675
1676 if (!strncmp(str, field->name, namelen)) {
1677 size_t len;
1678
1679 str += namelen + 1;
1680 len = pos - str;
1681
1682 if (len > hde->dynamic_len)
1683 hde->dynamic_len = len;
1684 break;
1685 }
1686
1687 if (last)
1688 str = NULL;
1689 else
1690 str = pos + 1;
1691 }
1692}
1693
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001694static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1695 struct perf_evsel *evsel __maybe_unused)
1696{
1697 struct hpp_dynamic_entry *hde;
1698 size_t len = fmt->user_len;
1699
1700 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1701
1702 if (!len)
1703 len = hde_width(hde);
1704
1705 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1706}
1707
1708static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1709 struct perf_hpp *hpp __maybe_unused,
1710 struct perf_evsel *evsel __maybe_unused)
1711{
1712 struct hpp_dynamic_entry *hde;
1713 size_t len = fmt->user_len;
1714
1715 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1716
1717 if (!len)
1718 len = hde_width(hde);
1719
1720 return len;
1721}
1722
Namhyung Kim361459f2015-12-23 02:07:08 +09001723bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1724{
1725 struct hpp_dynamic_entry *hde;
1726
1727 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1728
1729 return hists_to_evsel(hists) == hde->evsel;
1730}
1731
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001732static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1733 struct hist_entry *he)
1734{
1735 struct hpp_dynamic_entry *hde;
1736 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001737 char *str, *pos;
1738 struct format_field *field;
1739 size_t namelen;
1740 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001741 int ret;
1742
1743 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1744
1745 if (!len)
1746 len = hde_width(hde);
1747
Namhyung Kim053a3982015-12-23 02:07:05 +09001748 if (hde->raw_trace)
1749 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001750
Namhyung Kim053a3982015-12-23 02:07:05 +09001751 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001752 namelen = strlen(field->name);
1753 str = he->trace_output;
1754
1755 while (str) {
1756 pos = strchr(str, ' ');
1757 if (pos == NULL) {
1758 last = true;
1759 pos = str + strlen(str);
1760 }
1761
1762 if (!strncmp(str, field->name, namelen)) {
1763 str += namelen + 1;
1764 str = strndup(str, pos - str);
1765
1766 if (str == NULL)
1767 return scnprintf(hpp->buf, hpp->size,
1768 "%*.*s", len, len, "ERROR");
1769 break;
1770 }
1771
1772 if (last)
1773 str = NULL;
1774 else
1775 str = pos + 1;
1776 }
1777
1778 if (str == NULL) {
1779 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001780raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001781 trace_seq_init(&seq);
1782 pevent_print_field(&seq, he->raw_data, hde->field);
1783 str = seq.buffer;
1784 }
1785
1786 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1787 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001788 return ret;
1789}
1790
1791static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1792 struct hist_entry *a, struct hist_entry *b)
1793{
1794 struct hpp_dynamic_entry *hde;
1795 struct format_field *field;
1796 unsigned offset, size;
1797
1798 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1799
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001800 field = hde->field;
1801 if (field->flags & FIELD_IS_DYNAMIC) {
1802 unsigned long long dyn;
1803
1804 pevent_read_number_field(field, a->raw_data, &dyn);
1805 offset = dyn & 0xffff;
1806 size = (dyn >> 16) & 0xffff;
1807
1808 /* record max width for output */
1809 if (size > hde->dynamic_len)
1810 hde->dynamic_len = size;
1811 } else {
1812 offset = field->offset;
1813 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001814
1815 update_dynamic_len(hde, a);
1816 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001817 }
1818
1819 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1820}
1821
Namhyung Kim361459f2015-12-23 02:07:08 +09001822bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1823{
1824 return fmt->cmp == __sort__hde_cmp;
1825}
1826
Namhyung Kim665aa752016-02-21 23:22:35 +09001827static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1828{
1829 struct hpp_dynamic_entry *hde_a;
1830 struct hpp_dynamic_entry *hde_b;
1831
1832 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1833 return false;
1834
1835 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1836 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1837
1838 return hde_a->field == hde_b->field;
1839}
1840
Jiri Olsa564132f2016-01-18 10:24:09 +01001841static void hde_free(struct perf_hpp_fmt *fmt)
1842{
1843 struct hpp_dynamic_entry *hde;
1844
1845 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1846 free(hde);
1847}
1848
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001849static struct hpp_dynamic_entry *
1850__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1851{
1852 struct hpp_dynamic_entry *hde;
1853
1854 hde = malloc(sizeof(*hde));
1855 if (hde == NULL) {
1856 pr_debug("Memory allocation failed\n");
1857 return NULL;
1858 }
1859
1860 hde->evsel = evsel;
1861 hde->field = field;
1862 hde->dynamic_len = 0;
1863
1864 hde->hpp.name = field->name;
1865 hde->hpp.header = __sort__hde_header;
1866 hde->hpp.width = __sort__hde_width;
1867 hde->hpp.entry = __sort__hde_entry;
1868 hde->hpp.color = NULL;
1869
1870 hde->hpp.cmp = __sort__hde_cmp;
1871 hde->hpp.collapse = __sort__hde_cmp;
1872 hde->hpp.sort = __sort__hde_cmp;
Namhyung Kim665aa752016-02-21 23:22:35 +09001873 hde->hpp.equal = __sort__hde_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001874 hde->hpp.free = hde_free;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001875
1876 INIT_LIST_HEAD(&hde->hpp.list);
1877 INIT_LIST_HEAD(&hde->hpp.sort_list);
1878 hde->hpp.elide = false;
1879 hde->hpp.len = 0;
1880 hde->hpp.user_len = 0;
1881
1882 return hde;
1883}
1884
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001885static int parse_field_name(char *str, char **event, char **field, char **opt)
1886{
1887 char *event_name, *field_name, *opt_name;
1888
1889 event_name = str;
1890 field_name = strchr(str, '.');
1891
1892 if (field_name) {
1893 *field_name++ = '\0';
1894 } else {
1895 event_name = NULL;
1896 field_name = str;
1897 }
1898
1899 opt_name = strchr(field_name, '/');
1900 if (opt_name)
1901 *opt_name++ = '\0';
1902
1903 *event = event_name;
1904 *field = field_name;
1905 *opt = opt_name;
1906
1907 return 0;
1908}
1909
1910/* find match evsel using a given event name. The event name can be:
Namhyung Kim9735be22016-01-05 19:58:35 +09001911 * 1. '%' + event index (e.g. '%1' for first event)
1912 * 2. full event name (e.g. sched:sched_switch)
1913 * 3. partial event name (should not contain ':')
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001914 */
1915static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1916{
1917 struct perf_evsel *evsel = NULL;
1918 struct perf_evsel *pos;
1919 bool full_name;
1920
1921 /* case 1 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001922 if (event_name[0] == '%') {
1923 int nr = strtol(event_name+1, NULL, 0);
1924
1925 if (nr > evlist->nr_entries)
1926 return NULL;
1927
1928 evsel = perf_evlist__first(evlist);
1929 while (--nr > 0)
1930 evsel = perf_evsel__next(evsel);
1931
1932 return evsel;
1933 }
1934
1935 full_name = !!strchr(event_name, ':');
1936 evlist__for_each(evlist, pos) {
Namhyung Kim9735be22016-01-05 19:58:35 +09001937 /* case 2 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001938 if (full_name && !strcmp(pos->name, event_name))
1939 return pos;
Namhyung Kim9735be22016-01-05 19:58:35 +09001940 /* case 3 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001941 if (!full_name && strstr(pos->name, event_name)) {
1942 if (evsel) {
1943 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1944 event_name, evsel->name, pos->name);
1945 return NULL;
1946 }
1947 evsel = pos;
1948 }
1949 }
1950
1951 return evsel;
1952}
1953
Namhyung Kim3b099bf52015-12-23 02:07:07 +09001954static int __dynamic_dimension__add(struct perf_evsel *evsel,
1955 struct format_field *field,
1956 bool raw_trace)
1957{
1958 struct hpp_dynamic_entry *hde;
1959
1960 hde = __alloc_dynamic_entry(evsel, field);
1961 if (hde == NULL)
1962 return -ENOMEM;
1963
1964 hde->raw_trace = raw_trace;
1965
1966 perf_hpp__register_sort_field(&hde->hpp);
1967 return 0;
1968}
1969
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001970static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1971{
1972 int ret;
1973 struct format_field *field;
1974
1975 field = evsel->tp_format->format.fields;
1976 while (field) {
1977 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1978 if (ret < 0)
1979 return ret;
1980
1981 field = field->next;
1982 }
1983 return 0;
1984}
1985
1986static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1987{
1988 int ret;
1989 struct perf_evsel *evsel;
1990
1991 evlist__for_each(evlist, evsel) {
1992 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1993 continue;
1994
1995 ret = add_evsel_fields(evsel, raw_trace);
1996 if (ret < 0)
1997 return ret;
1998 }
1999 return 0;
2000}
2001
Namhyung Kim9735be22016-01-05 19:58:35 +09002002static int add_all_matching_fields(struct perf_evlist *evlist,
2003 char *field_name, bool raw_trace)
2004{
2005 int ret = -ESRCH;
2006 struct perf_evsel *evsel;
2007 struct format_field *field;
2008
2009 evlist__for_each(evlist, evsel) {
2010 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2011 continue;
2012
2013 field = pevent_find_any_field(evsel->tp_format, field_name);
2014 if (field == NULL)
2015 continue;
2016
2017 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2018 if (ret < 0)
2019 break;
2020 }
2021 return ret;
2022}
2023
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002024static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2025{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002026 char *str, *event_name, *field_name, *opt_name;
2027 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002028 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09002029 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002030 int ret = 0;
2031
2032 if (evlist == NULL)
2033 return -ENOENT;
2034
2035 str = strdup(tok);
2036 if (str == NULL)
2037 return -ENOMEM;
2038
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002039 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002040 ret = -EINVAL;
2041 goto out;
2042 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002043
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002044 if (opt_name) {
2045 if (strcmp(opt_name, "raw")) {
2046 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09002047 ret = -EINVAL;
2048 goto out;
2049 }
2050 raw_trace = true;
2051 }
2052
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002053 if (!strcmp(field_name, "trace_fields")) {
2054 ret = add_all_dynamic_fields(evlist, raw_trace);
2055 goto out;
2056 }
2057
Namhyung Kim9735be22016-01-05 19:58:35 +09002058 if (event_name == NULL) {
2059 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2060 goto out;
2061 }
2062
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002063 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002064 if (evsel == NULL) {
2065 pr_debug("Cannot find event: %s\n", event_name);
2066 ret = -ENOENT;
2067 goto out;
2068 }
2069
2070 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2071 pr_debug("%s is not a tracepoint event\n", event_name);
2072 ret = -EINVAL;
2073 goto out;
2074 }
2075
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002076 if (!strcmp(field_name, "*")) {
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002077 ret = add_evsel_fields(evsel, raw_trace);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002078 } else {
2079 field = pevent_find_any_field(evsel->tp_format, field_name);
2080 if (field == NULL) {
2081 pr_debug("Cannot find event field for %s.%s\n",
2082 event_name, field_name);
2083 return -ENOENT;
2084 }
2085
2086 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2087 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002088
2089out:
2090 free(str);
2091 return ret;
2092}
2093
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002094static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002095{
2096 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002097 return 0;
2098
Namhyung Kima7d945b2014-03-04 10:46:34 +09002099 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002100 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002101
2102 if (sd->entry->se_collapse)
2103 sort__need_collapse = 1;
2104
Namhyung Kim2f532d092013-04-03 21:26:10 +09002105 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002106
2107 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002108}
2109
Namhyung Kima2ce0672014-03-04 09:06:42 +09002110static int __hpp_dimension__add(struct hpp_dimension *hd)
2111{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002112 struct perf_hpp_fmt *fmt;
Namhyung Kima2ce0672014-03-04 09:06:42 +09002113
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002114 if (hd->taken)
2115 return 0;
2116
2117 fmt = __hpp_dimension__alloc_hpp(hd);
2118 if (!fmt)
2119 return -1;
2120
2121 hd->taken = 1;
2122 perf_hpp__register_sort_field(fmt);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002123 return 0;
2124}
2125
Jiri Olsa07600022016-01-18 10:24:16 +01002126static int __sort_dimension__add_output(struct perf_hpp_list *list,
2127 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002128{
2129 if (sd->taken)
2130 return 0;
2131
Jiri Olsa07600022016-01-18 10:24:16 +01002132 if (__sort_dimension__add_hpp_output(list, sd) < 0)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002133 return -1;
2134
2135 sd->taken = 1;
2136 return 0;
2137}
2138
Jiri Olsa07600022016-01-18 10:24:16 +01002139static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2140 struct hpp_dimension *hd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002141{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002142 struct perf_hpp_fmt *fmt;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002143
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002144 if (hd->taken)
2145 return 0;
2146
2147 fmt = __hpp_dimension__alloc_hpp(hd);
2148 if (!fmt)
2149 return -1;
2150
2151 hd->taken = 1;
Jiri Olsa07600022016-01-18 10:24:16 +01002152 perf_hpp_list__column_register(list, fmt);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002153 return 0;
2154}
2155
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002156int hpp_dimension__add_output(unsigned col)
2157{
2158 BUG_ON(col >= PERF_HPP__MAX_INDEX);
Jiri Olsa07600022016-01-18 10:24:16 +01002159 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002160}
2161
Namhyung Kim40184c42015-12-23 02:07:01 +09002162static int sort_dimension__add(const char *tok,
2163 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02002164{
2165 unsigned int i;
2166
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002167 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2168 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002169
John Kacurdd68ada2009-09-24 18:02:49 +02002170 if (strncasecmp(tok, sd->name, strlen(tok)))
2171 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002172
John Kacurdd68ada2009-09-24 18:02:49 +02002173 if (sd->entry == &sort_parent) {
2174 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2175 if (ret) {
2176 char err[BUFSIZ];
2177
2178 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002179 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2180 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002181 }
2182 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002183 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09002184 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002185 /*
2186 * perf diff displays the performance difference amongst
2187 * two or more perf.data files. Those files could come
2188 * from different binaries. So we should not compare
2189 * their ips, but the name of symbol.
2190 */
2191 if (sort__mode == SORT_MODE__DIFF)
2192 sd->entry->se_collapse = sort__sym_sort;
2193
Namhyung Kim68f6d022013-12-18 14:21:10 +09002194 } else if (sd->entry == &sort_dso) {
2195 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002196 } else if (sd->entry == &sort_socket) {
2197 sort__has_socket = 1;
Namhyung Kimcfd92da2016-01-21 19:13:24 -03002198 } else if (sd->entry == &sort_thread) {
2199 sort__has_thread = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002200 }
2201
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002202 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02002203 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002204
Namhyung Kima2ce0672014-03-04 09:06:42 +09002205 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2206 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2207
2208 if (strncasecmp(tok, hd->name, strlen(tok)))
2209 continue;
2210
2211 return __hpp_dimension__add(hd);
2212 }
2213
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002214 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2215 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2216
2217 if (strncasecmp(tok, sd->name, strlen(tok)))
2218 continue;
2219
Namhyung Kim55369fc2013-04-01 20:35:20 +09002220 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002221 return -EINVAL;
2222
2223 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2224 sort__has_sym = 1;
2225
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002226 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002227 return 0;
2228 }
2229
Namhyung Kimafab87b2013-04-03 21:26:11 +09002230 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2231 struct sort_dimension *sd = &memory_sort_dimensions[i];
2232
2233 if (strncasecmp(tok, sd->name, strlen(tok)))
2234 continue;
2235
2236 if (sort__mode != SORT_MODE__MEMORY)
2237 return -EINVAL;
2238
2239 if (sd->entry == &sort_mem_daddr_sym)
2240 sort__has_sym = 1;
2241
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002242 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002243 return 0;
2244 }
2245
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002246 if (!add_dynamic_entry(evlist, tok))
2247 return 0;
2248
John Kacurdd68ada2009-09-24 18:02:49 +02002249 return -ESRCH;
2250}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002251
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002252static int setup_sort_list(char *str, struct perf_evlist *evlist)
2253{
2254 char *tmp, *tok;
2255 int ret = 0;
2256
2257 for (tok = strtok_r(str, ", ", &tmp);
2258 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2259 ret = sort_dimension__add(tok, evlist);
2260 if (ret == -EINVAL) {
2261 error("Invalid --sort key: `%s'", tok);
2262 break;
2263 } else if (ret == -ESRCH) {
2264 error("Unknown --sort key: `%s'", tok);
2265 break;
2266 }
2267 }
2268
2269 return ret;
2270}
2271
Namhyung Kimd49dade2015-12-23 02:07:10 +09002272static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002273{
2274 const char *default_sort_orders[] = {
2275 default_sort_order,
2276 default_branch_sort_order,
2277 default_mem_sort_order,
2278 default_top_sort_order,
2279 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002280 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002281 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002282 bool use_trace = true;
2283 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002284
2285 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2286
Namhyung Kimd49dade2015-12-23 02:07:10 +09002287 if (evlist == NULL)
2288 goto out_no_evlist;
2289
2290 evlist__for_each(evlist, evsel) {
2291 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2292 use_trace = false;
2293 break;
2294 }
2295 }
2296
2297 if (use_trace) {
2298 sort__mode = SORT_MODE__TRACEPOINT;
2299 if (symbol_conf.raw_trace)
2300 return "trace_fields";
2301 }
2302out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002303 return default_sort_orders[sort__mode];
2304}
2305
Namhyung Kimd49dade2015-12-23 02:07:10 +09002306static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002307{
2308 char *new_sort_order;
2309
2310 /*
2311 * Append '+'-prefixed sort order to the default sort
2312 * order string.
2313 */
2314 if (!sort_order || is_strict_order(sort_order))
2315 return 0;
2316
2317 if (sort_order[1] == '\0') {
2318 error("Invalid --sort key: `+'");
2319 return -EINVAL;
2320 }
2321
2322 /*
2323 * We allocate new sort_order string, but we never free it,
2324 * because it's checked over the rest of the code.
2325 */
2326 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002327 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002328 error("Not enough memory to set up --sort");
2329 return -ENOMEM;
2330 }
2331
2332 sort_order = new_sort_order;
2333 return 0;
2334}
2335
Jiri Olsab97511c2016-01-07 10:14:08 +01002336/*
2337 * Adds 'pre,' prefix into 'str' is 'pre' is
2338 * not already part of 'str'.
2339 */
2340static char *prefix_if_not_in(const char *pre, char *str)
2341{
2342 char *n;
2343
2344 if (!str || strstr(str, pre))
2345 return str;
2346
2347 if (asprintf(&n, "%s,%s", pre, str) < 0)
2348 return NULL;
2349
2350 free(str);
2351 return n;
2352}
2353
2354static char *setup_overhead(char *keys)
2355{
2356 keys = prefix_if_not_in("overhead", keys);
2357
2358 if (symbol_conf.cumulate_callchain)
2359 keys = prefix_if_not_in("overhead_children", keys);
2360
2361 return keys;
2362}
2363
Namhyung Kim40184c42015-12-23 02:07:01 +09002364static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002365{
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002366 char *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002367 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002368 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002369
Namhyung Kimd49dade2015-12-23 02:07:10 +09002370 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002371 if (ret)
2372 return ret;
2373
2374 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002375 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002376 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002377 /*
2378 * If user specified field order but no sort order,
2379 * we'll honor it and not add default sort orders.
2380 */
2381 return 0;
2382 }
2383
Namhyung Kimd49dade2015-12-23 02:07:10 +09002384 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002385 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002386
2387 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002388 if (str == NULL) {
2389 error("Not enough memory to setup sort keys");
2390 return -ENOMEM;
2391 }
2392
Jiri Olsab97511c2016-01-07 10:14:08 +01002393 /*
2394 * Prepend overhead fields for backward compatibility.
2395 */
2396 if (!is_strict_order(field_order)) {
2397 str = setup_overhead(str);
2398 if (str == NULL) {
2399 error("Not enough memory to setup overhead keys");
2400 return -ENOMEM;
2401 }
2402 }
2403
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002404 ret = setup_sort_list(str, evlist);
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002405
2406 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002407 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002408}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002409
Jiri Olsaf2998422014-05-23 17:15:47 +02002410void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002411{
Jiri Olsaf2998422014-05-23 17:15:47 +02002412 struct perf_hpp_fmt *fmt;
2413 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002414
Jiri Olsacf094042016-01-18 10:24:17 +01002415 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002416 if (!perf_hpp__is_sort_entry(fmt))
2417 continue;
2418
2419 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2420 if (hse->se->se_width_idx == idx) {
2421 fmt->elide = elide;
2422 break;
2423 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002424 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002425}
2426
Jiri Olsaf2998422014-05-23 17:15:47 +02002427static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002428{
2429 if (list && strlist__nr_entries(list) == 1) {
2430 if (fp != NULL)
2431 fprintf(fp, "# %s: %s\n", list_name,
2432 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002433 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002434 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002435 return false;
2436}
2437
2438static bool get_elide(int idx, FILE *output)
2439{
2440 switch (idx) {
2441 case HISTC_SYMBOL:
2442 return __get_elide(symbol_conf.sym_list, "symbol", output);
2443 case HISTC_DSO:
2444 return __get_elide(symbol_conf.dso_list, "dso", output);
2445 case HISTC_COMM:
2446 return __get_elide(symbol_conf.comm_list, "comm", output);
2447 default:
2448 break;
2449 }
2450
2451 if (sort__mode != SORT_MODE__BRANCH)
2452 return false;
2453
2454 switch (idx) {
2455 case HISTC_SYMBOL_FROM:
2456 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2457 case HISTC_SYMBOL_TO:
2458 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2459 case HISTC_DSO_FROM:
2460 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2461 case HISTC_DSO_TO:
2462 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2463 default:
2464 break;
2465 }
2466
2467 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002468}
Namhyung Kim08e71542013-04-03 21:26:19 +09002469
2470void sort__setup_elide(FILE *output)
2471{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002472 struct perf_hpp_fmt *fmt;
2473 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002474
Jiri Olsacf094042016-01-18 10:24:17 +01002475 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002476 if (!perf_hpp__is_sort_entry(fmt))
2477 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002478
Jiri Olsaf2998422014-05-23 17:15:47 +02002479 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2480 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002481 }
2482
Namhyung Kim7524f632013-11-08 17:53:42 +09002483 /*
2484 * It makes no sense to elide all of sort entries.
2485 * Just revert them to show up again.
2486 */
Jiri Olsacf094042016-01-18 10:24:17 +01002487 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002488 if (!perf_hpp__is_sort_entry(fmt))
2489 continue;
2490
Jiri Olsaf2998422014-05-23 17:15:47 +02002491 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002492 return;
2493 }
2494
Jiri Olsacf094042016-01-18 10:24:17 +01002495 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002496 if (!perf_hpp__is_sort_entry(fmt))
2497 continue;
2498
Jiri Olsaf2998422014-05-23 17:15:47 +02002499 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002500 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002501}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002502
Jiri Olsa07600022016-01-18 10:24:16 +01002503static int output_field_add(struct perf_hpp_list *list, char *tok)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002504{
2505 unsigned int i;
2506
2507 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2508 struct sort_dimension *sd = &common_sort_dimensions[i];
2509
2510 if (strncasecmp(tok, sd->name, strlen(tok)))
2511 continue;
2512
Jiri Olsa07600022016-01-18 10:24:16 +01002513 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002514 }
2515
2516 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2517 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2518
2519 if (strncasecmp(tok, hd->name, strlen(tok)))
2520 continue;
2521
Jiri Olsa07600022016-01-18 10:24:16 +01002522 return __hpp_dimension__add_output(list, hd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002523 }
2524
2525 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2526 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2527
2528 if (strncasecmp(tok, sd->name, strlen(tok)))
2529 continue;
2530
Jiri Olsa07600022016-01-18 10:24:16 +01002531 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002532 }
2533
2534 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2535 struct sort_dimension *sd = &memory_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 return -ESRCH;
2544}
2545
Jiri Olsa07600022016-01-18 10:24:16 +01002546static int setup_output_list(struct perf_hpp_list *list, char *str)
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002547{
2548 char *tmp, *tok;
2549 int ret = 0;
2550
2551 for (tok = strtok_r(str, ", ", &tmp);
2552 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Jiri Olsa07600022016-01-18 10:24:16 +01002553 ret = output_field_add(list, tok);
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002554 if (ret == -EINVAL) {
2555 error("Invalid --fields key: `%s'", tok);
2556 break;
2557 } else if (ret == -ESRCH) {
2558 error("Unknown --fields key: `%s'", tok);
2559 break;
2560 }
2561 }
2562
2563 return ret;
2564}
2565
Namhyung Kima7d945b2014-03-04 10:46:34 +09002566static void reset_dimensions(void)
2567{
2568 unsigned int i;
2569
2570 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2571 common_sort_dimensions[i].taken = 0;
2572
2573 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2574 hpp_sort_dimensions[i].taken = 0;
2575
2576 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2577 bstack_sort_dimensions[i].taken = 0;
2578
2579 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2580 memory_sort_dimensions[i].taken = 0;
2581}
2582
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002583bool is_strict_order(const char *order)
2584{
2585 return order && (*order != '+');
2586}
2587
Namhyung Kima7d945b2014-03-04 10:46:34 +09002588static int __setup_output_field(void)
2589{
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002590 char *str, *strp;
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002591 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002592
2593 if (field_order == NULL)
2594 return 0;
2595
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002596 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002597 if (str == NULL) {
2598 error("Not enough memory to setup output fields");
2599 return -ENOMEM;
2600 }
2601
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002602 if (!is_strict_order(field_order))
2603 strp++;
2604
2605 if (!strlen(strp)) {
2606 error("Invalid --fields key: `+'");
2607 goto out;
2608 }
2609
Jiri Olsa07600022016-01-18 10:24:16 +01002610 ret = setup_output_list(&perf_hpp_list, strp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002611
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002612out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002613 free(str);
2614 return ret;
2615}
2616
Namhyung Kim40184c42015-12-23 02:07:01 +09002617int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002618{
2619 int err;
2620
Namhyung Kim40184c42015-12-23 02:07:01 +09002621 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002622 if (err < 0)
2623 return err;
2624
2625 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002626 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002627 if (err < 0)
2628 return err;
2629 }
2630
2631 reset_dimensions();
2632
2633 /*
2634 * perf diff doesn't use default hpp output fields.
2635 */
2636 if (sort__mode != SORT_MODE__DIFF)
2637 perf_hpp__init();
2638
2639 err = __setup_output_field();
2640 if (err < 0)
2641 return err;
2642
2643 /* copy sort keys to output fields */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002644 perf_hpp__setup_output_field(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002645 /* and then copy output fields to sort keys */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002646 perf_hpp__append_sort_keys(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002647
2648 return 0;
2649}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002650
2651void reset_output_field(void)
2652{
2653 sort__need_collapse = 0;
2654 sort__has_parent = 0;
2655 sort__has_sym = 0;
2656 sort__has_dso = 0;
2657
Namhyung Kimd69b2962014-05-23 10:59:01 +09002658 field_order = NULL;
2659 sort_order = NULL;
2660
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002661 reset_dimensions();
Jiri Olsa43e0a682016-01-18 10:24:21 +01002662 perf_hpp__reset_output_field(&perf_hpp_list);
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002663}