blob: 7daea71691df3f524800f9b572e0d0b3fa019ba6 [file] [log] [blame]
Don Zickus9b32ba72014-06-01 15:38:29 +02001#include <sys/mman.h>
John Kacurdd68ada2009-09-24 18:02:49 +02002#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03003#include "hist.h"
Namhyung Kim4dfced32013-09-13 16:28:57 +09004#include "comm.h"
Namhyung Kim08e71542013-04-03 21:26:19 +09005#include "symbol.h"
Namhyung Kim8b536992014-03-03 11:46:55 +09006#include "evsel.h"
Namhyung Kim40184c42015-12-23 02:07:01 +09007#include "evlist.h"
8#include <traceevent/event-parse.h>
John Kacurdd68ada2009-09-24 18:02:49 +02009
10regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -030011const char default_parent_pattern[] = "^sys_|^do_page_fault";
12const char *parent_pattern = default_parent_pattern;
13const char default_sort_order[] = "comm,dso,symbol";
Andi Kleen40997d62015-07-18 08:24:53 -070014const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090015const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
16const char default_top_sort_order[] = "dso,symbol";
17const char default_diff_sort_order[] = "dso,symbol";
Namhyung Kimd49dade2015-12-23 02:07:10 +090018const char default_tracepoint_sort_order[] = "trace";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090019const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090020const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080021regex_t ignore_callees_regex;
22int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020023int sort__need_collapse = 0;
24int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090025int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090026int sort__has_dso = 0;
Kan Liang2e7ea3a2015-09-04 10:45:43 -040027int sort__has_socket = 0;
Namhyung Kimcfd92da2016-01-21 19:13:24 -030028int sort__has_thread = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090029enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020030
Arnaldo Carvalho de Melo37d9bb52016-02-12 11:27:51 -030031/*
32 * Replaces all occurrences of a char used with the:
33 *
34 * -t, --field-separator
35 *
36 * option, that uses a special separator character and don't pad with spaces,
37 * replacing all occurances of this separator in symbol names (and other
38 * output) with a '.' character, that thus it's the only non valid separator.
39*/
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030040static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020041{
42 int n;
43 va_list ap;
44
45 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030046 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020047 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030048 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020049
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030050 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020051 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030052 if (sep == NULL)
53 break;
54 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020055 }
John Kacurdd68ada2009-09-24 18:02:49 +020056 }
57 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110058
59 if (n >= (int)size)
60 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020061 return n;
62}
63
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020064static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020065{
66 if (!l && !r)
67 return 0;
68 else if (!l)
69 return -1;
70 else
71 return 1;
72}
73
74/* --sort pid */
75
76static int64_t
77sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
78{
Adrian Hunter38051232013-07-04 16:20:31 +030079 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020080}
81
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030082static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030083 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020084{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020085 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090086
87 width = max(7U, width) - 6;
88 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
89 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020090}
91
Frederic Weisbecker872a8782011-06-29 03:14:52 +020092struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090093 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020094 .se_cmp = sort__thread_cmp,
95 .se_snprintf = hist_entry__thread_snprintf,
96 .se_width_idx = HISTC_THREAD,
97};
98
99/* --sort comm */
100
101static int64_t
102sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
103{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +0200104 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200105 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200106}
107
108static int64_t
109sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
110{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900111 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200112 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200113}
114
Namhyung Kim202e7a62014-03-04 11:01:41 +0900115static int64_t
116sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
117{
118 return strcmp(comm__str(right->comm), comm__str(left->comm));
119}
120
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300121static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300122 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200123{
Namhyung Kim5b591662014-07-31 14:47:38 +0900124 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200125}
126
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900127struct sort_entry sort_comm = {
128 .se_header = "Command",
129 .se_cmp = sort__comm_cmp,
130 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900131 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900132 .se_snprintf = hist_entry__comm_snprintf,
133 .se_width_idx = HISTC_COMM,
134};
135
136/* --sort dso */
137
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100138static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200139{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100140 struct dso *dso_l = map_l ? map_l->dso : NULL;
141 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300142 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200143
144 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900145 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200146
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300147 if (verbose) {
148 dso_name_l = dso_l->long_name;
149 dso_name_r = dso_r->long_name;
150 } else {
151 dso_name_l = dso_l->short_name;
152 dso_name_r = dso_r->short_name;
153 }
154
155 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200156}
157
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100158static int64_t
159sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200160{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900161 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100162}
163
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164static int _hist_entry__dso_snprintf(struct map *map, char *bf,
165 size_t size, unsigned int width)
166{
167 if (map && map->dso) {
168 const char *dso_name = !verbose ? map->dso->short_name :
169 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900170 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300171 }
John Kacurdd68ada2009-09-24 18:02:49 +0200172
Namhyung Kim5b591662014-07-31 14:47:38 +0900173 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200174}
175
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300176static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100177 size_t size, unsigned int width)
178{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300179 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100180}
181
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900182struct sort_entry sort_dso = {
183 .se_header = "Shared Object",
184 .se_cmp = sort__dso_cmp,
185 .se_snprintf = hist_entry__dso_snprintf,
186 .se_width_idx = HISTC_DSO,
187};
188
189/* --sort symbol */
190
Namhyung Kim2037be52013-12-18 14:21:09 +0900191static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
192{
193 return (int64_t)(right_ip - left_ip);
194}
195
Namhyung Kim51f27d12013-02-06 14:57:15 +0900196static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900197{
198 if (!sym_l || !sym_r)
199 return cmp_null(sym_l, sym_r);
200
201 if (sym_l == sym_r)
202 return 0;
203
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700204 if (sym_l->start != sym_r->start)
205 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700207 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900208}
209
210static int64_t
211sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
212{
Namhyung Kim09600e02013-10-15 11:01:56 +0900213 int64_t ret;
214
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900215 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900216 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900217
Namhyung Kim09600e02013-10-15 11:01:56 +0900218 /*
219 * comparing symbol address alone is not enough since it's a
220 * relative address within a dso.
221 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900222 if (!sort__has_dso) {
223 ret = sort__dso_cmp(left, right);
224 if (ret != 0)
225 return ret;
226 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900227
Namhyung Kim51f27d12013-02-06 14:57:15 +0900228 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900229}
230
Namhyung Kim202e7a62014-03-04 11:01:41 +0900231static int64_t
232sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
233{
234 if (!left->ms.sym || !right->ms.sym)
235 return cmp_null(left->ms.sym, right->ms.sym);
236
237 return strcmp(right->ms.sym->name, left->ms.sym->name);
238}
239
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100240static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
241 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900242 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100243{
244 size_t ret = 0;
245
246 if (verbose) {
247 char o = map ? dso__symtab_origin(map->dso) : '!';
248 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900249 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100250 }
251
252 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100253 if (sym && map) {
254 if (map->type == MAP__VARIABLE) {
255 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
256 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100257 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100258 } else {
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300259 ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
Stephane Eranian98a3b322013-01-24 16:10:35 +0100260 width - ret,
261 sym->name);
262 }
263 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100264 size_t len = BITS_PER_LONG / 4;
265 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
266 len, ip);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100267 }
268
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300269 return ret;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270}
271
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300272static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900273 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100274{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300275 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
276 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100277}
John Kacurdd68ada2009-09-24 18:02:49 +0200278
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200279struct sort_entry sort_sym = {
280 .se_header = "Symbol",
281 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900282 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200283 .se_snprintf = hist_entry__sym_snprintf,
284 .se_width_idx = HISTC_SYMBOL,
285};
John Kacurdd68ada2009-09-24 18:02:49 +0200286
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300287/* --sort srcline */
288
289static int64_t
290sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
291{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900292 if (!left->srcline) {
293 if (!left->ms.map)
294 left->srcline = SRCLINE_UNKNOWN;
295 else {
296 struct map *map = left->ms.map;
297 left->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800298 map__rip_2objdump(map, left->ip),
299 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900300 }
301 }
302 if (!right->srcline) {
303 if (!right->ms.map)
304 right->srcline = SRCLINE_UNKNOWN;
305 else {
306 struct map *map = right->ms.map;
307 right->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800308 map__rip_2objdump(map, right->ip),
309 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900310 }
311 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900312 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313}
314
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300315static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900316 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300317{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300318 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300319}
320
321struct sort_entry sort_srcline = {
322 .se_header = "Source:Line",
323 .se_cmp = sort__srcline_cmp,
324 .se_snprintf = hist_entry__srcline_snprintf,
325 .se_width_idx = HISTC_SRCLINE,
326};
327
Andi Kleen31191a82015-08-07 15:54:24 -0700328/* --sort srcfile */
329
330static char no_srcfile[1];
331
332static char *get_srcfile(struct hist_entry *e)
333{
334 char *sf, *p;
335 struct map *map = e->ms.map;
336
Andi Kleen2f84b422015-09-01 11:47:19 -0700337 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
338 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700339 if (!strcmp(sf, SRCLINE_UNKNOWN))
340 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700341 p = strchr(sf, ':');
342 if (p && *sf) {
343 *p = 0;
344 return sf;
345 }
346 free(sf);
347 return no_srcfile;
348}
349
350static int64_t
351sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
352{
353 if (!left->srcfile) {
354 if (!left->ms.map)
355 left->srcfile = no_srcfile;
356 else
357 left->srcfile = get_srcfile(left);
358 }
359 if (!right->srcfile) {
360 if (!right->ms.map)
361 right->srcfile = no_srcfile;
362 else
363 right->srcfile = get_srcfile(right);
364 }
365 return strcmp(right->srcfile, left->srcfile);
366}
367
368static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
369 size_t size, unsigned int width)
370{
371 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
372}
373
374struct sort_entry sort_srcfile = {
375 .se_header = "Source File",
376 .se_cmp = sort__srcfile_cmp,
377 .se_snprintf = hist_entry__srcfile_snprintf,
378 .se_width_idx = HISTC_SRCFILE,
379};
380
John Kacurdd68ada2009-09-24 18:02:49 +0200381/* --sort parent */
382
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200383static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200384sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
385{
386 struct symbol *sym_l = left->parent;
387 struct symbol *sym_r = right->parent;
388
389 if (!sym_l || !sym_r)
390 return cmp_null(sym_l, sym_r);
391
Namhyung Kim202e7a62014-03-04 11:01:41 +0900392 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200393}
394
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300395static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300396 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200397{
Namhyung Kim5b591662014-07-31 14:47:38 +0900398 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300399 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200400}
401
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200402struct sort_entry sort_parent = {
403 .se_header = "Parent symbol",
404 .se_cmp = sort__parent_cmp,
405 .se_snprintf = hist_entry__parent_snprintf,
406 .se_width_idx = HISTC_PARENT,
407};
408
Arun Sharmaf60f3592010-06-04 11:27:10 -0300409/* --sort cpu */
410
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200411static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300412sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
413{
414 return right->cpu - left->cpu;
415}
416
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300417static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
418 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300419{
Namhyung Kim5b591662014-07-31 14:47:38 +0900420 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300421}
422
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200423struct sort_entry sort_cpu = {
424 .se_header = "CPU",
425 .se_cmp = sort__cpu_cmp,
426 .se_snprintf = hist_entry__cpu_snprintf,
427 .se_width_idx = HISTC_CPU,
428};
429
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400430/* --sort socket */
431
432static int64_t
433sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
434{
435 return right->socket - left->socket;
436}
437
438static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
439 size_t size, unsigned int width)
440{
441 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
442}
443
444struct sort_entry sort_socket = {
445 .se_header = "Socket",
446 .se_cmp = sort__socket_cmp,
447 .se_snprintf = hist_entry__socket_snprintf,
448 .se_width_idx = HISTC_SOCKET,
449};
450
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900451/* --sort trace */
452
453static char *get_trace_output(struct hist_entry *he)
454{
455 struct trace_seq seq;
456 struct perf_evsel *evsel;
457 struct pevent_record rec = {
458 .data = he->raw_data,
459 .size = he->raw_size,
460 };
461
462 evsel = hists_to_evsel(he->hists);
463
464 trace_seq_init(&seq);
Namhyung Kim053a3982015-12-23 02:07:05 +0900465 if (symbol_conf.raw_trace) {
466 pevent_print_fields(&seq, he->raw_data, he->raw_size,
467 evsel->tp_format);
468 } else {
469 pevent_event_info(&seq, evsel->tp_format, &rec);
470 }
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900471 return seq.buffer;
472}
473
474static int64_t
475sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
476{
477 struct perf_evsel *evsel;
478
479 evsel = hists_to_evsel(left->hists);
480 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
481 return 0;
482
483 if (left->trace_output == NULL)
484 left->trace_output = get_trace_output(left);
485 if (right->trace_output == NULL)
486 right->trace_output = get_trace_output(right);
487
488 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
489 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
490
491 return strcmp(right->trace_output, left->trace_output);
492}
493
494static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
495 size_t size, unsigned int width)
496{
497 struct perf_evsel *evsel;
498
499 evsel = hists_to_evsel(he->hists);
500 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
501 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
502
503 if (he->trace_output == NULL)
504 he->trace_output = get_trace_output(he);
505 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
506}
507
508struct sort_entry sort_trace = {
509 .se_header = "Trace output",
510 .se_cmp = sort__trace_cmp,
511 .se_snprintf = hist_entry__trace_snprintf,
512 .se_width_idx = HISTC_TRACE,
513};
514
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900515/* sort keys for branch stacks */
516
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100517static int64_t
518sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
519{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200520 if (!left->branch_info || !right->branch_info)
521 return cmp_null(left->branch_info, right->branch_info);
522
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100523 return _sort__dso_cmp(left->branch_info->from.map,
524 right->branch_info->from.map);
525}
526
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300527static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100528 size_t size, unsigned int width)
529{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200530 if (he->branch_info)
531 return _hist_entry__dso_snprintf(he->branch_info->from.map,
532 bf, size, width);
533 else
534 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100535}
536
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100537static int64_t
538sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
539{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200540 if (!left->branch_info || !right->branch_info)
541 return cmp_null(left->branch_info, right->branch_info);
542
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100543 return _sort__dso_cmp(left->branch_info->to.map,
544 right->branch_info->to.map);
545}
546
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300547static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100548 size_t size, unsigned int width)
549{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200550 if (he->branch_info)
551 return _hist_entry__dso_snprintf(he->branch_info->to.map,
552 bf, size, width);
553 else
554 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100555}
556
557static int64_t
558sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
559{
560 struct addr_map_symbol *from_l = &left->branch_info->from;
561 struct addr_map_symbol *from_r = &right->branch_info->from;
562
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200563 if (!left->branch_info || !right->branch_info)
564 return cmp_null(left->branch_info, right->branch_info);
565
566 from_l = &left->branch_info->from;
567 from_r = &right->branch_info->from;
568
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100569 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900570 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100571
Namhyung Kim51f27d12013-02-06 14:57:15 +0900572 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100573}
574
575static int64_t
576sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
577{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200578 struct addr_map_symbol *to_l, *to_r;
579
580 if (!left->branch_info || !right->branch_info)
581 return cmp_null(left->branch_info, right->branch_info);
582
583 to_l = &left->branch_info->to;
584 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100585
586 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900587 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100588
Namhyung Kim51f27d12013-02-06 14:57:15 +0900589 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100590}
591
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300592static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900593 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100594{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200595 if (he->branch_info) {
596 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100597
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200598 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
599 he->level, bf, size, width);
600 }
601
602 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100603}
604
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300605static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900606 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100607{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200608 if (he->branch_info) {
609 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100610
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200611 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
612 he->level, bf, size, width);
613 }
614
615 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100616}
617
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900618struct sort_entry sort_dso_from = {
619 .se_header = "Source Shared Object",
620 .se_cmp = sort__dso_from_cmp,
621 .se_snprintf = hist_entry__dso_from_snprintf,
622 .se_width_idx = HISTC_DSO_FROM,
623};
624
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100625struct sort_entry sort_dso_to = {
626 .se_header = "Target Shared Object",
627 .se_cmp = sort__dso_to_cmp,
628 .se_snprintf = hist_entry__dso_to_snprintf,
629 .se_width_idx = HISTC_DSO_TO,
630};
631
632struct sort_entry sort_sym_from = {
633 .se_header = "Source Symbol",
634 .se_cmp = sort__sym_from_cmp,
635 .se_snprintf = hist_entry__sym_from_snprintf,
636 .se_width_idx = HISTC_SYMBOL_FROM,
637};
638
639struct sort_entry sort_sym_to = {
640 .se_header = "Target Symbol",
641 .se_cmp = sort__sym_to_cmp,
642 .se_snprintf = hist_entry__sym_to_snprintf,
643 .se_width_idx = HISTC_SYMBOL_TO,
644};
645
646static int64_t
647sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
648{
Jiri Olsa428560e2014-10-16 16:07:03 +0200649 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100650
Jiri Olsa428560e2014-10-16 16:07:03 +0200651 if (!left->branch_info || !right->branch_info)
652 return cmp_null(left->branch_info, right->branch_info);
653
654 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
655 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100656 return mp || p;
657}
658
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300659static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100660 size_t size, unsigned int width){
661 static const char *out = "N/A";
662
Jiri Olsa428560e2014-10-16 16:07:03 +0200663 if (he->branch_info) {
664 if (he->branch_info->flags.predicted)
665 out = "N";
666 else if (he->branch_info->flags.mispred)
667 out = "Y";
668 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100669
Namhyung Kim5b591662014-07-31 14:47:38 +0900670 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100671}
672
Andi Kleen0e332f02015-07-18 08:24:46 -0700673static int64_t
674sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
675{
676 return left->branch_info->flags.cycles -
677 right->branch_info->flags.cycles;
678}
679
680static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
681 size_t size, unsigned int width)
682{
683 if (he->branch_info->flags.cycles == 0)
684 return repsep_snprintf(bf, size, "%-*s", width, "-");
685 return repsep_snprintf(bf, size, "%-*hd", width,
686 he->branch_info->flags.cycles);
687}
688
689struct sort_entry sort_cycles = {
690 .se_header = "Basic Block Cycles",
691 .se_cmp = sort__cycles_cmp,
692 .se_snprintf = hist_entry__cycles_snprintf,
693 .se_width_idx = HISTC_CYCLES,
694};
695
Stephane Eranian98a3b322013-01-24 16:10:35 +0100696/* --sort daddr_sym */
697static int64_t
698sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
699{
700 uint64_t l = 0, r = 0;
701
702 if (left->mem_info)
703 l = left->mem_info->daddr.addr;
704 if (right->mem_info)
705 r = right->mem_info->daddr.addr;
706
707 return (int64_t)(r - l);
708}
709
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300710static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100711 size_t size, unsigned int width)
712{
713 uint64_t addr = 0;
714 struct map *map = NULL;
715 struct symbol *sym = NULL;
716
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300717 if (he->mem_info) {
718 addr = he->mem_info->daddr.addr;
719 map = he->mem_info->daddr.map;
720 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100721 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300722 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100723 width);
724}
725
726static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200727sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
728{
729 uint64_t l = 0, r = 0;
730
731 if (left->mem_info)
732 l = left->mem_info->iaddr.addr;
733 if (right->mem_info)
734 r = right->mem_info->iaddr.addr;
735
736 return (int64_t)(r - l);
737}
738
739static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
740 size_t size, unsigned int width)
741{
742 uint64_t addr = 0;
743 struct map *map = NULL;
744 struct symbol *sym = NULL;
745
746 if (he->mem_info) {
747 addr = he->mem_info->iaddr.addr;
748 map = he->mem_info->iaddr.map;
749 sym = he->mem_info->iaddr.sym;
750 }
751 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
752 width);
753}
754
755static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100756sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
757{
758 struct map *map_l = NULL;
759 struct map *map_r = NULL;
760
761 if (left->mem_info)
762 map_l = left->mem_info->daddr.map;
763 if (right->mem_info)
764 map_r = right->mem_info->daddr.map;
765
766 return _sort__dso_cmp(map_l, map_r);
767}
768
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300769static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100770 size_t size, unsigned int width)
771{
772 struct map *map = NULL;
773
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300774 if (he->mem_info)
775 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100776
777 return _hist_entry__dso_snprintf(map, bf, size, width);
778}
779
780static int64_t
781sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
782{
783 union perf_mem_data_src data_src_l;
784 union perf_mem_data_src data_src_r;
785
786 if (left->mem_info)
787 data_src_l = left->mem_info->data_src;
788 else
789 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
790
791 if (right->mem_info)
792 data_src_r = right->mem_info->data_src;
793 else
794 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
795
796 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
797}
798
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300799static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100800 size_t size, unsigned int width)
801{
802 const char *out;
803 u64 mask = PERF_MEM_LOCK_NA;
804
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300805 if (he->mem_info)
806 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100807
808 if (mask & PERF_MEM_LOCK_NA)
809 out = "N/A";
810 else if (mask & PERF_MEM_LOCK_LOCKED)
811 out = "Yes";
812 else
813 out = "No";
814
Arnaldo Carvalho de Melo89fee702016-02-11 17:14:13 -0300815 return repsep_snprintf(bf, size, "%.*s", width, out);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100816}
817
818static int64_t
819sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
820{
821 union perf_mem_data_src data_src_l;
822 union perf_mem_data_src data_src_r;
823
824 if (left->mem_info)
825 data_src_l = left->mem_info->data_src;
826 else
827 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
828
829 if (right->mem_info)
830 data_src_r = right->mem_info->data_src;
831 else
832 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
833
834 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
835}
836
837static const char * const tlb_access[] = {
838 "N/A",
839 "HIT",
840 "MISS",
841 "L1",
842 "L2",
843 "Walker",
844 "Fault",
845};
846#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
847
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300848static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100849 size_t size, unsigned int width)
850{
851 char out[64];
852 size_t sz = sizeof(out) - 1; /* -1 for null termination */
853 size_t l = 0, i;
854 u64 m = PERF_MEM_TLB_NA;
855 u64 hit, miss;
856
857 out[0] = '\0';
858
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300859 if (he->mem_info)
860 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100861
862 hit = m & PERF_MEM_TLB_HIT;
863 miss = m & PERF_MEM_TLB_MISS;
864
865 /* already taken care of */
866 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
867
868 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
869 if (!(m & 0x1))
870 continue;
871 if (l) {
872 strcat(out, " or ");
873 l += 4;
874 }
875 strncat(out, tlb_access[i], sz - l);
876 l += strlen(tlb_access[i]);
877 }
878 if (*out == '\0')
879 strcpy(out, "N/A");
880 if (hit)
881 strncat(out, " hit", sz - l);
882 if (miss)
883 strncat(out, " miss", sz - l);
884
885 return repsep_snprintf(bf, size, "%-*s", width, out);
886}
887
888static int64_t
889sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
890{
891 union perf_mem_data_src data_src_l;
892 union perf_mem_data_src data_src_r;
893
894 if (left->mem_info)
895 data_src_l = left->mem_info->data_src;
896 else
897 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
898
899 if (right->mem_info)
900 data_src_r = right->mem_info->data_src;
901 else
902 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
903
904 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
905}
906
907static const char * const mem_lvl[] = {
908 "N/A",
909 "HIT",
910 "MISS",
911 "L1",
912 "LFB",
913 "L2",
914 "L3",
915 "Local RAM",
916 "Remote RAM (1 hop)",
917 "Remote RAM (2 hops)",
918 "Remote Cache (1 hop)",
919 "Remote Cache (2 hops)",
920 "I/O",
921 "Uncached",
922};
923#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
924
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300925static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100926 size_t size, unsigned int width)
927{
928 char out[64];
929 size_t sz = sizeof(out) - 1; /* -1 for null termination */
930 size_t i, l = 0;
931 u64 m = PERF_MEM_LVL_NA;
932 u64 hit, miss;
933
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300934 if (he->mem_info)
935 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100936
937 out[0] = '\0';
938
939 hit = m & PERF_MEM_LVL_HIT;
940 miss = m & PERF_MEM_LVL_MISS;
941
942 /* already taken care of */
943 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
944
945 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
946 if (!(m & 0x1))
947 continue;
948 if (l) {
949 strcat(out, " or ");
950 l += 4;
951 }
952 strncat(out, mem_lvl[i], sz - l);
953 l += strlen(mem_lvl[i]);
954 }
955 if (*out == '\0')
956 strcpy(out, "N/A");
957 if (hit)
958 strncat(out, " hit", sz - l);
959 if (miss)
960 strncat(out, " miss", sz - l);
961
962 return repsep_snprintf(bf, size, "%-*s", width, out);
963}
964
965static int64_t
966sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
967{
968 union perf_mem_data_src data_src_l;
969 union perf_mem_data_src data_src_r;
970
971 if (left->mem_info)
972 data_src_l = left->mem_info->data_src;
973 else
974 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
975
976 if (right->mem_info)
977 data_src_r = right->mem_info->data_src;
978 else
979 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
980
981 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
982}
983
984static const char * const snoop_access[] = {
985 "N/A",
986 "None",
987 "Miss",
988 "Hit",
989 "HitM",
990};
991#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
992
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300993static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100994 size_t size, unsigned int width)
995{
996 char out[64];
997 size_t sz = sizeof(out) - 1; /* -1 for null termination */
998 size_t i, l = 0;
999 u64 m = PERF_MEM_SNOOP_NA;
1000
1001 out[0] = '\0';
1002
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001003 if (he->mem_info)
1004 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +01001005
1006 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1007 if (!(m & 0x1))
1008 continue;
1009 if (l) {
1010 strcat(out, " or ");
1011 l += 4;
1012 }
1013 strncat(out, snoop_access[i], sz - l);
1014 l += strlen(snoop_access[i]);
1015 }
1016
1017 if (*out == '\0')
1018 strcpy(out, "N/A");
1019
1020 return repsep_snprintf(bf, size, "%-*s", width, out);
1021}
1022
Don Zickus9b32ba72014-06-01 15:38:29 +02001023static inline u64 cl_address(u64 address)
1024{
1025 /* return the cacheline of the address */
1026 return (address & ~(cacheline_size - 1));
1027}
1028
1029static int64_t
1030sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1031{
1032 u64 l, r;
1033 struct map *l_map, *r_map;
1034
1035 if (!left->mem_info) return -1;
1036 if (!right->mem_info) return 1;
1037
1038 /* group event types together */
1039 if (left->cpumode > right->cpumode) return -1;
1040 if (left->cpumode < right->cpumode) return 1;
1041
1042 l_map = left->mem_info->daddr.map;
1043 r_map = right->mem_info->daddr.map;
1044
1045 /* if both are NULL, jump to sort on al_addr instead */
1046 if (!l_map && !r_map)
1047 goto addr;
1048
1049 if (!l_map) return -1;
1050 if (!r_map) return 1;
1051
1052 if (l_map->maj > r_map->maj) return -1;
1053 if (l_map->maj < r_map->maj) return 1;
1054
1055 if (l_map->min > r_map->min) return -1;
1056 if (l_map->min < r_map->min) return 1;
1057
1058 if (l_map->ino > r_map->ino) return -1;
1059 if (l_map->ino < r_map->ino) return 1;
1060
1061 if (l_map->ino_generation > r_map->ino_generation) return -1;
1062 if (l_map->ino_generation < r_map->ino_generation) return 1;
1063
1064 /*
1065 * Addresses with no major/minor numbers are assumed to be
1066 * anonymous in userspace. Sort those on pid then address.
1067 *
1068 * The kernel and non-zero major/minor mapped areas are
1069 * assumed to be unity mapped. Sort those on address.
1070 */
1071
1072 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1073 (!(l_map->flags & MAP_SHARED)) &&
1074 !l_map->maj && !l_map->min && !l_map->ino &&
1075 !l_map->ino_generation) {
1076 /* userspace anonymous */
1077
1078 if (left->thread->pid_ > right->thread->pid_) return -1;
1079 if (left->thread->pid_ < right->thread->pid_) return 1;
1080 }
1081
1082addr:
1083 /* al_addr does all the right addr - start + offset calculations */
1084 l = cl_address(left->mem_info->daddr.al_addr);
1085 r = cl_address(right->mem_info->daddr.al_addr);
1086
1087 if (l > r) return -1;
1088 if (l < r) return 1;
1089
1090 return 0;
1091}
1092
1093static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1094 size_t size, unsigned int width)
1095{
1096
1097 uint64_t addr = 0;
1098 struct map *map = NULL;
1099 struct symbol *sym = NULL;
1100 char level = he->level;
1101
1102 if (he->mem_info) {
1103 addr = cl_address(he->mem_info->daddr.al_addr);
1104 map = he->mem_info->daddr.map;
1105 sym = he->mem_info->daddr.sym;
1106
1107 /* print [s] for shared data mmaps */
1108 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1109 map && (map->type == MAP__VARIABLE) &&
1110 (map->flags & MAP_SHARED) &&
1111 (map->maj || map->min || map->ino ||
1112 map->ino_generation))
1113 level = 's';
1114 else if (!map)
1115 level = 'X';
1116 }
1117 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1118 width);
1119}
1120
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001121struct sort_entry sort_mispredict = {
1122 .se_header = "Branch Mispredicted",
1123 .se_cmp = sort__mispredict_cmp,
1124 .se_snprintf = hist_entry__mispredict_snprintf,
1125 .se_width_idx = HISTC_MISPREDICT,
1126};
1127
Andi Kleen05484292013-01-24 16:10:29 +01001128static u64 he_weight(struct hist_entry *he)
1129{
1130 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1131}
1132
1133static int64_t
1134sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1135{
1136 return he_weight(left) - he_weight(right);
1137}
1138
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001139static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001140 size_t size, unsigned int width)
1141{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001142 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001143}
1144
1145struct sort_entry sort_local_weight = {
1146 .se_header = "Local Weight",
1147 .se_cmp = sort__local_weight_cmp,
1148 .se_snprintf = hist_entry__local_weight_snprintf,
1149 .se_width_idx = HISTC_LOCAL_WEIGHT,
1150};
1151
1152static int64_t
1153sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1154{
1155 return left->stat.weight - right->stat.weight;
1156}
1157
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001158static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001159 size_t size, unsigned int width)
1160{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001161 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001162}
1163
1164struct sort_entry sort_global_weight = {
1165 .se_header = "Weight",
1166 .se_cmp = sort__global_weight_cmp,
1167 .se_snprintf = hist_entry__global_weight_snprintf,
1168 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1169};
1170
Stephane Eranian98a3b322013-01-24 16:10:35 +01001171struct sort_entry sort_mem_daddr_sym = {
1172 .se_header = "Data Symbol",
1173 .se_cmp = sort__daddr_cmp,
1174 .se_snprintf = hist_entry__daddr_snprintf,
1175 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1176};
1177
Don Zickus28e6db22015-10-05 20:06:07 +02001178struct sort_entry sort_mem_iaddr_sym = {
1179 .se_header = "Code Symbol",
1180 .se_cmp = sort__iaddr_cmp,
1181 .se_snprintf = hist_entry__iaddr_snprintf,
1182 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1183};
1184
Stephane Eranian98a3b322013-01-24 16:10:35 +01001185struct sort_entry sort_mem_daddr_dso = {
1186 .se_header = "Data Object",
1187 .se_cmp = sort__dso_daddr_cmp,
1188 .se_snprintf = hist_entry__dso_daddr_snprintf,
1189 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1190};
1191
1192struct sort_entry sort_mem_locked = {
1193 .se_header = "Locked",
1194 .se_cmp = sort__locked_cmp,
1195 .se_snprintf = hist_entry__locked_snprintf,
1196 .se_width_idx = HISTC_MEM_LOCKED,
1197};
1198
1199struct sort_entry sort_mem_tlb = {
1200 .se_header = "TLB access",
1201 .se_cmp = sort__tlb_cmp,
1202 .se_snprintf = hist_entry__tlb_snprintf,
1203 .se_width_idx = HISTC_MEM_TLB,
1204};
1205
1206struct sort_entry sort_mem_lvl = {
1207 .se_header = "Memory access",
1208 .se_cmp = sort__lvl_cmp,
1209 .se_snprintf = hist_entry__lvl_snprintf,
1210 .se_width_idx = HISTC_MEM_LVL,
1211};
1212
1213struct sort_entry sort_mem_snoop = {
1214 .se_header = "Snoop",
1215 .se_cmp = sort__snoop_cmp,
1216 .se_snprintf = hist_entry__snoop_snprintf,
1217 .se_width_idx = HISTC_MEM_SNOOP,
1218};
1219
Don Zickus9b32ba72014-06-01 15:38:29 +02001220struct sort_entry sort_mem_dcacheline = {
1221 .se_header = "Data Cacheline",
1222 .se_cmp = sort__dcacheline_cmp,
1223 .se_snprintf = hist_entry__dcacheline_snprintf,
1224 .se_width_idx = HISTC_MEM_DCACHELINE,
1225};
1226
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001227static int64_t
1228sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1229{
Jiri Olsa49f47442014-10-16 16:07:01 +02001230 if (!left->branch_info || !right->branch_info)
1231 return cmp_null(left->branch_info, right->branch_info);
1232
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001233 return left->branch_info->flags.abort !=
1234 right->branch_info->flags.abort;
1235}
1236
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001237static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001238 size_t size, unsigned int width)
1239{
Jiri Olsa49f47442014-10-16 16:07:01 +02001240 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001241
Jiri Olsa49f47442014-10-16 16:07:01 +02001242 if (he->branch_info) {
1243 if (he->branch_info->flags.abort)
1244 out = "A";
1245 else
1246 out = ".";
1247 }
1248
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001249 return repsep_snprintf(bf, size, "%-*s", width, out);
1250}
1251
1252struct sort_entry sort_abort = {
1253 .se_header = "Transaction abort",
1254 .se_cmp = sort__abort_cmp,
1255 .se_snprintf = hist_entry__abort_snprintf,
1256 .se_width_idx = HISTC_ABORT,
1257};
1258
1259static int64_t
1260sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1261{
Jiri Olsa0199d242014-10-16 16:07:02 +02001262 if (!left->branch_info || !right->branch_info)
1263 return cmp_null(left->branch_info, right->branch_info);
1264
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001265 return left->branch_info->flags.in_tx !=
1266 right->branch_info->flags.in_tx;
1267}
1268
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001269static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001270 size_t size, unsigned int width)
1271{
Jiri Olsa0199d242014-10-16 16:07:02 +02001272 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001273
Jiri Olsa0199d242014-10-16 16:07:02 +02001274 if (he->branch_info) {
1275 if (he->branch_info->flags.in_tx)
1276 out = "T";
1277 else
1278 out = ".";
1279 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001280
1281 return repsep_snprintf(bf, size, "%-*s", width, out);
1282}
1283
1284struct sort_entry sort_in_tx = {
1285 .se_header = "Branch in transaction",
1286 .se_cmp = sort__in_tx_cmp,
1287 .se_snprintf = hist_entry__in_tx_snprintf,
1288 .se_width_idx = HISTC_IN_TX,
1289};
1290
Andi Kleen475eeab2013-09-20 07:40:43 -07001291static int64_t
1292sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1293{
1294 return left->transaction - right->transaction;
1295}
1296
1297static inline char *add_str(char *p, const char *str)
1298{
1299 strcpy(p, str);
1300 return p + strlen(str);
1301}
1302
1303static struct txbit {
1304 unsigned flag;
1305 const char *name;
1306 int skip_for_len;
1307} txbits[] = {
1308 { PERF_TXN_ELISION, "EL ", 0 },
1309 { PERF_TXN_TRANSACTION, "TX ", 1 },
1310 { PERF_TXN_SYNC, "SYNC ", 1 },
1311 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1312 { PERF_TXN_RETRY, "RETRY ", 0 },
1313 { PERF_TXN_CONFLICT, "CON ", 0 },
1314 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1315 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1316 { 0, NULL, 0 }
1317};
1318
1319int hist_entry__transaction_len(void)
1320{
1321 int i;
1322 int len = 0;
1323
1324 for (i = 0; txbits[i].name; i++) {
1325 if (!txbits[i].skip_for_len)
1326 len += strlen(txbits[i].name);
1327 }
1328 len += 4; /* :XX<space> */
1329 return len;
1330}
1331
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001332static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001333 size_t size, unsigned int width)
1334{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001335 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001336 char buf[128];
1337 char *p = buf;
1338 int i;
1339
1340 buf[0] = 0;
1341 for (i = 0; txbits[i].name; i++)
1342 if (txbits[i].flag & t)
1343 p = add_str(p, txbits[i].name);
1344 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1345 p = add_str(p, "NEITHER ");
1346 if (t & PERF_TXN_ABORT_MASK) {
1347 sprintf(p, ":%" PRIx64,
1348 (t & PERF_TXN_ABORT_MASK) >>
1349 PERF_TXN_ABORT_SHIFT);
1350 p += strlen(p);
1351 }
1352
1353 return repsep_snprintf(bf, size, "%-*s", width, buf);
1354}
1355
1356struct sort_entry sort_transaction = {
1357 .se_header = "Transaction ",
1358 .se_cmp = sort__transaction_cmp,
1359 .se_snprintf = hist_entry__transaction_snprintf,
1360 .se_width_idx = HISTC_TRANSACTION,
1361};
1362
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001363struct sort_dimension {
1364 const char *name;
1365 struct sort_entry *entry;
1366 int taken;
1367};
1368
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001369#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1370
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001371static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001372 DIM(SORT_PID, "pid", sort_thread),
1373 DIM(SORT_COMM, "comm", sort_comm),
1374 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001375 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001376 DIM(SORT_PARENT, "parent", sort_parent),
1377 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001378 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001379 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001380 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001381 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1382 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001383 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001384 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001385};
1386
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001387#undef DIM
1388
1389#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1390
1391static struct sort_dimension bstack_sort_dimensions[] = {
1392 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1393 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1394 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1395 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1396 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001397 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1398 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001399 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001400};
1401
1402#undef DIM
1403
Namhyung Kimafab87b2013-04-03 21:26:11 +09001404#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1405
1406static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001407 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001408 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001409 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1410 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1411 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1412 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1413 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001414 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001415};
1416
1417#undef DIM
1418
Namhyung Kima2ce0672014-03-04 09:06:42 +09001419struct hpp_dimension {
1420 const char *name;
1421 struct perf_hpp_fmt *fmt;
1422 int taken;
1423};
1424
1425#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1426
1427static struct hpp_dimension hpp_sort_dimensions[] = {
1428 DIM(PERF_HPP__OVERHEAD, "overhead"),
1429 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1430 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1431 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1432 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001433 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001434 DIM(PERF_HPP__SAMPLES, "sample"),
1435 DIM(PERF_HPP__PERIOD, "period"),
1436};
1437
1438#undef DIM
1439
Namhyung Kim8b536992014-03-03 11:46:55 +09001440struct hpp_sort_entry {
1441 struct perf_hpp_fmt hpp;
1442 struct sort_entry *se;
1443};
1444
Namhyung Kime0d66c72014-07-31 14:47:37 +09001445void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001446{
1447 struct hpp_sort_entry *hse;
1448
1449 if (!perf_hpp__is_sort_entry(fmt))
1450 return;
1451
1452 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001453 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001454}
1455
Namhyung Kim8b536992014-03-03 11:46:55 +09001456static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1457 struct perf_evsel *evsel)
1458{
1459 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001460 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001461
1462 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001463
Namhyung Kim5b591662014-07-31 14:47:38 +09001464 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001465 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001466
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001467 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001468}
1469
1470static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1471 struct perf_hpp *hpp __maybe_unused,
1472 struct perf_evsel *evsel)
1473{
1474 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001475 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001476
1477 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1478
Namhyung Kim5b591662014-07-31 14:47:38 +09001479 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001480 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001481
1482 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001483}
1484
1485static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1486 struct hist_entry *he)
1487{
1488 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001489 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001490
1491 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001492
1493 if (!len)
1494 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001495
1496 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1497}
1498
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001499static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1500 struct hist_entry *a, struct hist_entry *b)
1501{
1502 struct hpp_sort_entry *hse;
1503
1504 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1505 return hse->se->se_cmp(a, b);
1506}
1507
1508static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1509 struct hist_entry *a, struct hist_entry *b)
1510{
1511 struct hpp_sort_entry *hse;
1512 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1513
1514 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1515 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1516 return collapse_fn(a, b);
1517}
1518
1519static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1520 struct hist_entry *a, struct hist_entry *b)
1521{
1522 struct hpp_sort_entry *hse;
1523 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1524
1525 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1526 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1527 return sort_fn(a, b);
1528}
1529
Jiri Olsa97358082016-01-18 10:24:03 +01001530bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1531{
1532 return format->header == __sort__hpp_header;
1533}
1534
1535static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1536{
1537 struct hpp_sort_entry *hse_a;
1538 struct hpp_sort_entry *hse_b;
1539
1540 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1541 return false;
1542
1543 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1544 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1545
1546 return hse_a->se == hse_b->se;
1547}
1548
Jiri Olsa564132f2016-01-18 10:24:09 +01001549static void hse_free(struct perf_hpp_fmt *fmt)
1550{
1551 struct hpp_sort_entry *hse;
1552
1553 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1554 free(hse);
1555}
1556
Namhyung Kima7d945b2014-03-04 10:46:34 +09001557static struct hpp_sort_entry *
1558__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001559{
1560 struct hpp_sort_entry *hse;
1561
1562 hse = malloc(sizeof(*hse));
1563 if (hse == NULL) {
1564 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001565 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001566 }
1567
1568 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001569 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001570 hse->hpp.header = __sort__hpp_header;
1571 hse->hpp.width = __sort__hpp_width;
1572 hse->hpp.entry = __sort__hpp_entry;
1573 hse->hpp.color = NULL;
1574
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001575 hse->hpp.cmp = __sort__hpp_cmp;
1576 hse->hpp.collapse = __sort__hpp_collapse;
1577 hse->hpp.sort = __sort__hpp_sort;
Jiri Olsa97358082016-01-18 10:24:03 +01001578 hse->hpp.equal = __sort__hpp_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001579 hse->hpp.free = hse_free;
Namhyung Kim8b536992014-03-03 11:46:55 +09001580
1581 INIT_LIST_HEAD(&hse->hpp.list);
1582 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001583 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001584 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001585 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001586
Namhyung Kima7d945b2014-03-04 10:46:34 +09001587 return hse;
1588}
1589
Jiri Olsa564132f2016-01-18 10:24:09 +01001590static void hpp_free(struct perf_hpp_fmt *fmt)
1591{
1592 free(fmt);
1593}
1594
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001595static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
1596{
1597 struct perf_hpp_fmt *fmt;
1598
1599 fmt = memdup(hd->fmt, sizeof(*fmt));
1600 if (fmt) {
1601 INIT_LIST_HEAD(&fmt->list);
1602 INIT_LIST_HEAD(&fmt->sort_list);
Jiri Olsa564132f2016-01-18 10:24:09 +01001603 fmt->free = hpp_free;
Jiri Olsa1945c3e2016-01-18 10:24:07 +01001604 }
1605
1606 return fmt;
1607}
1608
Namhyung Kima7d945b2014-03-04 10:46:34 +09001609static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1610{
1611 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1612
1613 if (hse == NULL)
1614 return -1;
1615
Namhyung Kim8b536992014-03-03 11:46:55 +09001616 perf_hpp__register_sort_field(&hse->hpp);
1617 return 0;
1618}
1619
Jiri Olsa07600022016-01-18 10:24:16 +01001620static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
1621 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09001622{
1623 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1624
1625 if (hse == NULL)
1626 return -1;
1627
Jiri Olsa07600022016-01-18 10:24:16 +01001628 perf_hpp_list__column_register(list, &hse->hpp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001629 return 0;
1630}
1631
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001632struct hpp_dynamic_entry {
1633 struct perf_hpp_fmt hpp;
1634 struct perf_evsel *evsel;
1635 struct format_field *field;
1636 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001637 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001638};
1639
1640static int hde_width(struct hpp_dynamic_entry *hde)
1641{
1642 if (!hde->hpp.len) {
1643 int len = hde->dynamic_len;
1644 int namelen = strlen(hde->field->name);
1645 int fieldlen = hde->field->size;
1646
1647 if (namelen > len)
1648 len = namelen;
1649
1650 if (!(hde->field->flags & FIELD_IS_STRING)) {
1651 /* length for print hex numbers */
1652 fieldlen = hde->field->size * 2 + 2;
1653 }
1654 if (fieldlen > len)
1655 len = fieldlen;
1656
1657 hde->hpp.len = len;
1658 }
1659 return hde->hpp.len;
1660}
1661
Namhyung Kim60517d22015-12-23 02:07:03 +09001662static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1663 struct hist_entry *he)
1664{
1665 char *str, *pos;
1666 struct format_field *field = hde->field;
1667 size_t namelen;
1668 bool last = false;
1669
Namhyung Kim053a3982015-12-23 02:07:05 +09001670 if (hde->raw_trace)
1671 return;
1672
Namhyung Kim60517d22015-12-23 02:07:03 +09001673 /* parse pretty print result and update max length */
1674 if (!he->trace_output)
1675 he->trace_output = get_trace_output(he);
1676
1677 namelen = strlen(field->name);
1678 str = he->trace_output;
1679
1680 while (str) {
1681 pos = strchr(str, ' ');
1682 if (pos == NULL) {
1683 last = true;
1684 pos = str + strlen(str);
1685 }
1686
1687 if (!strncmp(str, field->name, namelen)) {
1688 size_t len;
1689
1690 str += namelen + 1;
1691 len = pos - str;
1692
1693 if (len > hde->dynamic_len)
1694 hde->dynamic_len = len;
1695 break;
1696 }
1697
1698 if (last)
1699 str = NULL;
1700 else
1701 str = pos + 1;
1702 }
1703}
1704
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001705static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1706 struct perf_evsel *evsel __maybe_unused)
1707{
1708 struct hpp_dynamic_entry *hde;
1709 size_t len = fmt->user_len;
1710
1711 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1712
1713 if (!len)
1714 len = hde_width(hde);
1715
1716 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1717}
1718
1719static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1720 struct perf_hpp *hpp __maybe_unused,
1721 struct perf_evsel *evsel __maybe_unused)
1722{
1723 struct hpp_dynamic_entry *hde;
1724 size_t len = fmt->user_len;
1725
1726 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1727
1728 if (!len)
1729 len = hde_width(hde);
1730
1731 return len;
1732}
1733
Namhyung Kim361459f2015-12-23 02:07:08 +09001734bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1735{
1736 struct hpp_dynamic_entry *hde;
1737
1738 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1739
1740 return hists_to_evsel(hists) == hde->evsel;
1741}
1742
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001743static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1744 struct hist_entry *he)
1745{
1746 struct hpp_dynamic_entry *hde;
1747 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001748 char *str, *pos;
1749 struct format_field *field;
1750 size_t namelen;
1751 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001752 int ret;
1753
1754 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1755
1756 if (!len)
1757 len = hde_width(hde);
1758
Namhyung Kim053a3982015-12-23 02:07:05 +09001759 if (hde->raw_trace)
1760 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001761
Namhyung Kim053a3982015-12-23 02:07:05 +09001762 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001763 namelen = strlen(field->name);
1764 str = he->trace_output;
1765
1766 while (str) {
1767 pos = strchr(str, ' ');
1768 if (pos == NULL) {
1769 last = true;
1770 pos = str + strlen(str);
1771 }
1772
1773 if (!strncmp(str, field->name, namelen)) {
1774 str += namelen + 1;
1775 str = strndup(str, pos - str);
1776
1777 if (str == NULL)
1778 return scnprintf(hpp->buf, hpp->size,
1779 "%*.*s", len, len, "ERROR");
1780 break;
1781 }
1782
1783 if (last)
1784 str = NULL;
1785 else
1786 str = pos + 1;
1787 }
1788
1789 if (str == NULL) {
1790 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001791raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001792 trace_seq_init(&seq);
1793 pevent_print_field(&seq, he->raw_data, hde->field);
1794 str = seq.buffer;
1795 }
1796
1797 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1798 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001799 return ret;
1800}
1801
1802static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1803 struct hist_entry *a, struct hist_entry *b)
1804{
1805 struct hpp_dynamic_entry *hde;
1806 struct format_field *field;
1807 unsigned offset, size;
1808
1809 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1810
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001811 field = hde->field;
1812 if (field->flags & FIELD_IS_DYNAMIC) {
1813 unsigned long long dyn;
1814
1815 pevent_read_number_field(field, a->raw_data, &dyn);
1816 offset = dyn & 0xffff;
1817 size = (dyn >> 16) & 0xffff;
1818
1819 /* record max width for output */
1820 if (size > hde->dynamic_len)
1821 hde->dynamic_len = size;
1822 } else {
1823 offset = field->offset;
1824 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001825
1826 update_dynamic_len(hde, a);
1827 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001828 }
1829
1830 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1831}
1832
Namhyung Kim361459f2015-12-23 02:07:08 +09001833bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1834{
1835 return fmt->cmp == __sort__hde_cmp;
1836}
1837
Namhyung Kim665aa752016-02-21 23:22:35 +09001838static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1839{
1840 struct hpp_dynamic_entry *hde_a;
1841 struct hpp_dynamic_entry *hde_b;
1842
1843 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
1844 return false;
1845
1846 hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
1847 hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
1848
1849 return hde_a->field == hde_b->field;
1850}
1851
Jiri Olsa564132f2016-01-18 10:24:09 +01001852static void hde_free(struct perf_hpp_fmt *fmt)
1853{
1854 struct hpp_dynamic_entry *hde;
1855
1856 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1857 free(hde);
1858}
1859
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001860static struct hpp_dynamic_entry *
1861__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1862{
1863 struct hpp_dynamic_entry *hde;
1864
1865 hde = malloc(sizeof(*hde));
1866 if (hde == NULL) {
1867 pr_debug("Memory allocation failed\n");
1868 return NULL;
1869 }
1870
1871 hde->evsel = evsel;
1872 hde->field = field;
1873 hde->dynamic_len = 0;
1874
1875 hde->hpp.name = field->name;
1876 hde->hpp.header = __sort__hde_header;
1877 hde->hpp.width = __sort__hde_width;
1878 hde->hpp.entry = __sort__hde_entry;
1879 hde->hpp.color = NULL;
1880
1881 hde->hpp.cmp = __sort__hde_cmp;
1882 hde->hpp.collapse = __sort__hde_cmp;
1883 hde->hpp.sort = __sort__hde_cmp;
Namhyung Kim665aa752016-02-21 23:22:35 +09001884 hde->hpp.equal = __sort__hde_equal;
Jiri Olsa564132f2016-01-18 10:24:09 +01001885 hde->hpp.free = hde_free;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001886
1887 INIT_LIST_HEAD(&hde->hpp.list);
1888 INIT_LIST_HEAD(&hde->hpp.sort_list);
1889 hde->hpp.elide = false;
1890 hde->hpp.len = 0;
1891 hde->hpp.user_len = 0;
1892
1893 return hde;
1894}
1895
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001896static int parse_field_name(char *str, char **event, char **field, char **opt)
1897{
1898 char *event_name, *field_name, *opt_name;
1899
1900 event_name = str;
1901 field_name = strchr(str, '.');
1902
1903 if (field_name) {
1904 *field_name++ = '\0';
1905 } else {
1906 event_name = NULL;
1907 field_name = str;
1908 }
1909
1910 opt_name = strchr(field_name, '/');
1911 if (opt_name)
1912 *opt_name++ = '\0';
1913
1914 *event = event_name;
1915 *field = field_name;
1916 *opt = opt_name;
1917
1918 return 0;
1919}
1920
1921/* find match evsel using a given event name. The event name can be:
Namhyung Kim9735be22016-01-05 19:58:35 +09001922 * 1. '%' + event index (e.g. '%1' for first event)
1923 * 2. full event name (e.g. sched:sched_switch)
1924 * 3. partial event name (should not contain ':')
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001925 */
1926static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1927{
1928 struct perf_evsel *evsel = NULL;
1929 struct perf_evsel *pos;
1930 bool full_name;
1931
1932 /* case 1 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001933 if (event_name[0] == '%') {
1934 int nr = strtol(event_name+1, NULL, 0);
1935
1936 if (nr > evlist->nr_entries)
1937 return NULL;
1938
1939 evsel = perf_evlist__first(evlist);
1940 while (--nr > 0)
1941 evsel = perf_evsel__next(evsel);
1942
1943 return evsel;
1944 }
1945
1946 full_name = !!strchr(event_name, ':');
1947 evlist__for_each(evlist, pos) {
Namhyung Kim9735be22016-01-05 19:58:35 +09001948 /* case 2 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001949 if (full_name && !strcmp(pos->name, event_name))
1950 return pos;
Namhyung Kim9735be22016-01-05 19:58:35 +09001951 /* case 3 */
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001952 if (!full_name && strstr(pos->name, event_name)) {
1953 if (evsel) {
1954 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1955 event_name, evsel->name, pos->name);
1956 return NULL;
1957 }
1958 evsel = pos;
1959 }
1960 }
1961
1962 return evsel;
1963}
1964
Namhyung Kim3b099bf52015-12-23 02:07:07 +09001965static int __dynamic_dimension__add(struct perf_evsel *evsel,
1966 struct format_field *field,
1967 bool raw_trace)
1968{
1969 struct hpp_dynamic_entry *hde;
1970
1971 hde = __alloc_dynamic_entry(evsel, field);
1972 if (hde == NULL)
1973 return -ENOMEM;
1974
1975 hde->raw_trace = raw_trace;
1976
1977 perf_hpp__register_sort_field(&hde->hpp);
1978 return 0;
1979}
1980
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001981static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1982{
1983 int ret;
1984 struct format_field *field;
1985
1986 field = evsel->tp_format->format.fields;
1987 while (field) {
1988 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1989 if (ret < 0)
1990 return ret;
1991
1992 field = field->next;
1993 }
1994 return 0;
1995}
1996
1997static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1998{
1999 int ret;
2000 struct perf_evsel *evsel;
2001
2002 evlist__for_each(evlist, evsel) {
2003 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2004 continue;
2005
2006 ret = add_evsel_fields(evsel, raw_trace);
2007 if (ret < 0)
2008 return ret;
2009 }
2010 return 0;
2011}
2012
Namhyung Kim9735be22016-01-05 19:58:35 +09002013static int add_all_matching_fields(struct perf_evlist *evlist,
2014 char *field_name, bool raw_trace)
2015{
2016 int ret = -ESRCH;
2017 struct perf_evsel *evsel;
2018 struct format_field *field;
2019
2020 evlist__for_each(evlist, evsel) {
2021 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2022 continue;
2023
2024 field = pevent_find_any_field(evsel->tp_format, field_name);
2025 if (field == NULL)
2026 continue;
2027
2028 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2029 if (ret < 0)
2030 break;
2031 }
2032 return ret;
2033}
2034
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002035static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
2036{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002037 char *str, *event_name, *field_name, *opt_name;
2038 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002039 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09002040 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002041 int ret = 0;
2042
2043 if (evlist == NULL)
2044 return -ENOENT;
2045
2046 str = strdup(tok);
2047 if (str == NULL)
2048 return -ENOMEM;
2049
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002050 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002051 ret = -EINVAL;
2052 goto out;
2053 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002054
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002055 if (opt_name) {
2056 if (strcmp(opt_name, "raw")) {
2057 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09002058 ret = -EINVAL;
2059 goto out;
2060 }
2061 raw_trace = true;
2062 }
2063
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002064 if (!strcmp(field_name, "trace_fields")) {
2065 ret = add_all_dynamic_fields(evlist, raw_trace);
2066 goto out;
2067 }
2068
Namhyung Kim9735be22016-01-05 19:58:35 +09002069 if (event_name == NULL) {
2070 ret = add_all_matching_fields(evlist, field_name, raw_trace);
2071 goto out;
2072 }
2073
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002074 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002075 if (evsel == NULL) {
2076 pr_debug("Cannot find event: %s\n", event_name);
2077 ret = -ENOENT;
2078 goto out;
2079 }
2080
2081 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2082 pr_debug("%s is not a tracepoint event\n", event_name);
2083 ret = -EINVAL;
2084 goto out;
2085 }
2086
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002087 if (!strcmp(field_name, "*")) {
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002088 ret = add_evsel_fields(evsel, raw_trace);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002089 } else {
2090 field = pevent_find_any_field(evsel->tp_format, field_name);
2091 if (field == NULL) {
2092 pr_debug("Cannot find event field for %s.%s\n",
2093 event_name, field_name);
2094 return -ENOENT;
2095 }
2096
2097 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2098 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002099
2100out:
2101 free(str);
2102 return ret;
2103}
2104
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002105static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002106{
2107 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002108 return 0;
2109
Namhyung Kima7d945b2014-03-04 10:46:34 +09002110 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002111 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002112
2113 if (sd->entry->se_collapse)
2114 sort__need_collapse = 1;
2115
Namhyung Kim2f532d092013-04-03 21:26:10 +09002116 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002117
2118 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002119}
2120
Namhyung Kima2ce0672014-03-04 09:06:42 +09002121static int __hpp_dimension__add(struct hpp_dimension *hd)
2122{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002123 struct perf_hpp_fmt *fmt;
Namhyung Kima2ce0672014-03-04 09:06:42 +09002124
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002125 if (hd->taken)
2126 return 0;
2127
2128 fmt = __hpp_dimension__alloc_hpp(hd);
2129 if (!fmt)
2130 return -1;
2131
2132 hd->taken = 1;
2133 perf_hpp__register_sort_field(fmt);
Namhyung Kima2ce0672014-03-04 09:06:42 +09002134 return 0;
2135}
2136
Jiri Olsa07600022016-01-18 10:24:16 +01002137static int __sort_dimension__add_output(struct perf_hpp_list *list,
2138 struct sort_dimension *sd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002139{
2140 if (sd->taken)
2141 return 0;
2142
Jiri Olsa07600022016-01-18 10:24:16 +01002143 if (__sort_dimension__add_hpp_output(list, sd) < 0)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002144 return -1;
2145
2146 sd->taken = 1;
2147 return 0;
2148}
2149
Jiri Olsa07600022016-01-18 10:24:16 +01002150static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2151 struct hpp_dimension *hd)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002152{
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002153 struct perf_hpp_fmt *fmt;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002154
Jiri Olsa1945c3e2016-01-18 10:24:07 +01002155 if (hd->taken)
2156 return 0;
2157
2158 fmt = __hpp_dimension__alloc_hpp(hd);
2159 if (!fmt)
2160 return -1;
2161
2162 hd->taken = 1;
Jiri Olsa07600022016-01-18 10:24:16 +01002163 perf_hpp_list__column_register(list, fmt);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002164 return 0;
2165}
2166
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002167int hpp_dimension__add_output(unsigned col)
2168{
2169 BUG_ON(col >= PERF_HPP__MAX_INDEX);
Jiri Olsa07600022016-01-18 10:24:16 +01002170 return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002171}
2172
Namhyung Kim40184c42015-12-23 02:07:01 +09002173static int sort_dimension__add(const char *tok,
2174 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02002175{
2176 unsigned int i;
2177
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002178 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2179 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002180
John Kacurdd68ada2009-09-24 18:02:49 +02002181 if (strncasecmp(tok, sd->name, strlen(tok)))
2182 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002183
John Kacurdd68ada2009-09-24 18:02:49 +02002184 if (sd->entry == &sort_parent) {
2185 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2186 if (ret) {
2187 char err[BUFSIZ];
2188
2189 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002190 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2191 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002192 }
2193 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002194 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09002195 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002196 /*
2197 * perf diff displays the performance difference amongst
2198 * two or more perf.data files. Those files could come
2199 * from different binaries. So we should not compare
2200 * their ips, but the name of symbol.
2201 */
2202 if (sort__mode == SORT_MODE__DIFF)
2203 sd->entry->se_collapse = sort__sym_sort;
2204
Namhyung Kim68f6d022013-12-18 14:21:10 +09002205 } else if (sd->entry == &sort_dso) {
2206 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002207 } else if (sd->entry == &sort_socket) {
2208 sort__has_socket = 1;
Namhyung Kimcfd92da2016-01-21 19:13:24 -03002209 } else if (sd->entry == &sort_thread) {
2210 sort__has_thread = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002211 }
2212
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002213 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02002214 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002215
Namhyung Kima2ce0672014-03-04 09:06:42 +09002216 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2217 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2218
2219 if (strncasecmp(tok, hd->name, strlen(tok)))
2220 continue;
2221
2222 return __hpp_dimension__add(hd);
2223 }
2224
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002225 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2226 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2227
2228 if (strncasecmp(tok, sd->name, strlen(tok)))
2229 continue;
2230
Namhyung Kim55369fc2013-04-01 20:35:20 +09002231 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002232 return -EINVAL;
2233
2234 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2235 sort__has_sym = 1;
2236
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002237 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002238 return 0;
2239 }
2240
Namhyung Kimafab87b2013-04-03 21:26:11 +09002241 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2242 struct sort_dimension *sd = &memory_sort_dimensions[i];
2243
2244 if (strncasecmp(tok, sd->name, strlen(tok)))
2245 continue;
2246
2247 if (sort__mode != SORT_MODE__MEMORY)
2248 return -EINVAL;
2249
2250 if (sd->entry == &sort_mem_daddr_sym)
2251 sort__has_sym = 1;
2252
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002253 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002254 return 0;
2255 }
2256
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002257 if (!add_dynamic_entry(evlist, tok))
2258 return 0;
2259
John Kacurdd68ada2009-09-24 18:02:49 +02002260 return -ESRCH;
2261}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002262
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002263static int setup_sort_list(char *str, struct perf_evlist *evlist)
2264{
2265 char *tmp, *tok;
2266 int ret = 0;
2267
2268 for (tok = strtok_r(str, ", ", &tmp);
2269 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2270 ret = sort_dimension__add(tok, evlist);
2271 if (ret == -EINVAL) {
2272 error("Invalid --sort key: `%s'", tok);
2273 break;
2274 } else if (ret == -ESRCH) {
2275 error("Unknown --sort key: `%s'", tok);
2276 break;
2277 }
2278 }
2279
2280 return ret;
2281}
2282
Namhyung Kimd49dade2015-12-23 02:07:10 +09002283static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002284{
2285 const char *default_sort_orders[] = {
2286 default_sort_order,
2287 default_branch_sort_order,
2288 default_mem_sort_order,
2289 default_top_sort_order,
2290 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002291 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002292 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002293 bool use_trace = true;
2294 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002295
2296 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2297
Namhyung Kimd49dade2015-12-23 02:07:10 +09002298 if (evlist == NULL)
2299 goto out_no_evlist;
2300
2301 evlist__for_each(evlist, evsel) {
2302 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2303 use_trace = false;
2304 break;
2305 }
2306 }
2307
2308 if (use_trace) {
2309 sort__mode = SORT_MODE__TRACEPOINT;
2310 if (symbol_conf.raw_trace)
2311 return "trace_fields";
2312 }
2313out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002314 return default_sort_orders[sort__mode];
2315}
2316
Namhyung Kimd49dade2015-12-23 02:07:10 +09002317static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002318{
2319 char *new_sort_order;
2320
2321 /*
2322 * Append '+'-prefixed sort order to the default sort
2323 * order string.
2324 */
2325 if (!sort_order || is_strict_order(sort_order))
2326 return 0;
2327
2328 if (sort_order[1] == '\0') {
2329 error("Invalid --sort key: `+'");
2330 return -EINVAL;
2331 }
2332
2333 /*
2334 * We allocate new sort_order string, but we never free it,
2335 * because it's checked over the rest of the code.
2336 */
2337 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002338 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002339 error("Not enough memory to set up --sort");
2340 return -ENOMEM;
2341 }
2342
2343 sort_order = new_sort_order;
2344 return 0;
2345}
2346
Jiri Olsab97511c2016-01-07 10:14:08 +01002347/*
2348 * Adds 'pre,' prefix into 'str' is 'pre' is
2349 * not already part of 'str'.
2350 */
2351static char *prefix_if_not_in(const char *pre, char *str)
2352{
2353 char *n;
2354
2355 if (!str || strstr(str, pre))
2356 return str;
2357
2358 if (asprintf(&n, "%s,%s", pre, str) < 0)
2359 return NULL;
2360
2361 free(str);
2362 return n;
2363}
2364
2365static char *setup_overhead(char *keys)
2366{
2367 keys = prefix_if_not_in("overhead", keys);
2368
2369 if (symbol_conf.cumulate_callchain)
2370 keys = prefix_if_not_in("overhead_children", keys);
2371
2372 return keys;
2373}
2374
Namhyung Kim40184c42015-12-23 02:07:01 +09002375static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002376{
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002377 char *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002378 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002379 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002380
Namhyung Kimd49dade2015-12-23 02:07:10 +09002381 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002382 if (ret)
2383 return ret;
2384
2385 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002386 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002387 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002388 /*
2389 * If user specified field order but no sort order,
2390 * we'll honor it and not add default sort orders.
2391 */
2392 return 0;
2393 }
2394
Namhyung Kimd49dade2015-12-23 02:07:10 +09002395 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002396 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002397
2398 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002399 if (str == NULL) {
2400 error("Not enough memory to setup sort keys");
2401 return -ENOMEM;
2402 }
2403
Jiri Olsab97511c2016-01-07 10:14:08 +01002404 /*
2405 * Prepend overhead fields for backward compatibility.
2406 */
2407 if (!is_strict_order(field_order)) {
2408 str = setup_overhead(str);
2409 if (str == NULL) {
2410 error("Not enough memory to setup overhead keys");
2411 return -ENOMEM;
2412 }
2413 }
2414
Jiri Olsa2fbaa392016-01-18 10:24:10 +01002415 ret = setup_sort_list(str, evlist);
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002416
2417 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002418 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002419}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002420
Jiri Olsaf2998422014-05-23 17:15:47 +02002421void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002422{
Jiri Olsaf2998422014-05-23 17:15:47 +02002423 struct perf_hpp_fmt *fmt;
2424 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002425
Jiri Olsacf094042016-01-18 10:24:17 +01002426 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002427 if (!perf_hpp__is_sort_entry(fmt))
2428 continue;
2429
2430 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2431 if (hse->se->se_width_idx == idx) {
2432 fmt->elide = elide;
2433 break;
2434 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002435 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002436}
2437
Jiri Olsaf2998422014-05-23 17:15:47 +02002438static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002439{
2440 if (list && strlist__nr_entries(list) == 1) {
2441 if (fp != NULL)
2442 fprintf(fp, "# %s: %s\n", list_name,
2443 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002444 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002445 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002446 return false;
2447}
2448
2449static bool get_elide(int idx, FILE *output)
2450{
2451 switch (idx) {
2452 case HISTC_SYMBOL:
2453 return __get_elide(symbol_conf.sym_list, "symbol", output);
2454 case HISTC_DSO:
2455 return __get_elide(symbol_conf.dso_list, "dso", output);
2456 case HISTC_COMM:
2457 return __get_elide(symbol_conf.comm_list, "comm", output);
2458 default:
2459 break;
2460 }
2461
2462 if (sort__mode != SORT_MODE__BRANCH)
2463 return false;
2464
2465 switch (idx) {
2466 case HISTC_SYMBOL_FROM:
2467 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2468 case HISTC_SYMBOL_TO:
2469 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2470 case HISTC_DSO_FROM:
2471 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2472 case HISTC_DSO_TO:
2473 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2474 default:
2475 break;
2476 }
2477
2478 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002479}
Namhyung Kim08e71542013-04-03 21:26:19 +09002480
2481void sort__setup_elide(FILE *output)
2482{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002483 struct perf_hpp_fmt *fmt;
2484 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002485
Jiri Olsacf094042016-01-18 10:24:17 +01002486 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Jiri Olsaf2998422014-05-23 17:15:47 +02002487 if (!perf_hpp__is_sort_entry(fmt))
2488 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002489
Jiri Olsaf2998422014-05-23 17:15:47 +02002490 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2491 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002492 }
2493
Namhyung Kim7524f632013-11-08 17:53:42 +09002494 /*
2495 * It makes no sense to elide all of sort entries.
2496 * Just revert them to show up again.
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 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002503 return;
2504 }
2505
Jiri Olsacf094042016-01-18 10:24:17 +01002506 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002507 if (!perf_hpp__is_sort_entry(fmt))
2508 continue;
2509
Jiri Olsaf2998422014-05-23 17:15:47 +02002510 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002511 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002512}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002513
Jiri Olsa07600022016-01-18 10:24:16 +01002514static int output_field_add(struct perf_hpp_list *list, char *tok)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002515{
2516 unsigned int i;
2517
2518 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2519 struct sort_dimension *sd = &common_sort_dimensions[i];
2520
2521 if (strncasecmp(tok, sd->name, strlen(tok)))
2522 continue;
2523
Jiri Olsa07600022016-01-18 10:24:16 +01002524 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002525 }
2526
2527 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2528 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2529
2530 if (strncasecmp(tok, hd->name, strlen(tok)))
2531 continue;
2532
Jiri Olsa07600022016-01-18 10:24:16 +01002533 return __hpp_dimension__add_output(list, hd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002534 }
2535
2536 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2537 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2538
2539 if (strncasecmp(tok, sd->name, strlen(tok)))
2540 continue;
2541
Jiri Olsa07600022016-01-18 10:24:16 +01002542 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002543 }
2544
2545 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2546 struct sort_dimension *sd = &memory_sort_dimensions[i];
2547
2548 if (strncasecmp(tok, sd->name, strlen(tok)))
2549 continue;
2550
Jiri Olsa07600022016-01-18 10:24:16 +01002551 return __sort_dimension__add_output(list, sd);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002552 }
2553
2554 return -ESRCH;
2555}
2556
Jiri Olsa07600022016-01-18 10:24:16 +01002557static int setup_output_list(struct perf_hpp_list *list, char *str)
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002558{
2559 char *tmp, *tok;
2560 int ret = 0;
2561
2562 for (tok = strtok_r(str, ", ", &tmp);
2563 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Jiri Olsa07600022016-01-18 10:24:16 +01002564 ret = output_field_add(list, tok);
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002565 if (ret == -EINVAL) {
2566 error("Invalid --fields key: `%s'", tok);
2567 break;
2568 } else if (ret == -ESRCH) {
2569 error("Unknown --fields key: `%s'", tok);
2570 break;
2571 }
2572 }
2573
2574 return ret;
2575}
2576
Namhyung Kima7d945b2014-03-04 10:46:34 +09002577static void reset_dimensions(void)
2578{
2579 unsigned int i;
2580
2581 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2582 common_sort_dimensions[i].taken = 0;
2583
2584 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2585 hpp_sort_dimensions[i].taken = 0;
2586
2587 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2588 bstack_sort_dimensions[i].taken = 0;
2589
2590 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2591 memory_sort_dimensions[i].taken = 0;
2592}
2593
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002594bool is_strict_order(const char *order)
2595{
2596 return order && (*order != '+');
2597}
2598
Namhyung Kima7d945b2014-03-04 10:46:34 +09002599static int __setup_output_field(void)
2600{
Jiri Olsa6d3375e2016-01-18 10:24:11 +01002601 char *str, *strp;
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002602 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002603
2604 if (field_order == NULL)
2605 return 0;
2606
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002607 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002608 if (str == NULL) {
2609 error("Not enough memory to setup output fields");
2610 return -ENOMEM;
2611 }
2612
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002613 if (!is_strict_order(field_order))
2614 strp++;
2615
2616 if (!strlen(strp)) {
2617 error("Invalid --fields key: `+'");
2618 goto out;
2619 }
2620
Jiri Olsa07600022016-01-18 10:24:16 +01002621 ret = setup_output_list(&perf_hpp_list, strp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002622
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002623out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002624 free(str);
2625 return ret;
2626}
2627
Namhyung Kim40184c42015-12-23 02:07:01 +09002628int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002629{
2630 int err;
2631
Namhyung Kim40184c42015-12-23 02:07:01 +09002632 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002633 if (err < 0)
2634 return err;
2635
2636 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002637 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002638 if (err < 0)
2639 return err;
2640 }
2641
2642 reset_dimensions();
2643
2644 /*
2645 * perf diff doesn't use default hpp output fields.
2646 */
2647 if (sort__mode != SORT_MODE__DIFF)
2648 perf_hpp__init();
2649
2650 err = __setup_output_field();
2651 if (err < 0)
2652 return err;
2653
2654 /* copy sort keys to output fields */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002655 perf_hpp__setup_output_field(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002656 /* and then copy output fields to sort keys */
Jiri Olsa43e0a682016-01-18 10:24:21 +01002657 perf_hpp__append_sort_keys(&perf_hpp_list);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002658
2659 return 0;
2660}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002661
2662void reset_output_field(void)
2663{
2664 sort__need_collapse = 0;
2665 sort__has_parent = 0;
2666 sort__has_sym = 0;
2667 sort__has_dso = 0;
2668
Namhyung Kimd69b2962014-05-23 10:59:01 +09002669 field_order = NULL;
2670 sort_order = NULL;
2671
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002672 reset_dimensions();
Jiri Olsa43e0a682016-01-18 10:24:21 +01002673 perf_hpp__reset_output_field(&perf_hpp_list);
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002674}