blob: 4b4b1c5cccef3f56d2d06c79e5483f03a06d22cb [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 Kim55369fc2013-04-01 20:35:20 +090028enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020029
John Kacurdd68ada2009-09-24 18:02:49 +020030
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030031static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020032{
33 int n;
34 va_list ap;
35
36 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030037 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020038 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030039 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020040
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030041 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020042 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030043 if (sep == NULL)
44 break;
45 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020046 }
John Kacurdd68ada2009-09-24 18:02:49 +020047 }
48 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110049
50 if (n >= (int)size)
51 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020052 return n;
53}
54
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020055static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020056{
57 if (!l && !r)
58 return 0;
59 else if (!l)
60 return -1;
61 else
62 return 1;
63}
64
65/* --sort pid */
66
67static int64_t
68sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
69{
Adrian Hunter38051232013-07-04 16:20:31 +030070 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020071}
72
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030073static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030074 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020075{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020076 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090077
78 width = max(7U, width) - 6;
79 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
80 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020081}
82
Frederic Weisbecker872a8782011-06-29 03:14:52 +020083struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090084 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020085 .se_cmp = sort__thread_cmp,
86 .se_snprintf = hist_entry__thread_snprintf,
87 .se_width_idx = HISTC_THREAD,
88};
89
90/* --sort comm */
91
92static int64_t
93sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
94{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020095 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020096 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +020097}
98
99static int64_t
100sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
101{
Namhyung Kim4dfced32013-09-13 16:28:57 +0900102 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +0200103 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200104}
105
Namhyung Kim202e7a62014-03-04 11:01:41 +0900106static int64_t
107sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
108{
109 return strcmp(comm__str(right->comm), comm__str(left->comm));
110}
111
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300112static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300113 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200114{
Namhyung Kim5b591662014-07-31 14:47:38 +0900115 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200116}
117
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900118struct sort_entry sort_comm = {
119 .se_header = "Command",
120 .se_cmp = sort__comm_cmp,
121 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900122 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900123 .se_snprintf = hist_entry__comm_snprintf,
124 .se_width_idx = HISTC_COMM,
125};
126
127/* --sort dso */
128
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100129static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200130{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100131 struct dso *dso_l = map_l ? map_l->dso : NULL;
132 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300133 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200134
135 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900136 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200137
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300138 if (verbose) {
139 dso_name_l = dso_l->long_name;
140 dso_name_r = dso_r->long_name;
141 } else {
142 dso_name_l = dso_l->short_name;
143 dso_name_r = dso_r->short_name;
144 }
145
146 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200147}
148
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149static int64_t
150sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200151{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900152 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100153}
154
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100155static int _hist_entry__dso_snprintf(struct map *map, char *bf,
156 size_t size, unsigned int width)
157{
158 if (map && map->dso) {
159 const char *dso_name = !verbose ? map->dso->short_name :
160 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900161 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300162 }
John Kacurdd68ada2009-09-24 18:02:49 +0200163
Namhyung Kim5b591662014-07-31 14:47:38 +0900164 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200165}
166
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300167static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100168 size_t size, unsigned int width)
169{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300170 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100171}
172
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900173struct sort_entry sort_dso = {
174 .se_header = "Shared Object",
175 .se_cmp = sort__dso_cmp,
176 .se_snprintf = hist_entry__dso_snprintf,
177 .se_width_idx = HISTC_DSO,
178};
179
180/* --sort symbol */
181
Namhyung Kim2037be52013-12-18 14:21:09 +0900182static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
183{
184 return (int64_t)(right_ip - left_ip);
185}
186
Namhyung Kim51f27d12013-02-06 14:57:15 +0900187static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900188{
189 if (!sym_l || !sym_r)
190 return cmp_null(sym_l, sym_r);
191
192 if (sym_l == sym_r)
193 return 0;
194
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700195 if (sym_l->start != sym_r->start)
196 return (int64_t)(sym_r->start - sym_l->start);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900197
Yannick Brosseauc05676c2015-06-17 16:41:10 -0700198 return (int64_t)(sym_r->end - sym_l->end);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900199}
200
201static int64_t
202sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
203{
Namhyung Kim09600e02013-10-15 11:01:56 +0900204 int64_t ret;
205
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900207 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900208
Namhyung Kim09600e02013-10-15 11:01:56 +0900209 /*
210 * comparing symbol address alone is not enough since it's a
211 * relative address within a dso.
212 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900213 if (!sort__has_dso) {
214 ret = sort__dso_cmp(left, right);
215 if (ret != 0)
216 return ret;
217 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900218
Namhyung Kim51f27d12013-02-06 14:57:15 +0900219 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900220}
221
Namhyung Kim202e7a62014-03-04 11:01:41 +0900222static int64_t
223sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
224{
225 if (!left->ms.sym || !right->ms.sym)
226 return cmp_null(left->ms.sym, right->ms.sym);
227
228 return strcmp(right->ms.sym->name, left->ms.sym->name);
229}
230
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100231static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
232 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900233 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100234{
235 size_t ret = 0;
236
237 if (verbose) {
238 char o = map ? dso__symtab_origin(map->dso) : '!';
239 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900240 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100241 }
242
243 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100244 if (sym && map) {
245 if (map->type == MAP__VARIABLE) {
246 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
247 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100248 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
250 width - ret, "");
251 } else {
252 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
253 width - ret,
254 sym->name);
255 }
256 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100257 size_t len = BITS_PER_LONG / 4;
258 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
259 len, ip);
260 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
261 width - ret, "");
262 }
263
Namhyung Kim5b591662014-07-31 14:47:38 +0900264 if (ret > width)
265 bf[width] = '\0';
266
267 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100268}
269
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300270static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900271 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100272{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300273 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
274 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100275}
John Kacurdd68ada2009-09-24 18:02:49 +0200276
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200277struct sort_entry sort_sym = {
278 .se_header = "Symbol",
279 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900280 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200281 .se_snprintf = hist_entry__sym_snprintf,
282 .se_width_idx = HISTC_SYMBOL,
283};
John Kacurdd68ada2009-09-24 18:02:49 +0200284
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300285/* --sort srcline */
286
287static int64_t
288sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
289{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900290 if (!left->srcline) {
291 if (!left->ms.map)
292 left->srcline = SRCLINE_UNKNOWN;
293 else {
294 struct map *map = left->ms.map;
295 left->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800296 map__rip_2objdump(map, left->ip),
297 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900298 }
299 }
300 if (!right->srcline) {
301 if (!right->ms.map)
302 right->srcline = SRCLINE_UNKNOWN;
303 else {
304 struct map *map = right->ms.map;
305 right->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800306 map__rip_2objdump(map, right->ip),
307 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900308 }
309 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900310 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300311}
312
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300313static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900314 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300315{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300316 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300317}
318
319struct sort_entry sort_srcline = {
320 .se_header = "Source:Line",
321 .se_cmp = sort__srcline_cmp,
322 .se_snprintf = hist_entry__srcline_snprintf,
323 .se_width_idx = HISTC_SRCLINE,
324};
325
Andi Kleen31191a82015-08-07 15:54:24 -0700326/* --sort srcfile */
327
328static char no_srcfile[1];
329
330static char *get_srcfile(struct hist_entry *e)
331{
332 char *sf, *p;
333 struct map *map = e->ms.map;
334
Andi Kleen2f84b422015-09-01 11:47:19 -0700335 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
336 e->ms.sym, false, true);
Andi Kleen76b10652015-08-11 06:36:55 -0700337 if (!strcmp(sf, SRCLINE_UNKNOWN))
338 return no_srcfile;
Andi Kleen31191a82015-08-07 15:54:24 -0700339 p = strchr(sf, ':');
340 if (p && *sf) {
341 *p = 0;
342 return sf;
343 }
344 free(sf);
345 return no_srcfile;
346}
347
348static int64_t
349sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
350{
351 if (!left->srcfile) {
352 if (!left->ms.map)
353 left->srcfile = no_srcfile;
354 else
355 left->srcfile = get_srcfile(left);
356 }
357 if (!right->srcfile) {
358 if (!right->ms.map)
359 right->srcfile = no_srcfile;
360 else
361 right->srcfile = get_srcfile(right);
362 }
363 return strcmp(right->srcfile, left->srcfile);
364}
365
366static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
367 size_t size, unsigned int width)
368{
369 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile);
370}
371
372struct sort_entry sort_srcfile = {
373 .se_header = "Source File",
374 .se_cmp = sort__srcfile_cmp,
375 .se_snprintf = hist_entry__srcfile_snprintf,
376 .se_width_idx = HISTC_SRCFILE,
377};
378
John Kacurdd68ada2009-09-24 18:02:49 +0200379/* --sort parent */
380
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200381static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200382sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
383{
384 struct symbol *sym_l = left->parent;
385 struct symbol *sym_r = right->parent;
386
387 if (!sym_l || !sym_r)
388 return cmp_null(sym_l, sym_r);
389
Namhyung Kim202e7a62014-03-04 11:01:41 +0900390 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200391}
392
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300393static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300394 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200395{
Namhyung Kim5b591662014-07-31 14:47:38 +0900396 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300397 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200398}
399
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200400struct sort_entry sort_parent = {
401 .se_header = "Parent symbol",
402 .se_cmp = sort__parent_cmp,
403 .se_snprintf = hist_entry__parent_snprintf,
404 .se_width_idx = HISTC_PARENT,
405};
406
Arun Sharmaf60f3592010-06-04 11:27:10 -0300407/* --sort cpu */
408
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200409static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300410sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
411{
412 return right->cpu - left->cpu;
413}
414
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300415static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
416 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300417{
Namhyung Kim5b591662014-07-31 14:47:38 +0900418 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300419}
420
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200421struct sort_entry sort_cpu = {
422 .se_header = "CPU",
423 .se_cmp = sort__cpu_cmp,
424 .se_snprintf = hist_entry__cpu_snprintf,
425 .se_width_idx = HISTC_CPU,
426};
427
Kan Liang2e7ea3a2015-09-04 10:45:43 -0400428/* --sort socket */
429
430static int64_t
431sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
432{
433 return right->socket - left->socket;
434}
435
436static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
437 size_t size, unsigned int width)
438{
439 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
440}
441
442struct sort_entry sort_socket = {
443 .se_header = "Socket",
444 .se_cmp = sort__socket_cmp,
445 .se_snprintf = hist_entry__socket_snprintf,
446 .se_width_idx = HISTC_SOCKET,
447};
448
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900449/* --sort trace */
450
451static char *get_trace_output(struct hist_entry *he)
452{
453 struct trace_seq seq;
454 struct perf_evsel *evsel;
455 struct pevent_record rec = {
456 .data = he->raw_data,
457 .size = he->raw_size,
458 };
459
460 evsel = hists_to_evsel(he->hists);
461
462 trace_seq_init(&seq);
Namhyung Kim053a3982015-12-23 02:07:05 +0900463 if (symbol_conf.raw_trace) {
464 pevent_print_fields(&seq, he->raw_data, he->raw_size,
465 evsel->tp_format);
466 } else {
467 pevent_event_info(&seq, evsel->tp_format, &rec);
468 }
Namhyung Kima34bb6a2015-12-23 02:07:04 +0900469 return seq.buffer;
470}
471
472static int64_t
473sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 struct perf_evsel *evsel;
476
477 evsel = hists_to_evsel(left->hists);
478 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
479 return 0;
480
481 if (left->trace_output == NULL)
482 left->trace_output = get_trace_output(left);
483 if (right->trace_output == NULL)
484 right->trace_output = get_trace_output(right);
485
486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
488
489 return strcmp(right->trace_output, left->trace_output);
490}
491
492static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
493 size_t size, unsigned int width)
494{
495 struct perf_evsel *evsel;
496
497 evsel = hists_to_evsel(he->hists);
498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
500
501 if (he->trace_output == NULL)
502 he->trace_output = get_trace_output(he);
503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
504}
505
506struct sort_entry sort_trace = {
507 .se_header = "Trace output",
508 .se_cmp = sort__trace_cmp,
509 .se_snprintf = hist_entry__trace_snprintf,
510 .se_width_idx = HISTC_TRACE,
511};
512
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900513/* sort keys for branch stacks */
514
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100515static int64_t
516sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
517{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200518 if (!left->branch_info || !right->branch_info)
519 return cmp_null(left->branch_info, right->branch_info);
520
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100521 return _sort__dso_cmp(left->branch_info->from.map,
522 right->branch_info->from.map);
523}
524
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300525static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100526 size_t size, unsigned int width)
527{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200528 if (he->branch_info)
529 return _hist_entry__dso_snprintf(he->branch_info->from.map,
530 bf, size, width);
531 else
532 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100533}
534
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100535static int64_t
536sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
537{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200538 if (!left->branch_info || !right->branch_info)
539 return cmp_null(left->branch_info, right->branch_info);
540
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100541 return _sort__dso_cmp(left->branch_info->to.map,
542 right->branch_info->to.map);
543}
544
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300545static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100546 size_t size, unsigned int width)
547{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200548 if (he->branch_info)
549 return _hist_entry__dso_snprintf(he->branch_info->to.map,
550 bf, size, width);
551 else
552 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100553}
554
555static int64_t
556sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
557{
558 struct addr_map_symbol *from_l = &left->branch_info->from;
559 struct addr_map_symbol *from_r = &right->branch_info->from;
560
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200561 if (!left->branch_info || !right->branch_info)
562 return cmp_null(left->branch_info, right->branch_info);
563
564 from_l = &left->branch_info->from;
565 from_r = &right->branch_info->from;
566
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100567 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900568 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100569
Namhyung Kim51f27d12013-02-06 14:57:15 +0900570 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100571}
572
573static int64_t
574sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
575{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200576 struct addr_map_symbol *to_l, *to_r;
577
578 if (!left->branch_info || !right->branch_info)
579 return cmp_null(left->branch_info, right->branch_info);
580
581 to_l = &left->branch_info->to;
582 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100583
584 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900585 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100586
Namhyung Kim51f27d12013-02-06 14:57:15 +0900587 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100588}
589
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300590static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900591 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100592{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200593 if (he->branch_info) {
594 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100595
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200596 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
597 he->level, bf, size, width);
598 }
599
600 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100601}
602
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300603static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900604 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100605{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200606 if (he->branch_info) {
607 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100608
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200609 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
610 he->level, bf, size, width);
611 }
612
613 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100614}
615
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900616struct sort_entry sort_dso_from = {
617 .se_header = "Source Shared Object",
618 .se_cmp = sort__dso_from_cmp,
619 .se_snprintf = hist_entry__dso_from_snprintf,
620 .se_width_idx = HISTC_DSO_FROM,
621};
622
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100623struct sort_entry sort_dso_to = {
624 .se_header = "Target Shared Object",
625 .se_cmp = sort__dso_to_cmp,
626 .se_snprintf = hist_entry__dso_to_snprintf,
627 .se_width_idx = HISTC_DSO_TO,
628};
629
630struct sort_entry sort_sym_from = {
631 .se_header = "Source Symbol",
632 .se_cmp = sort__sym_from_cmp,
633 .se_snprintf = hist_entry__sym_from_snprintf,
634 .se_width_idx = HISTC_SYMBOL_FROM,
635};
636
637struct sort_entry sort_sym_to = {
638 .se_header = "Target Symbol",
639 .se_cmp = sort__sym_to_cmp,
640 .se_snprintf = hist_entry__sym_to_snprintf,
641 .se_width_idx = HISTC_SYMBOL_TO,
642};
643
644static int64_t
645sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
646{
Jiri Olsa428560e2014-10-16 16:07:03 +0200647 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100648
Jiri Olsa428560e2014-10-16 16:07:03 +0200649 if (!left->branch_info || !right->branch_info)
650 return cmp_null(left->branch_info, right->branch_info);
651
652 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
653 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100654 return mp || p;
655}
656
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300657static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100658 size_t size, unsigned int width){
659 static const char *out = "N/A";
660
Jiri Olsa428560e2014-10-16 16:07:03 +0200661 if (he->branch_info) {
662 if (he->branch_info->flags.predicted)
663 out = "N";
664 else if (he->branch_info->flags.mispred)
665 out = "Y";
666 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100667
Namhyung Kim5b591662014-07-31 14:47:38 +0900668 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100669}
670
Andi Kleen0e332f02015-07-18 08:24:46 -0700671static int64_t
672sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
673{
674 return left->branch_info->flags.cycles -
675 right->branch_info->flags.cycles;
676}
677
678static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
679 size_t size, unsigned int width)
680{
681 if (he->branch_info->flags.cycles == 0)
682 return repsep_snprintf(bf, size, "%-*s", width, "-");
683 return repsep_snprintf(bf, size, "%-*hd", width,
684 he->branch_info->flags.cycles);
685}
686
687struct sort_entry sort_cycles = {
688 .se_header = "Basic Block Cycles",
689 .se_cmp = sort__cycles_cmp,
690 .se_snprintf = hist_entry__cycles_snprintf,
691 .se_width_idx = HISTC_CYCLES,
692};
693
Stephane Eranian98a3b322013-01-24 16:10:35 +0100694/* --sort daddr_sym */
695static int64_t
696sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
697{
698 uint64_t l = 0, r = 0;
699
700 if (left->mem_info)
701 l = left->mem_info->daddr.addr;
702 if (right->mem_info)
703 r = right->mem_info->daddr.addr;
704
705 return (int64_t)(r - l);
706}
707
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300708static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100709 size_t size, unsigned int width)
710{
711 uint64_t addr = 0;
712 struct map *map = NULL;
713 struct symbol *sym = NULL;
714
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300715 if (he->mem_info) {
716 addr = he->mem_info->daddr.addr;
717 map = he->mem_info->daddr.map;
718 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100719 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300720 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100721 width);
722}
723
724static int64_t
Don Zickus28e6db22015-10-05 20:06:07 +0200725sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
726{
727 uint64_t l = 0, r = 0;
728
729 if (left->mem_info)
730 l = left->mem_info->iaddr.addr;
731 if (right->mem_info)
732 r = right->mem_info->iaddr.addr;
733
734 return (int64_t)(r - l);
735}
736
737static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
738 size_t size, unsigned int width)
739{
740 uint64_t addr = 0;
741 struct map *map = NULL;
742 struct symbol *sym = NULL;
743
744 if (he->mem_info) {
745 addr = he->mem_info->iaddr.addr;
746 map = he->mem_info->iaddr.map;
747 sym = he->mem_info->iaddr.sym;
748 }
749 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
750 width);
751}
752
753static int64_t
Stephane Eranian98a3b322013-01-24 16:10:35 +0100754sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
755{
756 struct map *map_l = NULL;
757 struct map *map_r = NULL;
758
759 if (left->mem_info)
760 map_l = left->mem_info->daddr.map;
761 if (right->mem_info)
762 map_r = right->mem_info->daddr.map;
763
764 return _sort__dso_cmp(map_l, map_r);
765}
766
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300767static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100768 size_t size, unsigned int width)
769{
770 struct map *map = NULL;
771
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300772 if (he->mem_info)
773 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100774
775 return _hist_entry__dso_snprintf(map, bf, size, width);
776}
777
778static int64_t
779sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
780{
781 union perf_mem_data_src data_src_l;
782 union perf_mem_data_src data_src_r;
783
784 if (left->mem_info)
785 data_src_l = left->mem_info->data_src;
786 else
787 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
788
789 if (right->mem_info)
790 data_src_r = right->mem_info->data_src;
791 else
792 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
793
794 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
795}
796
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300797static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100798 size_t size, unsigned int width)
799{
800 const char *out;
801 u64 mask = PERF_MEM_LOCK_NA;
802
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300803 if (he->mem_info)
804 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100805
806 if (mask & PERF_MEM_LOCK_NA)
807 out = "N/A";
808 else if (mask & PERF_MEM_LOCK_LOCKED)
809 out = "Yes";
810 else
811 out = "No";
812
813 return repsep_snprintf(bf, size, "%-*s", width, out);
814}
815
816static int64_t
817sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
818{
819 union perf_mem_data_src data_src_l;
820 union perf_mem_data_src data_src_r;
821
822 if (left->mem_info)
823 data_src_l = left->mem_info->data_src;
824 else
825 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
826
827 if (right->mem_info)
828 data_src_r = right->mem_info->data_src;
829 else
830 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
831
832 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
833}
834
835static const char * const tlb_access[] = {
836 "N/A",
837 "HIT",
838 "MISS",
839 "L1",
840 "L2",
841 "Walker",
842 "Fault",
843};
844#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
845
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300846static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100847 size_t size, unsigned int width)
848{
849 char out[64];
850 size_t sz = sizeof(out) - 1; /* -1 for null termination */
851 size_t l = 0, i;
852 u64 m = PERF_MEM_TLB_NA;
853 u64 hit, miss;
854
855 out[0] = '\0';
856
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300857 if (he->mem_info)
858 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100859
860 hit = m & PERF_MEM_TLB_HIT;
861 miss = m & PERF_MEM_TLB_MISS;
862
863 /* already taken care of */
864 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
865
866 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
867 if (!(m & 0x1))
868 continue;
869 if (l) {
870 strcat(out, " or ");
871 l += 4;
872 }
873 strncat(out, tlb_access[i], sz - l);
874 l += strlen(tlb_access[i]);
875 }
876 if (*out == '\0')
877 strcpy(out, "N/A");
878 if (hit)
879 strncat(out, " hit", sz - l);
880 if (miss)
881 strncat(out, " miss", sz - l);
882
883 return repsep_snprintf(bf, size, "%-*s", width, out);
884}
885
886static int64_t
887sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
888{
889 union perf_mem_data_src data_src_l;
890 union perf_mem_data_src data_src_r;
891
892 if (left->mem_info)
893 data_src_l = left->mem_info->data_src;
894 else
895 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
896
897 if (right->mem_info)
898 data_src_r = right->mem_info->data_src;
899 else
900 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
901
902 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
903}
904
905static const char * const mem_lvl[] = {
906 "N/A",
907 "HIT",
908 "MISS",
909 "L1",
910 "LFB",
911 "L2",
912 "L3",
913 "Local RAM",
914 "Remote RAM (1 hop)",
915 "Remote RAM (2 hops)",
916 "Remote Cache (1 hop)",
917 "Remote Cache (2 hops)",
918 "I/O",
919 "Uncached",
920};
921#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
922
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300923static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100924 size_t size, unsigned int width)
925{
926 char out[64];
927 size_t sz = sizeof(out) - 1; /* -1 for null termination */
928 size_t i, l = 0;
929 u64 m = PERF_MEM_LVL_NA;
930 u64 hit, miss;
931
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300932 if (he->mem_info)
933 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100934
935 out[0] = '\0';
936
937 hit = m & PERF_MEM_LVL_HIT;
938 miss = m & PERF_MEM_LVL_MISS;
939
940 /* already taken care of */
941 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
942
943 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
944 if (!(m & 0x1))
945 continue;
946 if (l) {
947 strcat(out, " or ");
948 l += 4;
949 }
950 strncat(out, mem_lvl[i], sz - l);
951 l += strlen(mem_lvl[i]);
952 }
953 if (*out == '\0')
954 strcpy(out, "N/A");
955 if (hit)
956 strncat(out, " hit", sz - l);
957 if (miss)
958 strncat(out, " miss", sz - l);
959
960 return repsep_snprintf(bf, size, "%-*s", width, out);
961}
962
963static int64_t
964sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
965{
966 union perf_mem_data_src data_src_l;
967 union perf_mem_data_src data_src_r;
968
969 if (left->mem_info)
970 data_src_l = left->mem_info->data_src;
971 else
972 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
973
974 if (right->mem_info)
975 data_src_r = right->mem_info->data_src;
976 else
977 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
978
979 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
980}
981
982static const char * const snoop_access[] = {
983 "N/A",
984 "None",
985 "Miss",
986 "Hit",
987 "HitM",
988};
989#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
990
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300991static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100992 size_t size, unsigned int width)
993{
994 char out[64];
995 size_t sz = sizeof(out) - 1; /* -1 for null termination */
996 size_t i, l = 0;
997 u64 m = PERF_MEM_SNOOP_NA;
998
999 out[0] = '\0';
1000
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001001 if (he->mem_info)
1002 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +01001003
1004 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
1005 if (!(m & 0x1))
1006 continue;
1007 if (l) {
1008 strcat(out, " or ");
1009 l += 4;
1010 }
1011 strncat(out, snoop_access[i], sz - l);
1012 l += strlen(snoop_access[i]);
1013 }
1014
1015 if (*out == '\0')
1016 strcpy(out, "N/A");
1017
1018 return repsep_snprintf(bf, size, "%-*s", width, out);
1019}
1020
Don Zickus9b32ba72014-06-01 15:38:29 +02001021static inline u64 cl_address(u64 address)
1022{
1023 /* return the cacheline of the address */
1024 return (address & ~(cacheline_size - 1));
1025}
1026
1027static int64_t
1028sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1029{
1030 u64 l, r;
1031 struct map *l_map, *r_map;
1032
1033 if (!left->mem_info) return -1;
1034 if (!right->mem_info) return 1;
1035
1036 /* group event types together */
1037 if (left->cpumode > right->cpumode) return -1;
1038 if (left->cpumode < right->cpumode) return 1;
1039
1040 l_map = left->mem_info->daddr.map;
1041 r_map = right->mem_info->daddr.map;
1042
1043 /* if both are NULL, jump to sort on al_addr instead */
1044 if (!l_map && !r_map)
1045 goto addr;
1046
1047 if (!l_map) return -1;
1048 if (!r_map) return 1;
1049
1050 if (l_map->maj > r_map->maj) return -1;
1051 if (l_map->maj < r_map->maj) return 1;
1052
1053 if (l_map->min > r_map->min) return -1;
1054 if (l_map->min < r_map->min) return 1;
1055
1056 if (l_map->ino > r_map->ino) return -1;
1057 if (l_map->ino < r_map->ino) return 1;
1058
1059 if (l_map->ino_generation > r_map->ino_generation) return -1;
1060 if (l_map->ino_generation < r_map->ino_generation) return 1;
1061
1062 /*
1063 * Addresses with no major/minor numbers are assumed to be
1064 * anonymous in userspace. Sort those on pid then address.
1065 *
1066 * The kernel and non-zero major/minor mapped areas are
1067 * assumed to be unity mapped. Sort those on address.
1068 */
1069
1070 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1071 (!(l_map->flags & MAP_SHARED)) &&
1072 !l_map->maj && !l_map->min && !l_map->ino &&
1073 !l_map->ino_generation) {
1074 /* userspace anonymous */
1075
1076 if (left->thread->pid_ > right->thread->pid_) return -1;
1077 if (left->thread->pid_ < right->thread->pid_) return 1;
1078 }
1079
1080addr:
1081 /* al_addr does all the right addr - start + offset calculations */
1082 l = cl_address(left->mem_info->daddr.al_addr);
1083 r = cl_address(right->mem_info->daddr.al_addr);
1084
1085 if (l > r) return -1;
1086 if (l < r) return 1;
1087
1088 return 0;
1089}
1090
1091static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1092 size_t size, unsigned int width)
1093{
1094
1095 uint64_t addr = 0;
1096 struct map *map = NULL;
1097 struct symbol *sym = NULL;
1098 char level = he->level;
1099
1100 if (he->mem_info) {
1101 addr = cl_address(he->mem_info->daddr.al_addr);
1102 map = he->mem_info->daddr.map;
1103 sym = he->mem_info->daddr.sym;
1104
1105 /* print [s] for shared data mmaps */
1106 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1107 map && (map->type == MAP__VARIABLE) &&
1108 (map->flags & MAP_SHARED) &&
1109 (map->maj || map->min || map->ino ||
1110 map->ino_generation))
1111 level = 's';
1112 else if (!map)
1113 level = 'X';
1114 }
1115 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1116 width);
1117}
1118
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001119struct sort_entry sort_mispredict = {
1120 .se_header = "Branch Mispredicted",
1121 .se_cmp = sort__mispredict_cmp,
1122 .se_snprintf = hist_entry__mispredict_snprintf,
1123 .se_width_idx = HISTC_MISPREDICT,
1124};
1125
Andi Kleen05484292013-01-24 16:10:29 +01001126static u64 he_weight(struct hist_entry *he)
1127{
1128 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1129}
1130
1131static int64_t
1132sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1133{
1134 return he_weight(left) - he_weight(right);
1135}
1136
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001137static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001138 size_t size, unsigned int width)
1139{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001140 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +01001141}
1142
1143struct sort_entry sort_local_weight = {
1144 .se_header = "Local Weight",
1145 .se_cmp = sort__local_weight_cmp,
1146 .se_snprintf = hist_entry__local_weight_snprintf,
1147 .se_width_idx = HISTC_LOCAL_WEIGHT,
1148};
1149
1150static int64_t
1151sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1152{
1153 return left->stat.weight - right->stat.weight;
1154}
1155
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001156static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +01001157 size_t size, unsigned int width)
1158{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001159 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +01001160}
1161
1162struct sort_entry sort_global_weight = {
1163 .se_header = "Weight",
1164 .se_cmp = sort__global_weight_cmp,
1165 .se_snprintf = hist_entry__global_weight_snprintf,
1166 .se_width_idx = HISTC_GLOBAL_WEIGHT,
1167};
1168
Stephane Eranian98a3b322013-01-24 16:10:35 +01001169struct sort_entry sort_mem_daddr_sym = {
1170 .se_header = "Data Symbol",
1171 .se_cmp = sort__daddr_cmp,
1172 .se_snprintf = hist_entry__daddr_snprintf,
1173 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1174};
1175
Don Zickus28e6db22015-10-05 20:06:07 +02001176struct sort_entry sort_mem_iaddr_sym = {
1177 .se_header = "Code Symbol",
1178 .se_cmp = sort__iaddr_cmp,
1179 .se_snprintf = hist_entry__iaddr_snprintf,
1180 .se_width_idx = HISTC_MEM_IADDR_SYMBOL,
1181};
1182
Stephane Eranian98a3b322013-01-24 16:10:35 +01001183struct sort_entry sort_mem_daddr_dso = {
1184 .se_header = "Data Object",
1185 .se_cmp = sort__dso_daddr_cmp,
1186 .se_snprintf = hist_entry__dso_daddr_snprintf,
1187 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
1188};
1189
1190struct sort_entry sort_mem_locked = {
1191 .se_header = "Locked",
1192 .se_cmp = sort__locked_cmp,
1193 .se_snprintf = hist_entry__locked_snprintf,
1194 .se_width_idx = HISTC_MEM_LOCKED,
1195};
1196
1197struct sort_entry sort_mem_tlb = {
1198 .se_header = "TLB access",
1199 .se_cmp = sort__tlb_cmp,
1200 .se_snprintf = hist_entry__tlb_snprintf,
1201 .se_width_idx = HISTC_MEM_TLB,
1202};
1203
1204struct sort_entry sort_mem_lvl = {
1205 .se_header = "Memory access",
1206 .se_cmp = sort__lvl_cmp,
1207 .se_snprintf = hist_entry__lvl_snprintf,
1208 .se_width_idx = HISTC_MEM_LVL,
1209};
1210
1211struct sort_entry sort_mem_snoop = {
1212 .se_header = "Snoop",
1213 .se_cmp = sort__snoop_cmp,
1214 .se_snprintf = hist_entry__snoop_snprintf,
1215 .se_width_idx = HISTC_MEM_SNOOP,
1216};
1217
Don Zickus9b32ba72014-06-01 15:38:29 +02001218struct sort_entry sort_mem_dcacheline = {
1219 .se_header = "Data Cacheline",
1220 .se_cmp = sort__dcacheline_cmp,
1221 .se_snprintf = hist_entry__dcacheline_snprintf,
1222 .se_width_idx = HISTC_MEM_DCACHELINE,
1223};
1224
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001225static int64_t
1226sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1227{
Jiri Olsa49f47442014-10-16 16:07:01 +02001228 if (!left->branch_info || !right->branch_info)
1229 return cmp_null(left->branch_info, right->branch_info);
1230
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001231 return left->branch_info->flags.abort !=
1232 right->branch_info->flags.abort;
1233}
1234
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001235static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001236 size_t size, unsigned int width)
1237{
Jiri Olsa49f47442014-10-16 16:07:01 +02001238 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001239
Jiri Olsa49f47442014-10-16 16:07:01 +02001240 if (he->branch_info) {
1241 if (he->branch_info->flags.abort)
1242 out = "A";
1243 else
1244 out = ".";
1245 }
1246
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001247 return repsep_snprintf(bf, size, "%-*s", width, out);
1248}
1249
1250struct sort_entry sort_abort = {
1251 .se_header = "Transaction abort",
1252 .se_cmp = sort__abort_cmp,
1253 .se_snprintf = hist_entry__abort_snprintf,
1254 .se_width_idx = HISTC_ABORT,
1255};
1256
1257static int64_t
1258sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1259{
Jiri Olsa0199d242014-10-16 16:07:02 +02001260 if (!left->branch_info || !right->branch_info)
1261 return cmp_null(left->branch_info, right->branch_info);
1262
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001263 return left->branch_info->flags.in_tx !=
1264 right->branch_info->flags.in_tx;
1265}
1266
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001267static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001268 size_t size, unsigned int width)
1269{
Jiri Olsa0199d242014-10-16 16:07:02 +02001270 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001271
Jiri Olsa0199d242014-10-16 16:07:02 +02001272 if (he->branch_info) {
1273 if (he->branch_info->flags.in_tx)
1274 out = "T";
1275 else
1276 out = ".";
1277 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001278
1279 return repsep_snprintf(bf, size, "%-*s", width, out);
1280}
1281
1282struct sort_entry sort_in_tx = {
1283 .se_header = "Branch in transaction",
1284 .se_cmp = sort__in_tx_cmp,
1285 .se_snprintf = hist_entry__in_tx_snprintf,
1286 .se_width_idx = HISTC_IN_TX,
1287};
1288
Andi Kleen475eeab2013-09-20 07:40:43 -07001289static int64_t
1290sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1291{
1292 return left->transaction - right->transaction;
1293}
1294
1295static inline char *add_str(char *p, const char *str)
1296{
1297 strcpy(p, str);
1298 return p + strlen(str);
1299}
1300
1301static struct txbit {
1302 unsigned flag;
1303 const char *name;
1304 int skip_for_len;
1305} txbits[] = {
1306 { PERF_TXN_ELISION, "EL ", 0 },
1307 { PERF_TXN_TRANSACTION, "TX ", 1 },
1308 { PERF_TXN_SYNC, "SYNC ", 1 },
1309 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1310 { PERF_TXN_RETRY, "RETRY ", 0 },
1311 { PERF_TXN_CONFLICT, "CON ", 0 },
1312 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1313 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1314 { 0, NULL, 0 }
1315};
1316
1317int hist_entry__transaction_len(void)
1318{
1319 int i;
1320 int len = 0;
1321
1322 for (i = 0; txbits[i].name; i++) {
1323 if (!txbits[i].skip_for_len)
1324 len += strlen(txbits[i].name);
1325 }
1326 len += 4; /* :XX<space> */
1327 return len;
1328}
1329
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001330static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001331 size_t size, unsigned int width)
1332{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001333 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001334 char buf[128];
1335 char *p = buf;
1336 int i;
1337
1338 buf[0] = 0;
1339 for (i = 0; txbits[i].name; i++)
1340 if (txbits[i].flag & t)
1341 p = add_str(p, txbits[i].name);
1342 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1343 p = add_str(p, "NEITHER ");
1344 if (t & PERF_TXN_ABORT_MASK) {
1345 sprintf(p, ":%" PRIx64,
1346 (t & PERF_TXN_ABORT_MASK) >>
1347 PERF_TXN_ABORT_SHIFT);
1348 p += strlen(p);
1349 }
1350
1351 return repsep_snprintf(bf, size, "%-*s", width, buf);
1352}
1353
1354struct sort_entry sort_transaction = {
1355 .se_header = "Transaction ",
1356 .se_cmp = sort__transaction_cmp,
1357 .se_snprintf = hist_entry__transaction_snprintf,
1358 .se_width_idx = HISTC_TRANSACTION,
1359};
1360
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001361struct sort_dimension {
1362 const char *name;
1363 struct sort_entry *entry;
1364 int taken;
1365};
1366
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001367#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1368
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001369static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001370 DIM(SORT_PID, "pid", sort_thread),
1371 DIM(SORT_COMM, "comm", sort_comm),
1372 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001373 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001374 DIM(SORT_PARENT, "parent", sort_parent),
1375 DIM(SORT_CPU, "cpu", sort_cpu),
Kan Liang2e7ea3a2015-09-04 10:45:43 -04001376 DIM(SORT_SOCKET, "socket", sort_socket),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001377 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen31191a82015-08-07 15:54:24 -07001378 DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001379 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1380 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001381 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Namhyung Kima34bb6a2015-12-23 02:07:04 +09001382 DIM(SORT_TRACE, "trace", sort_trace),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001383};
1384
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001385#undef DIM
1386
1387#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1388
1389static struct sort_dimension bstack_sort_dimensions[] = {
1390 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1391 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1392 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1393 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1394 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001395 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1396 DIM(SORT_ABORT, "abort", sort_abort),
Andi Kleen0e332f02015-07-18 08:24:46 -07001397 DIM(SORT_CYCLES, "cycles", sort_cycles),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001398};
1399
1400#undef DIM
1401
Namhyung Kimafab87b2013-04-03 21:26:11 +09001402#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1403
1404static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001405 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
Don Zickus28e6db22015-10-05 20:06:07 +02001406 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001407 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1408 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1409 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1410 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1411 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001412 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001413};
1414
1415#undef DIM
1416
Namhyung Kima2ce0672014-03-04 09:06:42 +09001417struct hpp_dimension {
1418 const char *name;
1419 struct perf_hpp_fmt *fmt;
1420 int taken;
1421};
1422
1423#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1424
1425static struct hpp_dimension hpp_sort_dimensions[] = {
1426 DIM(PERF_HPP__OVERHEAD, "overhead"),
1427 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1428 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1429 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1430 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001431 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001432 DIM(PERF_HPP__SAMPLES, "sample"),
1433 DIM(PERF_HPP__PERIOD, "period"),
1434};
1435
1436#undef DIM
1437
Namhyung Kim8b536992014-03-03 11:46:55 +09001438struct hpp_sort_entry {
1439 struct perf_hpp_fmt hpp;
1440 struct sort_entry *se;
1441};
1442
Namhyung Kima7d945b2014-03-04 10:46:34 +09001443bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1444{
1445 struct hpp_sort_entry *hse_a;
1446 struct hpp_sort_entry *hse_b;
1447
1448 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1449 return false;
1450
1451 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1452 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1453
1454 return hse_a->se == hse_b->se;
1455}
1456
Namhyung Kime0d66c72014-07-31 14:47:37 +09001457void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001458{
1459 struct hpp_sort_entry *hse;
1460
1461 if (!perf_hpp__is_sort_entry(fmt))
1462 return;
1463
1464 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001465 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001466}
1467
Namhyung Kim8b536992014-03-03 11:46:55 +09001468static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1469 struct perf_evsel *evsel)
1470{
1471 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001472 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001473
1474 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001475
Namhyung Kim5b591662014-07-31 14:47:38 +09001476 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001477 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001478
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001479 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001480}
1481
1482static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1483 struct perf_hpp *hpp __maybe_unused,
1484 struct perf_evsel *evsel)
1485{
1486 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001487 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001488
1489 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1490
Namhyung Kim5b591662014-07-31 14:47:38 +09001491 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001492 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001493
1494 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001495}
1496
1497static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1498 struct hist_entry *he)
1499{
1500 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001501 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001502
1503 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001504
1505 if (!len)
1506 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001507
1508 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1509}
1510
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001511static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1512 struct hist_entry *a, struct hist_entry *b)
1513{
1514 struct hpp_sort_entry *hse;
1515
1516 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1517 return hse->se->se_cmp(a, b);
1518}
1519
1520static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1521 struct hist_entry *a, struct hist_entry *b)
1522{
1523 struct hpp_sort_entry *hse;
1524 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1525
1526 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1527 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1528 return collapse_fn(a, b);
1529}
1530
1531static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1532 struct hist_entry *a, struct hist_entry *b)
1533{
1534 struct hpp_sort_entry *hse;
1535 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1536
1537 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1538 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1539 return sort_fn(a, b);
1540}
1541
Namhyung Kima7d945b2014-03-04 10:46:34 +09001542static struct hpp_sort_entry *
1543__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001544{
1545 struct hpp_sort_entry *hse;
1546
1547 hse = malloc(sizeof(*hse));
1548 if (hse == NULL) {
1549 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001550 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001551 }
1552
1553 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001554 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001555 hse->hpp.header = __sort__hpp_header;
1556 hse->hpp.width = __sort__hpp_width;
1557 hse->hpp.entry = __sort__hpp_entry;
1558 hse->hpp.color = NULL;
1559
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001560 hse->hpp.cmp = __sort__hpp_cmp;
1561 hse->hpp.collapse = __sort__hpp_collapse;
1562 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001563
1564 INIT_LIST_HEAD(&hse->hpp.list);
1565 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001566 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001567 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001568 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001569
Namhyung Kima7d945b2014-03-04 10:46:34 +09001570 return hse;
1571}
1572
1573bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1574{
1575 return format->header == __sort__hpp_header;
1576}
1577
1578static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1579{
1580 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1581
1582 if (hse == NULL)
1583 return -1;
1584
Namhyung Kim8b536992014-03-03 11:46:55 +09001585 perf_hpp__register_sort_field(&hse->hpp);
1586 return 0;
1587}
1588
Namhyung Kima7d945b2014-03-04 10:46:34 +09001589static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1590{
1591 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1592
1593 if (hse == NULL)
1594 return -1;
1595
1596 perf_hpp__column_register(&hse->hpp);
1597 return 0;
1598}
1599
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001600struct hpp_dynamic_entry {
1601 struct perf_hpp_fmt hpp;
1602 struct perf_evsel *evsel;
1603 struct format_field *field;
1604 unsigned dynamic_len;
Namhyung Kim053a3982015-12-23 02:07:05 +09001605 bool raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001606};
1607
1608static int hde_width(struct hpp_dynamic_entry *hde)
1609{
1610 if (!hde->hpp.len) {
1611 int len = hde->dynamic_len;
1612 int namelen = strlen(hde->field->name);
1613 int fieldlen = hde->field->size;
1614
1615 if (namelen > len)
1616 len = namelen;
1617
1618 if (!(hde->field->flags & FIELD_IS_STRING)) {
1619 /* length for print hex numbers */
1620 fieldlen = hde->field->size * 2 + 2;
1621 }
1622 if (fieldlen > len)
1623 len = fieldlen;
1624
1625 hde->hpp.len = len;
1626 }
1627 return hde->hpp.len;
1628}
1629
Namhyung Kim60517d22015-12-23 02:07:03 +09001630static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1631 struct hist_entry *he)
1632{
1633 char *str, *pos;
1634 struct format_field *field = hde->field;
1635 size_t namelen;
1636 bool last = false;
1637
Namhyung Kim053a3982015-12-23 02:07:05 +09001638 if (hde->raw_trace)
1639 return;
1640
Namhyung Kim60517d22015-12-23 02:07:03 +09001641 /* parse pretty print result and update max length */
1642 if (!he->trace_output)
1643 he->trace_output = get_trace_output(he);
1644
1645 namelen = strlen(field->name);
1646 str = he->trace_output;
1647
1648 while (str) {
1649 pos = strchr(str, ' ');
1650 if (pos == NULL) {
1651 last = true;
1652 pos = str + strlen(str);
1653 }
1654
1655 if (!strncmp(str, field->name, namelen)) {
1656 size_t len;
1657
1658 str += namelen + 1;
1659 len = pos - str;
1660
1661 if (len > hde->dynamic_len)
1662 hde->dynamic_len = len;
1663 break;
1664 }
1665
1666 if (last)
1667 str = NULL;
1668 else
1669 str = pos + 1;
1670 }
1671}
1672
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001673static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1674 struct perf_evsel *evsel __maybe_unused)
1675{
1676 struct hpp_dynamic_entry *hde;
1677 size_t len = fmt->user_len;
1678
1679 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1680
1681 if (!len)
1682 len = hde_width(hde);
1683
1684 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
1685}
1686
1687static int __sort__hde_width(struct perf_hpp_fmt *fmt,
1688 struct perf_hpp *hpp __maybe_unused,
1689 struct perf_evsel *evsel __maybe_unused)
1690{
1691 struct hpp_dynamic_entry *hde;
1692 size_t len = fmt->user_len;
1693
1694 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1695
1696 if (!len)
1697 len = hde_width(hde);
1698
1699 return len;
1700}
1701
Namhyung Kim361459f2015-12-23 02:07:08 +09001702bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
1703{
1704 struct hpp_dynamic_entry *hde;
1705
1706 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1707
1708 return hists_to_evsel(hists) == hde->evsel;
1709}
1710
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001711static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1712 struct hist_entry *he)
1713{
1714 struct hpp_dynamic_entry *hde;
1715 size_t len = fmt->user_len;
Namhyung Kim60517d22015-12-23 02:07:03 +09001716 char *str, *pos;
1717 struct format_field *field;
1718 size_t namelen;
1719 bool last = false;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001720 int ret;
1721
1722 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1723
1724 if (!len)
1725 len = hde_width(hde);
1726
Namhyung Kim053a3982015-12-23 02:07:05 +09001727 if (hde->raw_trace)
1728 goto raw_field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001729
Namhyung Kim053a3982015-12-23 02:07:05 +09001730 field = hde->field;
Namhyung Kim60517d22015-12-23 02:07:03 +09001731 namelen = strlen(field->name);
1732 str = he->trace_output;
1733
1734 while (str) {
1735 pos = strchr(str, ' ');
1736 if (pos == NULL) {
1737 last = true;
1738 pos = str + strlen(str);
1739 }
1740
1741 if (!strncmp(str, field->name, namelen)) {
1742 str += namelen + 1;
1743 str = strndup(str, pos - str);
1744
1745 if (str == NULL)
1746 return scnprintf(hpp->buf, hpp->size,
1747 "%*.*s", len, len, "ERROR");
1748 break;
1749 }
1750
1751 if (last)
1752 str = NULL;
1753 else
1754 str = pos + 1;
1755 }
1756
1757 if (str == NULL) {
1758 struct trace_seq seq;
Namhyung Kim053a3982015-12-23 02:07:05 +09001759raw_field:
Namhyung Kim60517d22015-12-23 02:07:03 +09001760 trace_seq_init(&seq);
1761 pevent_print_field(&seq, he->raw_data, hde->field);
1762 str = seq.buffer;
1763 }
1764
1765 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
1766 free(str);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001767 return ret;
1768}
1769
1770static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
1771 struct hist_entry *a, struct hist_entry *b)
1772{
1773 struct hpp_dynamic_entry *hde;
1774 struct format_field *field;
1775 unsigned offset, size;
1776
1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
1778
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001779 field = hde->field;
1780 if (field->flags & FIELD_IS_DYNAMIC) {
1781 unsigned long long dyn;
1782
1783 pevent_read_number_field(field, a->raw_data, &dyn);
1784 offset = dyn & 0xffff;
1785 size = (dyn >> 16) & 0xffff;
1786
1787 /* record max width for output */
1788 if (size > hde->dynamic_len)
1789 hde->dynamic_len = size;
1790 } else {
1791 offset = field->offset;
1792 size = field->size;
Namhyung Kim60517d22015-12-23 02:07:03 +09001793
1794 update_dynamic_len(hde, a);
1795 update_dynamic_len(hde, b);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001796 }
1797
1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size);
1799}
1800
Namhyung Kim361459f2015-12-23 02:07:08 +09001801bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
1802{
1803 return fmt->cmp == __sort__hde_cmp;
1804}
1805
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001806static struct hpp_dynamic_entry *
1807__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
1808{
1809 struct hpp_dynamic_entry *hde;
1810
1811 hde = malloc(sizeof(*hde));
1812 if (hde == NULL) {
1813 pr_debug("Memory allocation failed\n");
1814 return NULL;
1815 }
1816
1817 hde->evsel = evsel;
1818 hde->field = field;
1819 hde->dynamic_len = 0;
1820
1821 hde->hpp.name = field->name;
1822 hde->hpp.header = __sort__hde_header;
1823 hde->hpp.width = __sort__hde_width;
1824 hde->hpp.entry = __sort__hde_entry;
1825 hde->hpp.color = NULL;
1826
1827 hde->hpp.cmp = __sort__hde_cmp;
1828 hde->hpp.collapse = __sort__hde_cmp;
1829 hde->hpp.sort = __sort__hde_cmp;
1830
1831 INIT_LIST_HEAD(&hde->hpp.list);
1832 INIT_LIST_HEAD(&hde->hpp.sort_list);
1833 hde->hpp.elide = false;
1834 hde->hpp.len = 0;
1835 hde->hpp.user_len = 0;
1836
1837 return hde;
1838}
1839
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001840static int parse_field_name(char *str, char **event, char **field, char **opt)
1841{
1842 char *event_name, *field_name, *opt_name;
1843
1844 event_name = str;
1845 field_name = strchr(str, '.');
1846
1847 if (field_name) {
1848 *field_name++ = '\0';
1849 } else {
1850 event_name = NULL;
1851 field_name = str;
1852 }
1853
1854 opt_name = strchr(field_name, '/');
1855 if (opt_name)
1856 *opt_name++ = '\0';
1857
1858 *event = event_name;
1859 *field = field_name;
1860 *opt = opt_name;
1861
1862 return 0;
1863}
1864
1865/* find match evsel using a given event name. The event name can be:
1866 * 1. NULL - only valid for single event session
1867 * 2. '%' + event index (e.g. '%1' for first event)
1868 * 3. full event name (e.g. sched:sched_switch)
1869 * 4. partial event name (should not contain ':')
1870 */
1871static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
1872{
1873 struct perf_evsel *evsel = NULL;
1874 struct perf_evsel *pos;
1875 bool full_name;
1876
1877 /* case 1 */
1878 if (event_name == NULL) {
1879 if (evlist->nr_entries != 1) {
1880 pr_debug("event name should be given\n");
1881 return NULL;
1882 }
1883
1884 return perf_evlist__first(evlist);
1885 }
1886
1887 /* case 2 */
1888 if (event_name[0] == '%') {
1889 int nr = strtol(event_name+1, NULL, 0);
1890
1891 if (nr > evlist->nr_entries)
1892 return NULL;
1893
1894 evsel = perf_evlist__first(evlist);
1895 while (--nr > 0)
1896 evsel = perf_evsel__next(evsel);
1897
1898 return evsel;
1899 }
1900
1901 full_name = !!strchr(event_name, ':');
1902 evlist__for_each(evlist, pos) {
1903 /* case 3 */
1904 if (full_name && !strcmp(pos->name, event_name))
1905 return pos;
1906 /* case 4 */
1907 if (!full_name && strstr(pos->name, event_name)) {
1908 if (evsel) {
1909 pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
1910 event_name, evsel->name, pos->name);
1911 return NULL;
1912 }
1913 evsel = pos;
1914 }
1915 }
1916
1917 return evsel;
1918}
1919
Namhyung Kim3b099bf52015-12-23 02:07:07 +09001920static int __dynamic_dimension__add(struct perf_evsel *evsel,
1921 struct format_field *field,
1922 bool raw_trace)
1923{
1924 struct hpp_dynamic_entry *hde;
1925
1926 hde = __alloc_dynamic_entry(evsel, field);
1927 if (hde == NULL)
1928 return -ENOMEM;
1929
1930 hde->raw_trace = raw_trace;
1931
1932 perf_hpp__register_sort_field(&hde->hpp);
1933 return 0;
1934}
1935
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001936static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
1937{
1938 int ret;
1939 struct format_field *field;
1940
1941 field = evsel->tp_format->format.fields;
1942 while (field) {
1943 ret = __dynamic_dimension__add(evsel, field, raw_trace);
1944 if (ret < 0)
1945 return ret;
1946
1947 field = field->next;
1948 }
1949 return 0;
1950}
1951
1952static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
1953{
1954 int ret;
1955 struct perf_evsel *evsel;
1956
1957 evlist__for_each(evlist, evsel) {
1958 if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
1959 continue;
1960
1961 ret = add_evsel_fields(evsel, raw_trace);
1962 if (ret < 0)
1963 return ret;
1964 }
1965 return 0;
1966}
1967
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001968static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
1969{
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001970 char *str, *event_name, *field_name, *opt_name;
1971 struct perf_evsel *evsel;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001972 struct format_field *field;
Namhyung Kim053a3982015-12-23 02:07:05 +09001973 bool raw_trace = symbol_conf.raw_trace;
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001974 int ret = 0;
1975
1976 if (evlist == NULL)
1977 return -ENOENT;
1978
1979 str = strdup(tok);
1980 if (str == NULL)
1981 return -ENOMEM;
1982
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001983 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001984 ret = -EINVAL;
1985 goto out;
1986 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09001987
Namhyung Kim5d0cff92015-12-23 02:07:06 +09001988 if (opt_name) {
1989 if (strcmp(opt_name, "raw")) {
1990 pr_debug("unsupported field option %s\n", opt_name);
Namhyung Kim053a3982015-12-23 02:07:05 +09001991 ret = -EINVAL;
1992 goto out;
1993 }
1994 raw_trace = true;
1995 }
1996
Namhyung Kim2e422fd2015-12-23 02:07:09 +09001997 if (!strcmp(field_name, "trace_fields")) {
1998 ret = add_all_dynamic_fields(evlist, raw_trace);
1999 goto out;
2000 }
2001
Namhyung Kim5d0cff92015-12-23 02:07:06 +09002002 evsel = find_evsel(evlist, event_name);
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002003 if (evsel == NULL) {
2004 pr_debug("Cannot find event: %s\n", event_name);
2005 ret = -ENOENT;
2006 goto out;
2007 }
2008
2009 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2010 pr_debug("%s is not a tracepoint event\n", event_name);
2011 ret = -EINVAL;
2012 goto out;
2013 }
2014
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002015 if (!strcmp(field_name, "*")) {
Namhyung Kim2e422fd2015-12-23 02:07:09 +09002016 ret = add_evsel_fields(evsel, raw_trace);
Namhyung Kim3b099bf52015-12-23 02:07:07 +09002017 } else {
2018 field = pevent_find_any_field(evsel->tp_format, field_name);
2019 if (field == NULL) {
2020 pr_debug("Cannot find event field for %s.%s\n",
2021 event_name, field_name);
2022 return -ENOENT;
2023 }
2024
2025 ret = __dynamic_dimension__add(evsel, field, raw_trace);
2026 }
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002027
2028out:
2029 free(str);
2030 return ret;
2031}
2032
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002033static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d092013-04-03 21:26:10 +09002034{
2035 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09002036 return 0;
2037
Namhyung Kima7d945b2014-03-04 10:46:34 +09002038 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09002039 return -1;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002040
2041 if (sd->entry->se_collapse)
2042 sort__need_collapse = 1;
2043
Namhyung Kim2f532d092013-04-03 21:26:10 +09002044 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09002045
2046 return 0;
Namhyung Kim2f532d092013-04-03 21:26:10 +09002047}
2048
Namhyung Kima2ce0672014-03-04 09:06:42 +09002049static int __hpp_dimension__add(struct hpp_dimension *hd)
2050{
2051 if (!hd->taken) {
2052 hd->taken = 1;
2053
2054 perf_hpp__register_sort_field(hd->fmt);
2055 }
2056 return 0;
2057}
2058
Namhyung Kima7d945b2014-03-04 10:46:34 +09002059static int __sort_dimension__add_output(struct sort_dimension *sd)
2060{
2061 if (sd->taken)
2062 return 0;
2063
2064 if (__sort_dimension__add_hpp_output(sd) < 0)
2065 return -1;
2066
2067 sd->taken = 1;
2068 return 0;
2069}
2070
2071static int __hpp_dimension__add_output(struct hpp_dimension *hd)
2072{
2073 if (!hd->taken) {
2074 hd->taken = 1;
2075
2076 perf_hpp__column_register(hd->fmt);
2077 }
2078 return 0;
2079}
2080
Jiri Olsabeeaaeb2015-10-06 14:25:11 +02002081int hpp_dimension__add_output(unsigned col)
2082{
2083 BUG_ON(col >= PERF_HPP__MAX_INDEX);
2084 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
2085}
2086
Namhyung Kim40184c42015-12-23 02:07:01 +09002087static int sort_dimension__add(const char *tok,
2088 struct perf_evlist *evlist __maybe_unused)
John Kacurdd68ada2009-09-24 18:02:49 +02002089{
2090 unsigned int i;
2091
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002092 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2093 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02002094
John Kacurdd68ada2009-09-24 18:02:49 +02002095 if (strncasecmp(tok, sd->name, strlen(tok)))
2096 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002097
John Kacurdd68ada2009-09-24 18:02:49 +02002098 if (sd->entry == &sort_parent) {
2099 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2100 if (ret) {
2101 char err[BUFSIZ];
2102
2103 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03002104 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2105 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02002106 }
2107 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09002108 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09002109 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00002110 /*
2111 * perf diff displays the performance difference amongst
2112 * two or more perf.data files. Those files could come
2113 * from different binaries. So we should not compare
2114 * their ips, but the name of symbol.
2115 */
2116 if (sort__mode == SORT_MODE__DIFF)
2117 sd->entry->se_collapse = sort__sym_sort;
2118
Namhyung Kim68f6d022013-12-18 14:21:10 +09002119 } else if (sd->entry == &sort_dso) {
2120 sort__has_dso = 1;
Kan Liang2e7ea3a2015-09-04 10:45:43 -04002121 } else if (sd->entry == &sort_socket) {
2122 sort__has_socket = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02002123 }
2124
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002125 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02002126 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002127
Namhyung Kima2ce0672014-03-04 09:06:42 +09002128 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2129 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2130
2131 if (strncasecmp(tok, hd->name, strlen(tok)))
2132 continue;
2133
2134 return __hpp_dimension__add(hd);
2135 }
2136
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002137 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2138 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2139
2140 if (strncasecmp(tok, sd->name, strlen(tok)))
2141 continue;
2142
Namhyung Kim55369fc2013-04-01 20:35:20 +09002143 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002144 return -EINVAL;
2145
2146 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2147 sort__has_sym = 1;
2148
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002149 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002150 return 0;
2151 }
2152
Namhyung Kimafab87b2013-04-03 21:26:11 +09002153 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2154 struct sort_dimension *sd = &memory_sort_dimensions[i];
2155
2156 if (strncasecmp(tok, sd->name, strlen(tok)))
2157 continue;
2158
2159 if (sort__mode != SORT_MODE__MEMORY)
2160 return -EINVAL;
2161
2162 if (sd->entry == &sort_mem_daddr_sym)
2163 sort__has_sym = 1;
2164
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002165 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09002166 return 0;
2167 }
2168
Namhyung Kimc7c2a5e2015-12-23 02:07:02 +09002169 if (!add_dynamic_entry(evlist, tok))
2170 return 0;
2171
John Kacurdd68ada2009-09-24 18:02:49 +02002172 return -ESRCH;
2173}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002174
Namhyung Kimd49dade2015-12-23 02:07:10 +09002175static const char *get_default_sort_order(struct perf_evlist *evlist)
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002176{
2177 const char *default_sort_orders[] = {
2178 default_sort_order,
2179 default_branch_sort_order,
2180 default_mem_sort_order,
2181 default_top_sort_order,
2182 default_diff_sort_order,
Namhyung Kimd49dade2015-12-23 02:07:10 +09002183 default_tracepoint_sort_order,
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002184 };
Namhyung Kimd49dade2015-12-23 02:07:10 +09002185 bool use_trace = true;
2186 struct perf_evsel *evsel;
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002187
2188 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2189
Namhyung Kimd49dade2015-12-23 02:07:10 +09002190 if (evlist == NULL)
2191 goto out_no_evlist;
2192
2193 evlist__for_each(evlist, evsel) {
2194 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2195 use_trace = false;
2196 break;
2197 }
2198 }
2199
2200 if (use_trace) {
2201 sort__mode = SORT_MODE__TRACEPOINT;
2202 if (symbol_conf.raw_trace)
2203 return "trace_fields";
2204 }
2205out_no_evlist:
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002206 return default_sort_orders[sort__mode];
2207}
2208
Namhyung Kimd49dade2015-12-23 02:07:10 +09002209static int setup_sort_order(struct perf_evlist *evlist)
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002210{
2211 char *new_sort_order;
2212
2213 /*
2214 * Append '+'-prefixed sort order to the default sort
2215 * order string.
2216 */
2217 if (!sort_order || is_strict_order(sort_order))
2218 return 0;
2219
2220 if (sort_order[1] == '\0') {
2221 error("Invalid --sort key: `+'");
2222 return -EINVAL;
2223 }
2224
2225 /*
2226 * We allocate new sort_order string, but we never free it,
2227 * because it's checked over the rest of the code.
2228 */
2229 if (asprintf(&new_sort_order, "%s,%s",
Namhyung Kimd49dade2015-12-23 02:07:10 +09002230 get_default_sort_order(evlist), sort_order + 1) < 0) {
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002231 error("Not enough memory to set up --sort");
2232 return -ENOMEM;
2233 }
2234
2235 sort_order = new_sort_order;
2236 return 0;
2237}
2238
Namhyung Kim40184c42015-12-23 02:07:01 +09002239static int __setup_sorting(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002240{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002241 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002242 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09002243 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002244
Namhyung Kimd49dade2015-12-23 02:07:10 +09002245 ret = setup_sort_order(evlist);
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02002246 if (ret)
2247 return ret;
2248
2249 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002250 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002251 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09002252 /*
2253 * If user specified field order but no sort order,
2254 * we'll honor it and not add default sort orders.
2255 */
2256 return 0;
2257 }
2258
Namhyung Kimd49dade2015-12-23 02:07:10 +09002259 sort_keys = get_default_sort_order(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002260 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09002261
2262 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09002263 if (str == NULL) {
2264 error("Not enough memory to setup sort keys");
2265 return -ENOMEM;
2266 }
2267
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002268 for (tok = strtok_r(str, ", ", &tmp);
2269 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002270 ret = sort_dimension__add(tok, evlist);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002271 if (ret == -EINVAL) {
2272 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09002273 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09002274 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002275 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09002276 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002277 }
2278 }
2279
2280 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09002281 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02002282}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002283
Jiri Olsaf2998422014-05-23 17:15:47 +02002284void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09002285{
Jiri Olsaf2998422014-05-23 17:15:47 +02002286 struct perf_hpp_fmt *fmt;
2287 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09002288
Jiri Olsaf2998422014-05-23 17:15:47 +02002289 perf_hpp__for_each_format(fmt) {
2290 if (!perf_hpp__is_sort_entry(fmt))
2291 continue;
2292
2293 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2294 if (hse->se->se_width_idx == idx) {
2295 fmt->elide = elide;
2296 break;
2297 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002298 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09002299}
2300
Jiri Olsaf2998422014-05-23 17:15:47 +02002301static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002302{
2303 if (list && strlist__nr_entries(list) == 1) {
2304 if (fp != NULL)
2305 fprintf(fp, "# %s: %s\n", list_name,
2306 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02002307 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002308 }
Jiri Olsaf2998422014-05-23 17:15:47 +02002309 return false;
2310}
2311
2312static bool get_elide(int idx, FILE *output)
2313{
2314 switch (idx) {
2315 case HISTC_SYMBOL:
2316 return __get_elide(symbol_conf.sym_list, "symbol", output);
2317 case HISTC_DSO:
2318 return __get_elide(symbol_conf.dso_list, "dso", output);
2319 case HISTC_COMM:
2320 return __get_elide(symbol_conf.comm_list, "comm", output);
2321 default:
2322 break;
2323 }
2324
2325 if (sort__mode != SORT_MODE__BRANCH)
2326 return false;
2327
2328 switch (idx) {
2329 case HISTC_SYMBOL_FROM:
2330 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2331 case HISTC_SYMBOL_TO:
2332 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2333 case HISTC_DSO_FROM:
2334 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2335 case HISTC_DSO_TO:
2336 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2337 default:
2338 break;
2339 }
2340
2341 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02002342}
Namhyung Kim08e71542013-04-03 21:26:19 +09002343
2344void sort__setup_elide(FILE *output)
2345{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002346 struct perf_hpp_fmt *fmt;
2347 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09002348
Jiri Olsaf2998422014-05-23 17:15:47 +02002349 perf_hpp__for_each_format(fmt) {
2350 if (!perf_hpp__is_sort_entry(fmt))
2351 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09002352
Jiri Olsaf2998422014-05-23 17:15:47 +02002353 hse = container_of(fmt, struct hpp_sort_entry, hpp);
2354 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09002355 }
2356
Namhyung Kim7524f632013-11-08 17:53:42 +09002357 /*
2358 * It makes no sense to elide all of sort entries.
2359 * Just revert them to show up again.
2360 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002361 perf_hpp__for_each_format(fmt) {
2362 if (!perf_hpp__is_sort_entry(fmt))
2363 continue;
2364
Jiri Olsaf2998422014-05-23 17:15:47 +02002365 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09002366 return;
2367 }
2368
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002369 perf_hpp__for_each_format(fmt) {
2370 if (!perf_hpp__is_sort_entry(fmt))
2371 continue;
2372
Jiri Olsaf2998422014-05-23 17:15:47 +02002373 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09002374 }
Namhyung Kim08e71542013-04-03 21:26:19 +09002375}
Namhyung Kima7d945b2014-03-04 10:46:34 +09002376
2377static int output_field_add(char *tok)
2378{
2379 unsigned int i;
2380
2381 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2382 struct sort_dimension *sd = &common_sort_dimensions[i];
2383
2384 if (strncasecmp(tok, sd->name, strlen(tok)))
2385 continue;
2386
2387 return __sort_dimension__add_output(sd);
2388 }
2389
2390 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2391 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2392
2393 if (strncasecmp(tok, hd->name, strlen(tok)))
2394 continue;
2395
2396 return __hpp_dimension__add_output(hd);
2397 }
2398
2399 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2400 struct sort_dimension *sd = &bstack_sort_dimensions[i];
2401
2402 if (strncasecmp(tok, sd->name, strlen(tok)))
2403 continue;
2404
2405 return __sort_dimension__add_output(sd);
2406 }
2407
2408 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2409 struct sort_dimension *sd = &memory_sort_dimensions[i];
2410
2411 if (strncasecmp(tok, sd->name, strlen(tok)))
2412 continue;
2413
2414 return __sort_dimension__add_output(sd);
2415 }
2416
2417 return -ESRCH;
2418}
2419
2420static void reset_dimensions(void)
2421{
2422 unsigned int i;
2423
2424 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2425 common_sort_dimensions[i].taken = 0;
2426
2427 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2428 hpp_sort_dimensions[i].taken = 0;
2429
2430 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2431 bstack_sort_dimensions[i].taken = 0;
2432
2433 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2434 memory_sort_dimensions[i].taken = 0;
2435}
2436
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002437bool is_strict_order(const char *order)
2438{
2439 return order && (*order != '+');
2440}
2441
Namhyung Kima7d945b2014-03-04 10:46:34 +09002442static int __setup_output_field(void)
2443{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002444 char *tmp, *tok, *str, *strp;
2445 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09002446
2447 if (field_order == NULL)
2448 return 0;
2449
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002450 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002451 if (str == NULL) {
2452 error("Not enough memory to setup output fields");
2453 return -ENOMEM;
2454 }
2455
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002456 if (!is_strict_order(field_order))
2457 strp++;
2458
2459 if (!strlen(strp)) {
2460 error("Invalid --fields key: `+'");
2461 goto out;
2462 }
2463
2464 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002465 tok; tok = strtok_r(NULL, ", ", &tmp)) {
2466 ret = output_field_add(tok);
2467 if (ret == -EINVAL) {
2468 error("Invalid --fields key: `%s'", tok);
2469 break;
2470 } else if (ret == -ESRCH) {
2471 error("Unknown --fields key: `%s'", tok);
2472 break;
2473 }
2474 }
2475
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02002476out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09002477 free(str);
2478 return ret;
2479}
2480
Namhyung Kim40184c42015-12-23 02:07:01 +09002481int setup_sorting(struct perf_evlist *evlist)
Namhyung Kima7d945b2014-03-04 10:46:34 +09002482{
2483 int err;
2484
Namhyung Kim40184c42015-12-23 02:07:01 +09002485 err = __setup_sorting(evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002486 if (err < 0)
2487 return err;
2488
2489 if (parent_pattern != default_parent_pattern) {
Namhyung Kim40184c42015-12-23 02:07:01 +09002490 err = sort_dimension__add("parent", evlist);
Namhyung Kima7d945b2014-03-04 10:46:34 +09002491 if (err < 0)
2492 return err;
2493 }
2494
2495 reset_dimensions();
2496
2497 /*
2498 * perf diff doesn't use default hpp output fields.
2499 */
2500 if (sort__mode != SORT_MODE__DIFF)
2501 perf_hpp__init();
2502
2503 err = __setup_output_field();
2504 if (err < 0)
2505 return err;
2506
2507 /* copy sort keys to output fields */
2508 perf_hpp__setup_output_field();
2509 /* and then copy output fields to sort keys */
2510 perf_hpp__append_sort_keys();
2511
2512 return 0;
2513}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002514
2515void reset_output_field(void)
2516{
2517 sort__need_collapse = 0;
2518 sort__has_parent = 0;
2519 sort__has_sym = 0;
2520 sort__has_dso = 0;
2521
Namhyung Kimd69b2962014-05-23 10:59:01 +09002522 field_order = NULL;
2523 sort_order = NULL;
2524
Namhyung Kim1c89fe92014-05-07 18:42:24 +09002525 reset_dimensions();
2526 perf_hpp__reset_output_field();
2527}