blob: 8b54ede7ec1f4e1944bc445f106d42dfe9426caf [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 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259 width - ret, "");
260 } else {
261 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
262 width - ret,
263 sym->name);
264 }
265 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100266 size_t len = BITS_PER_LONG / 4;
267 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
268 len, ip);
269 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
270 width - ret, "");
271 }
272
Namhyung Kim5b591662014-07-31 14:47:38 +0900273 if (ret > width)
274 bf[width] = '\0';
275
276 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100277}
278
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300279static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900280 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100281{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300282 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
283 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100284}
John Kacurdd68ada2009-09-24 18:02:49 +0200285
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200286struct sort_entry sort_sym = {
287 .se_header = "Symbol",
288 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900289 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200290 .se_snprintf = hist_entry__sym_snprintf,
291 .se_width_idx = HISTC_SYMBOL,
292};
John Kacurdd68ada2009-09-24 18:02:49 +0200293
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300294/* --sort srcline */
295
296static int64_t
297sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
298{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900299 if (!left->srcline) {
300 if (!left->ms.map)
301 left->srcline = SRCLINE_UNKNOWN;
302 else {
303 struct map *map = left->ms.map;
304 left->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800305 map__rip_2objdump(map, left->ip),
306 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900307 }
308 }
309 if (!right->srcline) {
310 if (!right->ms.map)
311 right->srcline = SRCLINE_UNKNOWN;
312 else {
313 struct map *map = right->ms.map;
314 right->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800315 map__rip_2objdump(map, right->ip),
316 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900317 }
318 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900319 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300320}
321
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300322static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900323 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300324{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300325 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300326}
327
328struct sort_entry sort_srcline = {
329 .se_header = "Source:Line",
330 .se_cmp = sort__srcline_cmp,
331 .se_snprintf = hist_entry__srcline_snprintf,
332 .se_width_idx = HISTC_SRCLINE,
333};
334
Andi Kleen31191a82015-08-07 15:54:24 -0700335/* --sort srcfile */
336
337static char no_srcfile[1];
338
339static char *get_srcfile(struct hist_entry *e)
340{
341 char *sf, *p;
342 struct map *map = e->ms.map;
343
Andi Kleen2f84b422015-09-01 11:47:19 -0700344 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
345 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700346 if (!strcmp(sf, SRCLINE_UNKNOWN))
347 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700348 p = strchr(sf, ':');
349 if (p && *sf) {
350 *p = 0;
351 return sf;
352 }
353 free(sf);
354 return no_srcfile;
355}
356
357static int64_t
358sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
359{
360 if (!left->srcfile) {
361 if (!left->ms.map)
362 left->srcfile = no_srcfile;
363 else
364 left->srcfile = get_srcfile(left);
365 }
366 if (!right->srcfile) {
367 if (!right->ms.map)
368 right->srcfile = no_srcfile;
369 else
370 right->srcfile = get_srcfile(right);
371 }
372 return strcmp(right->srcfile, left->srcfile);
373}
374
375static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
376 size_t size, unsigned int width)
377{
378 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
379}
380
381struct sort_entry sort_srcfile = {
382 .se_header = "Source File",
383 .se_cmp = sort__srcfile_cmp,
384 .se_snprintf = hist_entry__srcfile_snprintf,
385 .se_width_idx = HISTC_SRCFILE,
386};
387
John Kacurdd68ada2009-09-24 18:02:49 +0200388/* --sort parent */
389
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200390static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200391sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
392{
393 struct symbol *sym_l = left->parent;
394 struct symbol *sym_r = right->parent;
395
396 if (!sym_l || !sym_r)
397 return cmp_null(sym_l, sym_r);
398
Namhyung Kim202e7a62014-03-04 11:01:41 +0900399 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200400}
401
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300402static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300403 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200404{
Namhyung Kim5b591662014-07-31 14:47:38 +0900405 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300406 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200407}
408
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200409struct sort_entry sort_parent = {
410 .se_header = "Parent symbol",
411 .se_cmp = sort__parent_cmp,
412 .se_snprintf = hist_entry__parent_snprintf,
413 .se_width_idx = HISTC_PARENT,
414};
415
Arun Sharmaf60f3592010-06-04 11:27:10 -0300416/* --sort cpu */
417
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200418static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300419sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
420{
421 return right->cpu - left->cpu;
422}
423
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300424static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
425 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300426{
Namhyung Kim5b591662014-07-31 14:47:38 +0900427 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300428}
429
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200430struct sort_entry sort_cpu = {
431 .se_header = "CPU",
432 .se_cmp = sort__cpu_cmp,
433 .se_snprintf = hist_entry__cpu_snprintf,
434 .se_width_idx = HISTC_CPU,
435};
436
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400437/* --sort socket */
438
439static int64_t
440sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
441{
442 return right->socket - left->socket;
443}
444
445static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
446 size_t size, unsigned int width)
447{
448 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
449}
450
451struct sort_entry sort_socket = {
452 .se_header = "Socket",
453 .se_cmp = sort__socket_cmp,
454 .se_snprintf = hist_entry__socket_snprintf,
455 .se_width_idx = HISTC_SOCKET,
456};
457
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900458/* --sort trace */
459
460static char *get_trace_output(struct hist_entry *he)
461{
462 struct trace_seq seq;
463 struct perf_evsel *evsel;
464 struct pevent_record rec = {
465 .data = he->raw_data,
466 .size = he->raw_size,
467 };
468
469 evsel = hists_to_evsel(he->hists);
470
471 trace_seq_init(&seq);
Namhyung Kim053a3982015-12-23 02:07:05 +0900472 if (symbol_conf.raw_trace) {
473 pevent_print_fields(&seq, he->raw_data, he->raw_size,
474 evsel->tp_format);
475 } else {
476 pevent_event_info(&seq, evsel->tp_format, &rec);
477 }
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900478 return seq.buffer;
479}
480
481static int64_t
482sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
483{
484 struct perf_evsel *evsel;
485
486 evsel = hists_to_evsel(left->hists);
487 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
488 return 0;
489
490 if (left->trace_output == NULL)
491 left->trace_output = get_trace_output(left);
492 if (right->trace_output == NULL)
493 right->trace_output = get_trace_output(right);
494
495 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
496 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
497
498 return strcmp(right->trace_output, left->trace_output);
499}
500
501static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
502 size_t size, unsigned int width)
503{
504 struct perf_evsel *evsel;
505
506 evsel = hists_to_evsel(he->hists);
507 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
508 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
509
510 if (he->trace_output == NULL)
511 he->trace_output = get_trace_output(he);
512 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
513}
514
515struct sort_entry sort_trace = {
516 .se_header = "Trace output",
517 .se_cmp = sort__trace_cmp,
518 .se_snprintf = hist_entry__trace_snprintf,
519 .se_width_idx = HISTC_TRACE,
520};
521
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900522/* sort keys for branch stacks */
523
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100524static int64_t
525sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
526{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200527 if (!left->branch_info || !right->branch_info)
528 return cmp_null(left->branch_info, right->branch_info);
529
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100530 return _sort__dso_cmp(left->branch_info->from.map,
531 right->branch_info->from.map);
532}
533
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300534static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100535 size_t size, unsigned int width)
536{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200537 if (he->branch_info)
538 return _hist_entry__dso_snprintf(he->branch_info->from.map,
539 bf, size, width);
540 else
541 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100542}
543
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100544static int64_t
545sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
546{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200547 if (!left->branch_info || !right->branch_info)
548 return cmp_null(left->branch_info, right->branch_info);
549
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100550 return _sort__dso_cmp(left->branch_info->to.map,
551 right->branch_info->to.map);
552}
553
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300554static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100555 size_t size, unsigned int width)
556{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200557 if (he->branch_info)
558 return _hist_entry__dso_snprintf(he->branch_info->to.map,
559 bf, size, width);
560 else
561 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100562}
563
564static int64_t
565sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
566{
567 struct addr_map_symbol *from_l = &left->branch_info->from;
568 struct addr_map_symbol *from_r = &right->branch_info->from;
569
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200570 if (!left->branch_info || !right->branch_info)
571 return cmp_null(left->branch_info, right->branch_info);
572
573 from_l = &left->branch_info->from;
574 from_r = &right->branch_info->from;
575
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100576 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900577 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100578
Namhyung Kim51f27d12013-02-06 14:57:15 +0900579 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100580}
581
582static int64_t
583sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
584{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200585 struct addr_map_symbol *to_l, *to_r;
586
587 if (!left->branch_info || !right->branch_info)
588 return cmp_null(left->branch_info, right->branch_info);
589
590 to_l = &left->branch_info->to;
591 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100592
593 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900594 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100595
Namhyung Kim51f27d12013-02-06 14:57:15 +0900596 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100597}
598
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300599static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900600 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100601{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200602 if (he->branch_info) {
603 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100604
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200605 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
606 he->level, bf, size, width);
607 }
608
609 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100610}
611
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300612static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900613 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100614{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200615 if (he->branch_info) {
616 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100617
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200618 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
619 he->level, bf, size, width);
620 }
621
622 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100623}
624
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900625struct sort_entry sort_dso_from = {
626 .se_header = "Source Shared Object",
627 .se_cmp = sort__dso_from_cmp,
628 .se_snprintf = hist_entry__dso_from_snprintf,
629 .se_width_idx = HISTC_DSO_FROM,
630};
631
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100632struct sort_entry sort_dso_to = {
633 .se_header = "Target Shared Object",
634 .se_cmp = sort__dso_to_cmp,
635 .se_snprintf = hist_entry__dso_to_snprintf,
636 .se_width_idx = HISTC_DSO_TO,
637};
638
639struct sort_entry sort_sym_from = {
640 .se_header = "Source Symbol",
641 .se_cmp = sort__sym_from_cmp,
642 .se_snprintf = hist_entry__sym_from_snprintf,
643 .se_width_idx = HISTC_SYMBOL_FROM,
644};
645
646struct sort_entry sort_sym_to = {
647 .se_header = "Target Symbol",
648 .se_cmp = sort__sym_to_cmp,
649 .se_snprintf = hist_entry__sym_to_snprintf,
650 .se_width_idx = HISTC_SYMBOL_TO,
651};
652
653static int64_t
654sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
655{
Jiri Olsa428560e2014-10-16 16:07:03 +0200656 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100657
Jiri Olsa428560e2014-10-16 16:07:03 +0200658 if (!left->branch_info || !right->branch_info)
659 return cmp_null(left->branch_info, right->branch_info);
660
661 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
662 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100663 return mp || p;
664}
665
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300666static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100667 size_t size, unsigned int width){
668 static const char *out = "N/A";
669
Jiri Olsa428560e2014-10-16 16:07:03 +0200670 if (he->branch_info) {
671 if (he->branch_info->flags.predicted)
672 out = "N";
673 else if (he->branch_info->flags.mispred)
674 out = "Y";
675 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100676
Namhyung Kim5b591662014-07-31 14:47:38 +0900677 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100678}
679
Andi Kleen0e332f02015-07-18 08:24:46 -0700680static int64_t
681sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
682{
683 return left->branch_info->flags.cycles -
684 right->branch_info->flags.cycles;
685}
686
687static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
688 size_t size, unsigned int width)
689{
690 if (he->branch_info->flags.cycles == 0)
691 return repsep_snprintf(bf, size, "%-*s", width, "-");
692 return repsep_snprintf(bf, size, "%-*hd", width,
693 he->branch_info->flags.cycles);
694}
695
696struct sort_entry sort_cycles = {
697 .se_header = "Basic Block Cycles",
698 .se_cmp = sort__cycles_cmp,
699 .se_snprintf = hist_entry__cycles_snprintf,
700 .se_width_idx = HISTC_CYCLES,
701};
702
Stephane Eranian98a3b322013-01-24 16:10:35 +0100703/* --sort daddr_sym */
704static int64_t
705sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
706{
707 uint64_t l = 0, r = 0;
708
709 if (left->mem_info)
710 l = left->mem_info->daddr.addr;
711 if (right->mem_info)
712 r = right->mem_info->daddr.addr;
713
714 return (int64_t)(r - l);
715}
716
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300717static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100718 size_t size, unsigned int width)
719{
720 uint64_t addr = 0;
721 struct map *map = NULL;
722 struct symbol *sym = NULL;
723
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300724 if (he->mem_info) {
725 addr = he->mem_info->daddr.addr;
726 map = he->mem_info->daddr.map;
727 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100728 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300729 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100730 width);
731}
732
733static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200734sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
735{
736 uint64_t l = 0, r = 0;
737
738 if (left->mem_info)
739 l = left->mem_info->iaddr.addr;
740 if (right->mem_info)
741 r = right->mem_info->iaddr.addr;
742
743 return (int64_t)(r - l);
744}
745
746static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
747 size_t size, unsigned int width)
748{
749 uint64_t addr = 0;
750 struct map *map = NULL;
751 struct symbol *sym = NULL;
752
753 if (he->mem_info) {
754 addr = he->mem_info->iaddr.addr;
755 map = he->mem_info->iaddr.map;
756 sym = he->mem_info->iaddr.sym;
757 }
758 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
759 width);
760}
761
762static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100763sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
764{
765 struct map *map_l = NULL;
766 struct map *map_r = NULL;
767
768 if (left->mem_info)
769 map_l = left->mem_info->daddr.map;
770 if (right->mem_info)
771 map_r = right->mem_info->daddr.map;
772
773 return _sort__dso_cmp(map_l, map_r);
774}
775
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300776static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100777 size_t size, unsigned int width)
778{
779 struct map *map = NULL;
780
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300781 if (he->mem_info)
782 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100783
784 return _hist_entry__dso_snprintf(map, bf, size, width);
785}
786
787static int64_t
788sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
789{
790 union perf_mem_data_src data_src_l;
791 union perf_mem_data_src data_src_r;
792
793 if (left->mem_info)
794 data_src_l = left->mem_info->data_src;
795 else
796 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
797
798 if (right->mem_info)
799 data_src_r = right->mem_info->data_src;
800 else
801 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
802
803 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
804}
805
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300806static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100807 size_t size, unsigned int width)
808{
809 const char *out;
810 u64 mask = PERF_MEM_LOCK_NA;
811
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300812 if (he->mem_info)
813 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100814
815 if (mask & PERF_MEM_LOCK_NA)
816 out = "N/A";
817 else if (mask & PERF_MEM_LOCK_LOCKED)
818 out = "Yes";
819 else
820 out = "No";
821
822 return repsep_snprintf(bf, size, "%-*s", width, out);
823}
824
825static int64_t
826sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
827{
828 union perf_mem_data_src data_src_l;
829 union perf_mem_data_src data_src_r;
830
831 if (left->mem_info)
832 data_src_l = left->mem_info->data_src;
833 else
834 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
835
836 if (right->mem_info)
837 data_src_r = right->mem_info->data_src;
838 else
839 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
840
841 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
842}
843
844static const char * const tlb_access[] = {
845 "N/A",
846 "HIT",
847 "MISS",
848 "L1",
849 "L2",
850 "Walker",
851 "Fault",
852};
853#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
854
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300855static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100856 size_t size, unsigned int width)
857{
858 char out[64];
859 size_t sz = sizeof(out) - 1; /* -1 for null termination */
860 size_t l = 0, i;
861 u64 m = PERF_MEM_TLB_NA;
862 u64 hit, miss;
863
864 out[0] = '\0';
865
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300866 if (he->mem_info)
867 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100868
869 hit = m & PERF_MEM_TLB_HIT;
870 miss = m & PERF_MEM_TLB_MISS;
871
872 /* already taken care of */
873 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
874
875 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
876 if (!(m & 0x1))
877 continue;
878 if (l) {
879 strcat(out, " or ");
880 l += 4;
881 }
882 strncat(out, tlb_access[i], sz - l);
883 l += strlen(tlb_access[i]);
884 }
885 if (*out == '\0')
886 strcpy(out, "N/A");
887 if (hit)
888 strncat(out, " hit", sz - l);
889 if (miss)
890 strncat(out, " miss", sz - l);
891
892 return repsep_snprintf(bf, size, "%-*s", width, out);
893}
894
895static int64_t
896sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
897{
898 union perf_mem_data_src data_src_l;
899 union perf_mem_data_src data_src_r;
900
901 if (left->mem_info)
902 data_src_l = left->mem_info->data_src;
903 else
904 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
905
906 if (right->mem_info)
907 data_src_r = right->mem_info->data_src;
908 else
909 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
910
911 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
912}
913
914static const char * const mem_lvl[] = {
915 "N/A",
916 "HIT",
917 "MISS",
918 "L1",
919 "LFB",
920 "L2",
921 "L3",
922 "Local RAM",
923 "Remote RAM (1 hop)",
924 "Remote RAM (2 hops)",
925 "Remote Cache (1 hop)",
926 "Remote Cache (2 hops)",
927 "I/O",
928 "Uncached",
929};
930#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
931
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300932static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100933 size_t size, unsigned int width)
934{
935 char out[64];
936 size_t sz = sizeof(out) - 1; /* -1 for null termination */
937 size_t i, l = 0;
938 u64 m = PERF_MEM_LVL_NA;
939 u64 hit, miss;
940
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300941 if (he->mem_info)
942 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100943
944 out[0] = '\0';
945
946 hit = m & PERF_MEM_LVL_HIT;
947 miss = m & PERF_MEM_LVL_MISS;
948
949 /* already taken care of */
950 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
951
952 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
953 if (!(m & 0x1))
954 continue;
955 if (l) {
956 strcat(out, " or ");
957 l += 4;
958 }
959 strncat(out, mem_lvl[i], sz - l);
960 l += strlen(mem_lvl[i]);
961 }
962 if (*out == '\0')
963 strcpy(out, "N/A");
964 if (hit)
965 strncat(out, " hit", sz - l);
966 if (miss)
967 strncat(out, " miss", sz - l);
968
969 return repsep_snprintf(bf, size, "%-*s", width, out);
970}
971
972static int64_t
973sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
974{
975 union perf_mem_data_src data_src_l;
976 union perf_mem_data_src data_src_r;
977
978 if (left->mem_info)
979 data_src_l = left->mem_info->data_src;
980 else
981 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
982
983 if (right->mem_info)
984 data_src_r = right->mem_info->data_src;
985 else
986 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
987
988 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
989}
990
991static const char * const snoop_access[] = {
992 "N/A",
993 "None",
994 "Miss",
995 "Hit",
996 "HitM",
997};
998#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
999
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001000static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +01001001 size_t size, unsigned int width)
1002{
1003 char out[64];
1004 size_t sz = sizeof(out) - 1; /* -1 for null termination */
1005 size_t i, l = 0;
1006 u64 m = PERF_MEM_SNOOP_NA;
1007
1008 out[0] = '\0';
1009
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001010 if (he->mem_info)
1011 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +01001012
1013 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1014 if (!(m & 0x1))
1015 continue;
1016 if (l) {
1017 strcat(out, " or ");
1018 l += 4;
1019 }
1020 strncat(out, snoop_access[i], sz - l);
1021 l += strlen(snoop_access[i]);
1022 }
1023
1024 if (*out == '\0')
1025 strcpy(out, "N/A");
1026
1027 return repsep_snprintf(bf, size, "%-*s", width, out);
1028}
1029
Don Zickus9b32ba72014-06-01 15:38:29 +02001030static inline u64 cl_address(u64 address)
1031{
1032 /* return the cacheline of the address */
1033 return (address & ~(cacheline_size - 1));
1034}
1035
1036static int64_t
1037sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1038{
1039 u64 l, r;
1040 struct map *l_map, *r_map;
1041
1042 if (!left->mem_info) return -1;
1043 if (!right->mem_info) return 1;
1044
1045 /* group event types together */
1046 if (left->cpumode > right->cpumode) return -1;
1047 if (left->cpumode < right->cpumode) return 1;
1048
1049 l_map = left->mem_info->daddr.map;
1050 r_map = right->mem_info->daddr.map;
1051
1052 /* if both are NULL, jump to sort on al_addr instead */
1053 if (!l_map && !r_map)
1054 goto addr;
1055
1056 if (!l_map) return -1;
1057 if (!r_map) return 1;
1058
1059 if (l_map->maj > r_map->maj) return -1;
1060 if (l_map->maj < r_map->maj) return 1;
1061
1062 if (l_map->min > r_map->min) return -1;
1063 if (l_map->min < r_map->min) return 1;
1064
1065 if (l_map->ino > r_map->ino) return -1;
1066 if (l_map->ino < r_map->ino) return 1;
1067
1068 if (l_map->ino_generation > r_map->ino_generation) return -1;
1069 if (l_map->ino_generation < r_map->ino_generation) return 1;
1070
1071 /*
1072 * Addresses with no major/minor numbers are assumed to be
1073 * anonymous in userspace. Sort those on pid then address.
1074 *
1075 * The kernel and non-zero major/minor mapped areas are
1076 * assumed to be unity mapped. Sort those on address.
1077 */
1078
1079 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1080 (!(l_map->flags & MAP_SHARED)) &&
1081 !l_map->maj && !l_map->min && !l_map->ino &&
1082 !l_map->ino_generation) {
1083 /* userspace anonymous */
1084
1085 if (left->thread->pid_ > right->thread->pid_) return -1;
1086 if (left->thread->pid_ < right->thread->pid_) return 1;
1087 }
1088
1089addr:
1090 /* al_addr does all the right addr - start + offset calculations */
1091 l = cl_address(left->mem_info->daddr.al_addr);
1092 r = cl_address(right->mem_info->daddr.al_addr);
1093
1094 if (l > r) return -1;
1095 if (l < r) return 1;
1096
1097 return 0;
1098}
1099
1100static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1101 size_t size, unsigned int width)
1102{
1103
1104 uint64_t addr = 0;
1105 struct map *map = NULL;
1106 struct symbol *sym = NULL;
1107 char level = he->level;
1108
1109 if (he->mem_info) {
1110 addr = cl_address(he->mem_info->daddr.al_addr);
1111 map = he->mem_info->daddr.map;
1112 sym = he->mem_info->daddr.sym;
1113
1114 /* print [s] for shared data mmaps */
1115 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1116 map && (map->type == MAP__VARIABLE) &&
1117 (map->flags & MAP_SHARED) &&
1118 (map->maj || map->min || map->ino ||
1119 map->ino_generation))
1120 level = 's';
1121 else if (!map)
1122 level = 'X';
1123 }
1124 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1125 width);
1126}
1127
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001128struct sort_entry sort_mispredict = {
1129 .se_header = "Branch Mispredicted",
1130 .se_cmp = sort__mispredict_cmp,
1131 .se_snprintf = hist_entry__mispredict_snprintf,
1132 .se_width_idx = HISTC_MISPREDICT,
1133};
1134
Andi Kleen05484292013-01-24 16:10:29 +01001135static u64 he_weight(struct hist_entry *he)
1136{
1137 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1138}
1139
1140static int64_t
1141sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1142{
1143 return he_weight(left) - he_weight(right);
1144}
1145
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001146static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001147 size_t size, unsigned int width)
1148{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001149 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001150}
1151
1152struct sort_entry sort_local_weight = {
1153 .se_header = "Local Weight",
1154 .se_cmp = sort__local_weight_cmp,
1155 .se_snprintf = hist_entry__local_weight_snprintf,
1156 .se_width_idx = HISTC_LOCAL_WEIGHT,
1157};
1158
1159static int64_t
1160sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1161{
1162 return left->stat.weight - right->stat.weight;
1163}
1164
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001165static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001166 size_t size, unsigned int width)
1167{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001168 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001169}
1170
1171struct sort_entry sort_global_weight = {
1172 .se_header = "Weight",
1173 .se_cmp = sort__global_weight_cmp,
1174 .se_snprintf = hist_entry__global_weight_snprintf,
1175 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1176};
1177
Stephane Eranian98a3b322013-01-24 16:10:35 +01001178struct sort_entry sort_mem_daddr_sym = {
1179 .se_header = "Data Symbol",
1180 .se_cmp = sort__daddr_cmp,
1181 .se_snprintf = hist_entry__daddr_snprintf,
1182 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1183};
1184
Don Zickus28e6db22015-10-05 20:06:07 +02001185struct sort_entry sort_mem_iaddr_sym = {
1186 .se_header = "Code Symbol",
1187 .se_cmp = sort__iaddr_cmp,
1188 .se_snprintf = hist_entry__iaddr_snprintf,
1189 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1190};
1191
Stephane Eranian98a3b322013-01-24 16:10:35 +01001192struct sort_entry sort_mem_daddr_dso = {
1193 .se_header = "Data Object",
1194 .se_cmp = sort__dso_daddr_cmp,
1195 .se_snprintf = hist_entry__dso_daddr_snprintf,
1196 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1197};
1198
1199struct sort_entry sort_mem_locked = {
1200 .se_header = "Locked",
1201 .se_cmp = sort__locked_cmp,
1202 .se_snprintf = hist_entry__locked_snprintf,
1203 .se_width_idx = HISTC_MEM_LOCKED,
1204};
1205
1206struct sort_entry sort_mem_tlb = {
1207 .se_header = "TLB access",
1208 .se_cmp = sort__tlb_cmp,
1209 .se_snprintf = hist_entry__tlb_snprintf,
1210 .se_width_idx = HISTC_MEM_TLB,
1211};
1212
1213struct sort_entry sort_mem_lvl = {
1214 .se_header = "Memory access",
1215 .se_cmp = sort__lvl_cmp,
1216 .se_snprintf = hist_entry__lvl_snprintf,
1217 .se_width_idx = HISTC_MEM_LVL,
1218};
1219
1220struct sort_entry sort_mem_snoop = {
1221 .se_header = "Snoop",
1222 .se_cmp = sort__snoop_cmp,
1223 .se_snprintf = hist_entry__snoop_snprintf,
1224 .se_width_idx = HISTC_MEM_SNOOP,
1225};
1226
Don Zickus9b32ba72014-06-01 15:38:29 +02001227struct sort_entry sort_mem_dcacheline = {
1228 .se_header = "Data Cacheline",
1229 .se_cmp = sort__dcacheline_cmp,
1230 .se_snprintf = hist_entry__dcacheline_snprintf,
1231 .se_width_idx = HISTC_MEM_DCACHELINE,
1232};
1233
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001234static int64_t
1235sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1236{
Jiri Olsa49f47442014-10-16 16:07:01 +02001237 if (!left->branch_info || !right->branch_info)
1238 return cmp_null(left->branch_info, right->branch_info);
1239
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001240 return left->branch_info->flags.abort !=
1241 right->branch_info->flags.abort;
1242}
1243
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001244static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001245 size_t size, unsigned int width)
1246{
Jiri Olsa49f47442014-10-16 16:07:01 +02001247 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001248
Jiri Olsa49f47442014-10-16 16:07:01 +02001249 if (he->branch_info) {
1250 if (he->branch_info->flags.abort)
1251 out = "A";
1252 else
1253 out = ".";
1254 }
1255
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001256 return repsep_snprintf(bf, size, "%-*s", width, out);
1257}
1258
1259struct sort_entry sort_abort = {
1260 .se_header = "Transaction abort",
1261 .se_cmp = sort__abort_cmp,
1262 .se_snprintf = hist_entry__abort_snprintf,
1263 .se_width_idx = HISTC_ABORT,
1264};
1265
1266static int64_t
1267sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1268{
Jiri Olsa0199d242014-10-16 16:07:02 +02001269 if (!left->branch_info || !right->branch_info)
1270 return cmp_null(left->branch_info, right->branch_info);
1271
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001272 return left->branch_info->flags.in_tx !=
1273 right->branch_info->flags.in_tx;
1274}
1275
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001276static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001277 size_t size, unsigned int width)
1278{
Jiri Olsa0199d242014-10-16 16:07:02 +02001279 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001280
Jiri Olsa0199d242014-10-16 16:07:02 +02001281 if (he->branch_info) {
1282 if (he->branch_info->flags.in_tx)
1283 out = "T";
1284 else
1285 out = ".";
1286 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001287
1288 return repsep_snprintf(bf, size, "%-*s", width, out);
1289}
1290
1291struct sort_entry sort_in_tx = {
1292 .se_header = "Branch in transaction",
1293 .se_cmp = sort__in_tx_cmp,
1294 .se_snprintf = hist_entry__in_tx_snprintf,
1295 .se_width_idx = HISTC_IN_TX,
1296};
1297
Andi Kleen475eeab2013-09-20 07:40:43 -07001298static int64_t
1299sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1300{
1301 return left->transaction - right->transaction;
1302}
1303
1304static inline char *add_str(char *p, const char *str)
1305{
1306 strcpy(p, str);
1307 return p + strlen(str);
1308}
1309
1310static struct txbit {
1311 unsigned flag;
1312 const char *name;
1313 int skip_for_len;
1314} txbits[] = {
1315 { PERF_TXN_ELISION, "EL ", 0 },
1316 { PERF_TXN_TRANSACTION, "TX ", 1 },
1317 { PERF_TXN_SYNC, "SYNC ", 1 },
1318 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1319 { PERF_TXN_RETRY, "RETRY ", 0 },
1320 { PERF_TXN_CONFLICT, "CON ", 0 },
1321 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1322 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1323 { 0, NULL, 0 }
1324};
1325
1326int hist_entry__transaction_len(void)
1327{
1328 int i;
1329 int len = 0;
1330
1331 for (i = 0; txbits[i].name; i++) {
1332 if (!txbits[i].skip_for_len)
1333 len += strlen(txbits[i].name);
1334 }
1335 len += 4; /* :XX<space> */
1336 return len;
1337}
1338
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001339static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001340 size_t size, unsigned int width)
1341{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001342 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001343 char buf[128];
1344 char *p = buf;
1345 int i;
1346
1347 buf[0] = 0;
1348 for (i = 0; txbits[i].name; i++)
1349 if (txbits[i].flag & t)
1350 p = add_str(p, txbits[i].name);
1351 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1352 p = add_str(p, "NEITHER ");
1353 if (t & PERF_TXN_ABORT_MASK) {
1354 sprintf(p, ":%" PRIx64,
1355 (t & PERF_TXN_ABORT_MASK) >>
1356 PERF_TXN_ABORT_SHIFT);
1357 p += strlen(p);
1358 }
1359
1360 return repsep_snprintf(bf, size, "%-*s", width, buf);
1361}
1362
1363struct sort_entry sort_transaction = {
1364 .se_header = "Transaction ",
1365 .se_cmp = sort__transaction_cmp,
1366 .se_snprintf = hist_entry__transaction_snprintf,
1367 .se_width_idx = HISTC_TRANSACTION,
1368};
1369
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001370struct sort_dimension {
1371 const char *name;
1372 struct sort_entry *entry;
1373 int taken;
1374};
1375
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001376#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1377
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001378static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001379 DIM(SORT_PID, "pid", sort_thread),
1380 DIM(SORT_COMM, "comm", sort_comm),
1381 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001382 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001383 DIM(SORT_PARENT, "parent", sort_parent),
1384 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001385 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001386 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001387 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001388 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1389 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001390 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001391 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001392};
1393
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001394#undef DIM
1395
1396#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1397
1398static struct sort_dimension bstack_sort_dimensions[] = {
1399 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1400 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1401 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1402 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1403 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001404 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1405 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001406 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001407};
1408
1409#undef DIM
1410
Namhyung Kimafab87b2013-04-03 21:26:11 +09001411#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1412
1413static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001414 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001415 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001416 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1417 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1418 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1419 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1420 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001421 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001422};
1423
1424#undef DIM
1425
Namhyung Kima2ce0672014-03-04 09:06:42 +09001426struct hpp_dimension {
1427 const char *name;
1428 struct perf_hpp_fmt *fmt;
1429 int taken;
1430};
1431
1432#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1433
1434static struct hpp_dimension hpp_sort_dimensions[] = {
1435 DIM(PERF_HPP__OVERHEAD, "overhead"),
1436 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1437 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1438 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1439 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001440 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001441 DIM(PERF_HPP__SAMPLES, "sample"),
1442 DIM(PERF_HPP__PERIOD, "period"),
1443};
1444
1445#undef DIM
1446
Namhyung Kim8b536992014-03-03 11:46:55 +09001447struct hpp_sort_entry {
1448 struct perf_hpp_fmt hpp;
1449 struct sort_entry *se;
1450};
1451
Namhyung Kime0d66c72014-07-31 14:47:37 +09001452void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001453{
1454 struct hpp_sort_entry *hse;
1455
1456 if (!perf_hpp__is_sort_entry(fmt))
1457 return;
1458
1459 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001460 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001461}
1462
Namhyung Kim8b536992014-03-03 11:46:55 +09001463static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1464 struct perf_evsel *evsel)
1465{
1466 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001467 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001468
1469 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001470
Namhyung Kim5b591662014-07-31 14:47:38 +09001471 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001472 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001473
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001474 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001475}
1476
1477static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1478 struct perf_hpp *hpp __maybe_unused,
1479 struct perf_evsel *evsel)
1480{
1481 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001482 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001483
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485
Namhyung Kim5b591662014-07-31 14:47:38 +09001486 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001487 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001488
1489 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001490}
1491
1492static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1493 struct hist_entry *he)
1494{
1495 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001496 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001497
1498 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001499
1500 if (!len)
1501 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001502
1503 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1504}
1505
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001506static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1507 struct hist_entry *a, struct hist_entry *b)
1508{
1509 struct hpp_sort_entry *hse;
1510
1511 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1512 return hse->se->se_cmp(a, b);
1513}
1514
1515static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1516 struct hist_entry *a, struct hist_entry *b)
1517{
1518 struct hpp_sort_entry *hse;
1519 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1520
1521 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1522 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1523 return collapse_fn(a, b);
1524}
1525
1526static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1527 struct hist_entry *a, struct hist_entry *b)
1528{
1529 struct hpp_sort_entry *hse;
1530 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1531
1532 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1533 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1534 return sort_fn(a, b);
1535}
1536
Jiri Olsa97358082016-01-18 10:24:03 +01001537bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1538{
1539 return format->header == __sort__hpp_header;
1540}
1541
1542static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1543{
1544 struct hpp_sort_entry *hse_a;
1545 struct hpp_sort_entry *hse_b;
1546
1547 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1548 return false;
1549
1550 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1551 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1552
1553 return hse_a->se == hse_b->se;
1554}
1555
Jiri Olsa564132f2016-01-18 10:24:09 +01001556static void hse_free(struct perf_hpp_fmt *fmt)
1557{
1558 struct hpp_sort_entry *hse;
1559
1560 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1561 free(hse);
1562}
1563
Namhyung Kima7d945b2014-03-04 10:46:34 +09001564static struct hpp_sort_entry *
1565__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001566{
1567 struct hpp_sort_entry *hse;
1568
1569 hse = malloc(sizeof(*hse));
1570 if (hse == NULL) {
1571 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001572 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001573 }
1574
1575 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001576 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001577 hse->hpp.header = __sort__hpp_header;
1578 hse->hpp.width = __sort__hpp_width;
1579 hse->hpp.entry = __sort__hpp_entry;
1580 hse->hpp.color = NULL;
1581
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001582 hse->hpp.cmp = __sort__hpp_cmp;
1583 hse->hpp.collapse = __sort__hpp_collapse;
1584 hse->hpp.sort = __sort__hpp_sort;
Jiri Olsa97358082016-01-18 10:24:03 +01001585 hse->hpp.equal = __sort__hpp_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001586 hse->hpp.free = hse_free;
Namhyung Kim8b536992014-03-03 11:46:55 +09001587
1588 INIT_LIST_HEAD(&hse->hpp.list);
1589 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001590 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001591 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001592 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001593
Namhyung Kima7d945b2014-03-04 10:46:34 +09001594 return hse;
1595}
1596
Jiri Olsa564132f2016-01-18 10:24:09 +01001597static void hpp_free(struct perf_hpp_fmt *fmt)
1598{
1599 free(fmt);
1600}
1601
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001602static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
1603{
1604 struct perf_hpp_fmt *fmt;
1605
1606 fmt = memdup(hd->fmt, sizeof(*fmt));
1607 if (fmt) {
1608 INIT_LIST_HEAD(&fmt->list);
1609 INIT_LIST_HEAD(&fmt->sort_list);
Jiri Olsa564132f2016-01-18 10:24:09 +01001610 fmt->free = hpp_free;
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001611 }
1612
1613 return fmt;
1614}
1615
Namhyung Kima7d945b2014-03-04 10:46:34 +09001616static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1617{
1618 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1619
1620 if (hse == NULL)
1621 return -1;
1622
Namhyung Kim8b536992014-03-03 11:46:55 +09001623 perf_hpp__register_sort_field(&hse->hpp);
1624 return 0;
1625}
1626
Jiri Olsa07600022016-01-18 10:24:16 +01001627static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
1628 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001629{
1630 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1631
1632 if (hse == NULL)
1633 return -1;
1634
Jiri Olsa07600022016-01-18 10:24:16 +01001635 perf_hpp_list__column_register(list, &hse->hpp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001636 return 0;
1637}
1638
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001639struct hpp_dynamic_entry {
1640 struct perf_hpp_fmt hpp;
1641 struct perf_evsel *evsel;
1642 struct format_field *field;
1643 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001644 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001645};
1646
1647static int hde_width(struct hpp_dynamic_entry *hde)
1648{
1649 if (!hde->hpp.len) {
1650 int len = hde->dynamic_len;
1651 int namelen = strlen(hde->field->name);
1652 int fieldlen = hde->field->size;
1653
1654 if (namelen > len)
1655 len = namelen;
1656
1657 if (!(hde->field->flags & FIELD_IS_STRING)) {
1658 /* length for print hex numbers */
1659 fieldlen = hde->field->size * 2 + 2;
1660 }
1661 if (fieldlen > len)
1662 len = fieldlen;
1663
1664 hde->hpp.len = len;
1665 }
1666 return hde->hpp.len;
1667}
1668
Namhyung Kim60517d22015-12-23 02:07:03 +09001669static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1670 struct hist_entry *he)
1671{
1672 char *str, *pos;
1673 struct format_field *field = hde->field;
1674 size_t namelen;
1675 bool last = false;
1676
Namhyung Kim053a3982015-12-23 02:07:05 +09001677 if (hde->raw_trace)
1678 return;
1679
Namhyung Kim60517d22015-12-23 02:07:03 +09001680 /* parse pretty print result and update max length */
1681 if (!he->trace_output)
1682 he->trace_output = get_trace_output(he);
1683
1684 namelen = strlen(field->name);
1685 str = he->trace_output;
1686
1687 while (str) {
1688 pos = strchr(str, ' ');
1689 if (pos == NULL) {
1690 last = true;
1691 pos = str + strlen(str);
1692 }
1693
1694 if (!strncmp(str, field->name, namelen)) {
1695 size_t len;
1696
1697 str += namelen + 1;
1698 len = pos - str;
1699
1700 if (len > hde->dynamic_len)
1701 hde->dynamic_len = len;
1702 break;
1703 }
1704
1705 if (last)
1706 str = NULL;
1707 else
1708 str = pos + 1;
1709 }
1710}
1711
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001712static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1713 struct perf_evsel *evsel __maybe_unused)
1714{
1715 struct hpp_dynamic_entry *hde;
1716 size_t len = fmt->user_len;
1717
1718 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1719
1720 if (!len)
1721 len = hde_width(hde);
1722
1723 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1724}
1725
1726static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1727 struct perf_hpp *hpp __maybe_unused,
1728 struct perf_evsel *evsel __maybe_unused)
1729{
1730 struct hpp_dynamic_entry *hde;
1731 size_t len = fmt->user_len;
1732
1733 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1734
1735 if (!len)
1736 len = hde_width(hde);
1737
1738 return len;
1739}
1740
Namhyung Kim361459f2015-12-23 02:07:08 +09001741bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1742{
1743 struct hpp_dynamic_entry *hde;
1744
1745 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1746
1747 return hists_to_evsel(hists) == hde->evsel;
1748}
1749
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001750static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1751 struct hist_entry *he)
1752{
1753 struct hpp_dynamic_entry *hde;
1754 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001755 char *str, *pos;
1756 struct format_field *field;
1757 size_t namelen;
1758 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001759 int ret;
1760
1761 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1762
1763 if (!len)
1764 len = hde_width(hde);
1765
Namhyung Kim053a3982015-12-23 02:07:05 +09001766 if (hde->raw_trace)
1767 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001768
Namhyung Kim053a3982015-12-23 02:07:05 +09001769 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001770 namelen = strlen(field->name);
1771 str = he->trace_output;
1772
1773 while (str) {
1774 pos = strchr(str, ' ');
1775 if (pos == NULL) {
1776 last = true;
1777 pos = str + strlen(str);
1778 }
1779
1780 if (!strncmp(str, field->name, namelen)) {
1781 str += namelen + 1;
1782 str = strndup(str, pos - str);
1783
1784 if (str == NULL)
1785 return scnprintf(hpp->buf, hpp->size,
1786 "%*.*s", len, len, "ERROR");
1787 break;
1788 }
1789
1790 if (last)
1791 str = NULL;
1792 else
1793 str = pos + 1;
1794 }
1795
1796 if (str == NULL) {
1797 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001798raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001799 trace_seq_init(&seq);
1800 pevent_print_field(&seq, he->raw_data, hde->field);
1801 str = seq.buffer;
1802 }
1803
1804 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1805 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001806 return ret;
1807}
1808
1809static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1810 struct hist_entry *a, struct hist_entry *b)
1811{
1812 struct hpp_dynamic_entry *hde;
1813 struct format_field *field;
1814 unsigned offset, size;
1815
1816 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1817
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001818 field = hde->field;
1819 if (field->flags & FIELD_IS_DYNAMIC) {
1820 unsigned long long dyn;
1821
1822 pevent_read_number_field(field, a->raw_data, &dyn);
1823 offset = dyn & 0xffff;
1824 size = (dyn >> 16) & 0xffff;
1825
1826 /* record max width for output */
1827 if (size > hde->dynamic_len)
1828 hde->dynamic_len = size;
1829 } else {
1830 offset = field->offset;
1831 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001832
1833 update_dynamic_len(hde, a);
1834 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001835 }
1836
1837 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1838}
1839
Namhyung Kim361459f2015-12-23 02:07:08 +09001840bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1841{
1842 return fmt->cmp == __sort__hde_cmp;
1843}
1844
Jiri Olsa564132f2016-01-18 10:24:09 +01001845static void hde_free(struct perf_hpp_fmt *fmt)
1846{
1847 struct hpp_dynamic_entry *hde;
1848
1849 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1850 free(hde);
1851}
1852
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001853static struct hpp_dynamic_entry *
1854__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1855{
1856 struct hpp_dynamic_entry *hde;
1857
1858 hde = malloc(sizeof(*hde));
1859 if (hde == NULL) {
1860 pr_debug("Memory allocation failed\n");
1861 return NULL;
1862 }
1863
1864 hde->evsel = evsel;
1865 hde->field = field;
1866 hde->dynamic_len = 0;
1867
1868 hde->hpp.name = field->name;
1869 hde->hpp.header = __sort__hde_header;
1870 hde->hpp.width = __sort__hde_width;
1871 hde->hpp.entry = __sort__hde_entry;
1872 hde->hpp.color = NULL;
1873
1874 hde->hpp.cmp = __sort__hde_cmp;
1875 hde->hpp.collapse = __sort__hde_cmp;
1876 hde->hpp.sort = __sort__hde_cmp;
Jiri Olsa564132f2016-01-18 10:24:09 +01001877 hde->hpp.free = hde_free;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001878
1879 INIT_LIST_HEAD(&hde->hpp.list);
1880 INIT_LIST_HEAD(&hde->hpp.sort_list);
1881 hde->hpp.elide = false;
1882 hde->hpp.len = 0;
1883 hde->hpp.user_len = 0;
1884
1885 return hde;
1886}
1887
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001888static int parse_field_name(char *str, char **event, char **field, char **opt)
1889{
1890 char *event_name, *field_name, *opt_name;
1891
1892 event_name = str;
1893 field_name = strchr(str, '.');
1894
1895 if (field_name) {
1896 *field_name++ = '\0';
1897 } else {
1898 event_name = NULL;
1899 field_name = str;
1900 }
1901
1902 opt_name = strchr(field_name, '/');
1903 if (opt_name)
1904 *opt_name++ = '\0';
1905
1906 *event = event_name;
1907 *field = field_name;
1908 *opt = opt_name;
1909
1910 return 0;
1911}
1912
1913/* find match evsel using a given event name. The event name can be:
Namhyung Kim9735be22016-01-05 19:58:35 +09001914 * 1. '%' + event index (e.g. '%1' for first event)
1915 * 2. full event name (e.g. sched:sched_switch)
1916 * 3. partial event name (should not contain ':')
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001917 */
1918static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1919{
1920 struct perf_evsel *evsel = NULL;
1921 struct perf_evsel *pos;
1922 bool full_name;
1923
1924 /* case 1 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001925 if (event_name[0] == '%') {
1926 int nr = strtol(event_name+1, NULL, 0);
1927
1928 if (nr > evlist->nr_entries)
1929 return NULL;
1930
1931 evsel = perf_evlist__first(evlist);
1932 while (--nr > 0)
1933 evsel = perf_evsel__next(evsel);
1934
1935 return evsel;
1936 }
1937
1938 full_name = !!strchr(event_name, ':');
1939 evlist__for_each(evlist, pos) {
Namhyung Kim9735be22016-01-05 19:58:35 +09001940 /* case 2 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001941 if (full_name && !strcmp(pos->name, event_name))
1942 return pos;
Namhyung Kim9735be22016-01-05 19:58:35 +09001943 /* case 3 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001944 if (!full_name && strstr(pos->name, event_name)) {
1945 if (evsel) {
1946 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1947 event_name, evsel->name, pos->name);
1948 return NULL;
1949 }
1950 evsel = pos;
1951 }
1952 }
1953
1954 return evsel;
1955}
1956
Namhyung Kim3b099bf52015-12-23 02:07:07 +09001957static int __dynamic_dimension__add(struct perf_evsel *evsel,
1958 struct format_field *field,
1959 bool raw_trace)
1960{
1961 struct hpp_dynamic_entry *hde;
1962
1963 hde = __alloc_dynamic_entry(evsel, field);
1964 if (hde == NULL)
1965 return -ENOMEM;
1966
1967 hde->raw_trace = raw_trace;
1968
1969 perf_hpp__register_sort_field(&hde->hpp);
1970 return 0;
1971}
1972
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001973static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1974{
1975 int ret;
1976 struct format_field *field;
1977
1978 field = evsel->tp_format->format.fields;
1979 while (field) {
1980 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1981 if (ret < 0)
1982 return ret;
1983
1984 field = field->next;
1985 }
1986 return 0;
1987}
1988
1989static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1990{
1991 int ret;
1992 struct perf_evsel *evsel;
1993
1994 evlist__for_each(evlist, evsel) {
1995 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1996 continue;
1997
1998 ret = add_evsel_fields(evsel, raw_trace);
1999 if (ret < 0)
2000 return ret;
2001 }
2002 return 0;
2003}
2004
Namhyung Kim9735be22016-01-05 19:58:35 +09002005static int add_all_matching_fields(struct perf_evlist *evlist,
2006 char *field_name, bool raw_trace)
2007{
2008 int ret = -ESRCH;
2009 struct perf_evsel *evsel;
2010 struct format_field *field;
2011
2012 evlist__for_each(evlist, evsel) {
2013 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2014 continue;
2015
2016 field = pevent_find_any_field(evsel->tp_format, field_name);
2017 if (field == NULL)
2018 continue;
2019
2020 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2021 if (ret < 0)
2022 break;
2023 }
2024 return ret;
2025}
2026
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002027static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2028{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002029 char *str, *event_name, *field_name, *opt_name;
2030 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002031 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09002032 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002033 int ret = 0;
2034
2035 if (evlist == NULL)
2036 return -ENOENT;
2037
2038 str = strdup(tok);
2039 if (str == NULL)
2040 return -ENOMEM;
2041
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002042 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002043 ret = -EINVAL;
2044 goto out;
2045 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002046
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002047 if (opt_name) {
2048 if (strcmp(opt_name, "raw")) {
2049 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09002050 ret = -EINVAL;
2051 goto out;
2052 }
2053 raw_trace = true;
2054 }
2055
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002056 if (!strcmp(field_name, "trace_fields")) {
2057 ret = add_all_dynamic_fields(evlist, raw_trace);
2058 goto out;
2059 }
2060
Namhyung Kim9735be22016-01-05 19:58:35 +09002061 if (event_name == NULL) {
2062 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2063 goto out;
2064 }
2065
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002066 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002067 if (evsel == NULL) {
2068 pr_debug("Cannot find event: %s\n", event_name);
2069 ret = -ENOENT;
2070 goto out;
2071 }
2072
2073 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2074 pr_debug("%s is not a tracepoint event\n", event_name);
2075 ret = -EINVAL;
2076 goto out;
2077 }
2078
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002079 if (!strcmp(field_name, "*")) {
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002080 ret = add_evsel_fields(evsel, raw_trace);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002081 } else {
2082 field = pevent_find_any_field(evsel->tp_format, field_name);
2083 if (field == NULL) {
2084 pr_debug("Cannot find event field for %s.%s\n",
2085 event_name, field_name);
2086 return -ENOENT;
2087 }
2088
2089 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2090 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002091
2092out:
2093 free(str);
2094 return ret;
2095}
2096
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002097static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002098{
2099 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002100 return 0;
2101
Namhyung Kima7d945b2014-03-04 10:46:34 +09002102 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002103 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002104
2105 if (sd->entry->se_collapse)
2106 sort__need_collapse = 1;
2107
Namhyung Kim2f532d092013-04-03 21:26:10 +09002108 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002109
2110 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002111}
2112
Namhyung Kima2ce0672014-03-04 09:06:42 +09002113static int __hpp_dimension__add(struct hpp_dimension *hd)
2114{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002115 struct perf_hpp_fmt *fmt;
Namhyung Kima2ce0672014-03-04 09:06:42 +09002116
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002117 if (hd->taken)
2118 return 0;
2119
2120 fmt = __hpp_dimension__alloc_hpp(hd);
2121 if (!fmt)
2122 return -1;
2123
2124 hd->taken = 1;
2125 perf_hpp__register_sort_field(fmt);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002126 return 0;
2127}
2128
Jiri Olsa07600022016-01-18 10:24:16 +01002129static int __sort_dimension__add_output(struct perf_hpp_list *list,
2130 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002131{
2132 if (sd->taken)
2133 return 0;
2134
Jiri Olsa07600022016-01-18 10:24:16 +01002135 if (__sort_dimension__add_hpp_output(list, sd) < 0)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002136 return -1;
2137
2138 sd->taken = 1;
2139 return 0;
2140}
2141
Jiri Olsa07600022016-01-18 10:24:16 +01002142static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2143 struct hpp_dimension *hd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002144{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002145 struct perf_hpp_fmt *fmt;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002146
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002147 if (hd->taken)
2148 return 0;
2149
2150 fmt = __hpp_dimension__alloc_hpp(hd);
2151 if (!fmt)
2152 return -1;
2153
2154 hd->taken = 1;
Jiri Olsa07600022016-01-18 10:24:16 +01002155 perf_hpp_list__column_register(list, fmt);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002156 return 0;
2157}
2158
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002159int hpp_dimension__add_output(unsigned col)
2160{
2161 BUG_ON(col >= PERF_HPP__MAX_INDEX);
Jiri Olsa07600022016-01-18 10:24:16 +01002162 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002163}
2164
Namhyung Kim40184c42015-12-23 02:07:01 +09002165static int sort_dimension__add(const char *tok,
2166 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02002167{
2168 unsigned int i;
2169
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002170 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2171 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002172
John Kacurdd68ada2009-09-24 18:02:49 +02002173 if (strncasecmp(tok, sd->name, strlen(tok)))
2174 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002175
John Kacurdd68ada2009-09-24 18:02:49 +02002176 if (sd->entry == &sort_parent) {
2177 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2178 if (ret) {
2179 char err[BUFSIZ];
2180
2181 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002182 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2183 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002184 }
2185 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002186 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09002187 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002188 /*
2189 * perf diff displays the performance difference amongst
2190 * two or more perf.data files. Those files could come
2191 * from different binaries. So we should not compare
2192 * their ips, but the name of symbol.
2193 */
2194 if (sort__mode == SORT_MODE__DIFF)
2195 sd->entry->se_collapse = sort__sym_sort;
2196
Namhyung Kim68f6d022013-12-18 14:21:10 +09002197 } else if (sd->entry == &sort_dso) {
2198 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002199 } else if (sd->entry == &sort_socket) {
2200 sort__has_socket = 1;
Namhyung Kimcfd92da2016-01-21 19:13:24 -03002201 } else if (sd->entry == &sort_thread) {
2202 sort__has_thread = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002203 }
2204
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002205 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02002206 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002207
Namhyung Kima2ce0672014-03-04 09:06:42 +09002208 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2209 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2210
2211 if (strncasecmp(tok, hd->name, strlen(tok)))
2212 continue;
2213
2214 return __hpp_dimension__add(hd);
2215 }
2216
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002217 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2218 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2219
2220 if (strncasecmp(tok, sd->name, strlen(tok)))
2221 continue;
2222
Namhyung Kim55369fc2013-04-01 20:35:20 +09002223 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002224 return -EINVAL;
2225
2226 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2227 sort__has_sym = 1;
2228
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002229 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002230 return 0;
2231 }
2232
Namhyung Kimafab87b2013-04-03 21:26:11 +09002233 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2234 struct sort_dimension *sd = &memory_sort_dimensions[i];
2235
2236 if (strncasecmp(tok, sd->name, strlen(tok)))
2237 continue;
2238
2239 if (sort__mode != SORT_MODE__MEMORY)
2240 return -EINVAL;
2241
2242 if (sd->entry == &sort_mem_daddr_sym)
2243 sort__has_sym = 1;
2244
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002245 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002246 return 0;
2247 }
2248
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002249 if (!add_dynamic_entry(evlist, tok))
2250 return 0;
2251
John Kacurdd68ada2009-09-24 18:02:49 +02002252 return -ESRCH;
2253}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002254
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002255static int setup_sort_list(char *str, struct perf_evlist *evlist)
2256{
2257 char *tmp, *tok;
2258 int ret = 0;
2259
2260 for (tok = strtok_r(str, ", ", &tmp);
2261 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2262 ret = sort_dimension__add(tok, evlist);
2263 if (ret == -EINVAL) {
2264 error("Invalid --sort key: `%s'", tok);
2265 break;
2266 } else if (ret == -ESRCH) {
2267 error("Unknown --sort key: `%s'", tok);
2268 break;
2269 }
2270 }
2271
2272 return ret;
2273}
2274
Namhyung Kimd49dade2015-12-23 02:07:10 +09002275static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002276{
2277 const char *default_sort_orders[] = {
2278 default_sort_order,
2279 default_branch_sort_order,
2280 default_mem_sort_order,
2281 default_top_sort_order,
2282 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002283 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002284 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002285 bool use_trace = true;
2286 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002287
2288 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2289
Namhyung Kimd49dade2015-12-23 02:07:10 +09002290 if (evlist == NULL)
2291 goto out_no_evlist;
2292
2293 evlist__for_each(evlist, evsel) {
2294 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2295 use_trace = false;
2296 break;
2297 }
2298 }
2299
2300 if (use_trace) {
2301 sort__mode = SORT_MODE__TRACEPOINT;
2302 if (symbol_conf.raw_trace)
2303 return "trace_fields";
2304 }
2305out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002306 return default_sort_orders[sort__mode];
2307}
2308
Namhyung Kimd49dade2015-12-23 02:07:10 +09002309static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002310{
2311 char *new_sort_order;
2312
2313 /*
2314 * Append '+'-prefixed sort order to the default sort
2315 * order string.
2316 */
2317 if (!sort_order || is_strict_order(sort_order))
2318 return 0;
2319
2320 if (sort_order[1] == '\0') {
2321 error("Invalid --sort key: `+'");
2322 return -EINVAL;
2323 }
2324
2325 /*
2326 * We allocate new sort_order string, but we never free it,
2327 * because it's checked over the rest of the code.
2328 */
2329 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002330 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002331 error("Not enough memory to set up --sort");
2332 return -ENOMEM;
2333 }
2334
2335 sort_order = new_sort_order;
2336 return 0;
2337}
2338
Jiri Olsab97511c2016-01-07 10:14:08 +01002339/*
2340 * Adds 'pre,' prefix into 'str' is 'pre' is
2341 * not already part of 'str'.
2342 */
2343static char *prefix_if_not_in(const char *pre, char *str)
2344{
2345 char *n;
2346
2347 if (!str || strstr(str, pre))
2348 return str;
2349
2350 if (asprintf(&n, "%s,%s", pre, str) < 0)
2351 return NULL;
2352
2353 free(str);
2354 return n;
2355}
2356
2357static char *setup_overhead(char *keys)
2358{
2359 keys = prefix_if_not_in("overhead", keys);
2360
2361 if (symbol_conf.cumulate_callchain)
2362 keys = prefix_if_not_in("overhead_children", keys);
2363
2364 return keys;
2365}
2366
Namhyung Kim40184c42015-12-23 02:07:01 +09002367static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002368{
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002369 char *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002370 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002371 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002372
Namhyung Kimd49dade2015-12-23 02:07:10 +09002373 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002374 if (ret)
2375 return ret;
2376
2377 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002378 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002379 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002380 /*
2381 * If user specified field order but no sort order,
2382 * we'll honor it and not add default sort orders.
2383 */
2384 return 0;
2385 }
2386
Namhyung Kimd49dade2015-12-23 02:07:10 +09002387 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002388 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002389
2390 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002391 if (str == NULL) {
2392 error("Not enough memory to setup sort keys");
2393 return -ENOMEM;
2394 }
2395
Jiri Olsab97511c2016-01-07 10:14:08 +01002396 /*
2397 * Prepend overhead fields for backward compatibility.
2398 */
2399 if (!is_strict_order(field_order)) {
2400 str = setup_overhead(str);
2401 if (str == NULL) {
2402 error("Not enough memory to setup overhead keys");
2403 return -ENOMEM;
2404 }
2405 }
2406
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002407 ret = setup_sort_list(str, evlist);
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002408
2409 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002410 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002411}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002412
Jiri Olsaf2998422014-05-23 17:15:47 +02002413void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002414{
Jiri Olsaf2998422014-05-23 17:15:47 +02002415 struct perf_hpp_fmt *fmt;
2416 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002417
Jiri Olsacf094042016-01-18 10:24:17 +01002418 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002419 if (!perf_hpp__is_sort_entry(fmt))
2420 continue;
2421
2422 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2423 if (hse->se->se_width_idx == idx) {
2424 fmt->elide = elide;
2425 break;
2426 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002427 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002428}
2429
Jiri Olsaf2998422014-05-23 17:15:47 +02002430static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002431{
2432 if (list && strlist__nr_entries(list) == 1) {
2433 if (fp != NULL)
2434 fprintf(fp, "# %s: %s\n", list_name,
2435 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002436 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002437 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002438 return false;
2439}
2440
2441static bool get_elide(int idx, FILE *output)
2442{
2443 switch (idx) {
2444 case HISTC_SYMBOL:
2445 return __get_elide(symbol_conf.sym_list, "symbol", output);
2446 case HISTC_DSO:
2447 return __get_elide(symbol_conf.dso_list, "dso", output);
2448 case HISTC_COMM:
2449 return __get_elide(symbol_conf.comm_list, "comm", output);
2450 default:
2451 break;
2452 }
2453
2454 if (sort__mode != SORT_MODE__BRANCH)
2455 return false;
2456
2457 switch (idx) {
2458 case HISTC_SYMBOL_FROM:
2459 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2460 case HISTC_SYMBOL_TO:
2461 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2462 case HISTC_DSO_FROM:
2463 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2464 case HISTC_DSO_TO:
2465 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2466 default:
2467 break;
2468 }
2469
2470 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002471}
Namhyung Kim08e71542013-04-03 21:26:19 +09002472
2473void sort__setup_elide(FILE *output)
2474{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002475 struct perf_hpp_fmt *fmt;
2476 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002477
Jiri Olsacf094042016-01-18 10:24:17 +01002478 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002479 if (!perf_hpp__is_sort_entry(fmt))
2480 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002481
Jiri Olsaf2998422014-05-23 17:15:47 +02002482 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2483 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002484 }
2485
Namhyung Kim7524f632013-11-08 17:53:42 +09002486 /*
2487 * It makes no sense to elide all of sort entries.
2488 * Just revert them to show up again.
2489 */
Jiri Olsacf094042016-01-18 10:24:17 +01002490 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002491 if (!perf_hpp__is_sort_entry(fmt))
2492 continue;
2493
Jiri Olsaf2998422014-05-23 17:15:47 +02002494 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002495 return;
2496 }
2497
Jiri Olsacf094042016-01-18 10:24:17 +01002498 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002499 if (!perf_hpp__is_sort_entry(fmt))
2500 continue;
2501
Jiri Olsaf2998422014-05-23 17:15:47 +02002502 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002503 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002504}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002505
Jiri Olsa07600022016-01-18 10:24:16 +01002506static int output_field_add(struct perf_hpp_list *list, char *tok)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002507{
2508 unsigned int i;
2509
2510 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2511 struct sort_dimension *sd = &common_sort_dimensions[i];
2512
2513 if (strncasecmp(tok, sd->name, strlen(tok)))
2514 continue;
2515
Jiri Olsa07600022016-01-18 10:24:16 +01002516 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002517 }
2518
2519 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2520 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2521
2522 if (strncasecmp(tok, hd->name, strlen(tok)))
2523 continue;
2524
Jiri Olsa07600022016-01-18 10:24:16 +01002525 return __hpp_dimension__add_output(list, hd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002526 }
2527
2528 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2529 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2530
2531 if (strncasecmp(tok, sd->name, strlen(tok)))
2532 continue;
2533
Jiri Olsa07600022016-01-18 10:24:16 +01002534 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002535 }
2536
2537 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2538 struct sort_dimension *sd = &memory_sort_dimensions[i];
2539
2540 if (strncasecmp(tok, sd->name, strlen(tok)))
2541 continue;
2542
Jiri Olsa07600022016-01-18 10:24:16 +01002543 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002544 }
2545
2546 return -ESRCH;
2547}
2548
Jiri Olsa07600022016-01-18 10:24:16 +01002549static int setup_output_list(struct perf_hpp_list *list, char *str)
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002550{
2551 char *tmp, *tok;
2552 int ret = 0;
2553
2554 for (tok = strtok_r(str, ", ", &tmp);
2555 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Jiri Olsa07600022016-01-18 10:24:16 +01002556 ret = output_field_add(list, tok);
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002557 if (ret == -EINVAL) {
2558 error("Invalid --fields key: `%s'", tok);
2559 break;
2560 } else if (ret == -ESRCH) {
2561 error("Unknown --fields key: `%s'", tok);
2562 break;
2563 }
2564 }
2565
2566 return ret;
2567}
2568
Namhyung Kima7d945b2014-03-04 10:46:34 +09002569static void reset_dimensions(void)
2570{
2571 unsigned int i;
2572
2573 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2574 common_sort_dimensions[i].taken = 0;
2575
2576 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2577 hpp_sort_dimensions[i].taken = 0;
2578
2579 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2580 bstack_sort_dimensions[i].taken = 0;
2581
2582 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2583 memory_sort_dimensions[i].taken = 0;
2584}
2585
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002586bool is_strict_order(const char *order)
2587{
2588 return order && (*order != '+');
2589}
2590
Namhyung Kima7d945b2014-03-04 10:46:34 +09002591static int __setup_output_field(void)
2592{
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002593 char *str, *strp;
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002594 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002595
2596 if (field_order == NULL)
2597 return 0;
2598
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002599 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002600 if (str == NULL) {
2601 error("Not enough memory to setup output fields");
2602 return -ENOMEM;
2603 }
2604
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002605 if (!is_strict_order(field_order))
2606 strp++;
2607
2608 if (!strlen(strp)) {
2609 error("Invalid --fields key: `+'");
2610 goto out;
2611 }
2612
Jiri Olsa07600022016-01-18 10:24:16 +01002613 ret = setup_output_list(&perf_hpp_list, strp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002614
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002615out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002616 free(str);
2617 return ret;
2618}
2619
Namhyung Kim40184c42015-12-23 02:07:01 +09002620int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002621{
2622 int err;
2623
Namhyung Kim40184c42015-12-23 02:07:01 +09002624 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002625 if (err < 0)
2626 return err;
2627
2628 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002629 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002630 if (err < 0)
2631 return err;
2632 }
2633
2634 reset_dimensions();
2635
2636 /*
2637 * perf diff doesn't use default hpp output fields.
2638 */
2639 if (sort__mode != SORT_MODE__DIFF)
2640 perf_hpp__init();
2641
2642 err = __setup_output_field();
2643 if (err < 0)
2644 return err;
2645
2646 /* copy sort keys to output fields */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002647 perf_hpp__setup_output_field(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002648 /* and then copy output fields to sort keys */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002649 perf_hpp__append_sort_keys(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002650
2651 return 0;
2652}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002653
2654void reset_output_field(void)
2655{
2656 sort__need_collapse = 0;
2657 sort__has_parent = 0;
2658 sort__has_sym = 0;
2659 sort__has_dso = 0;
2660
Namhyung Kimd69b2962014-05-23 10:59:01 +09002661 field_order = NULL;
2662 sort_order = NULL;
2663
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002664 reset_dimensions();
Jiri Olsa43e0a682016-01-18 10:24:21 +01002665 perf_hpp__reset_output_field(&perf_hpp_list);
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002666}