blob: 09d4696fd9a1156f096bd9cf3ea7b1a4f00454d7 [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"
John Kacurdd68ada2009-09-24 18:02:49 +02007
8regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03009const char default_parent_pattern[] = "^sys_|^do_page_fault";
10const char *parent_pattern = default_parent_pattern;
11const char default_sort_order[] = "comm,dso,symbol";
Namhyung Kim512ae1b2014-03-18 11:31:39 +090012const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +090017const char *field_order;
Greg Priceb21484f2012-12-06 21:48:05 -080018regex_t ignore_callees_regex;
19int have_ignore_callees = 0;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +020020int sort__need_collapse = 0;
21int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090022int sort__has_sym = 0;
Namhyung Kim68f6d022013-12-18 14:21:10 +090023int sort__has_dso = 0;
Namhyung Kim55369fc2013-04-01 20:35:20 +090024enum sort_mode sort__mode = SORT_MODE__NORMAL;
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020025
John Kacurdd68ada2009-09-24 18:02:49 +020026
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030027static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020028{
29 int n;
30 va_list ap;
31
32 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030033 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020034 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030035 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020036
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030037 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020038 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030039 if (sep == NULL)
40 break;
41 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020042 }
John Kacurdd68ada2009-09-24 18:02:49 +020043 }
44 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110045
46 if (n >= (int)size)
47 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020048 return n;
49}
50
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020051static int64_t cmp_null(const void *l, const void *r)
Frederic Weisbecker872a8782011-06-29 03:14:52 +020052{
53 if (!l && !r)
54 return 0;
55 else if (!l)
56 return -1;
57 else
58 return 1;
59}
60
61/* --sort pid */
62
63static int64_t
64sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
65{
Adrian Hunter38051232013-07-04 16:20:31 +030066 return right->thread->tid - left->thread->tid;
Frederic Weisbecker872a8782011-06-29 03:14:52 +020067}
68
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -030069static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030070 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020071{
Frederic Weisbeckerb9c51432013-09-11 14:46:56 +020072 const char *comm = thread__comm_str(he->thread);
Namhyung Kim5b591662014-07-31 14:47:38 +090073
74 width = max(7U, width) - 6;
75 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
76 width, width, comm ?: "");
John Kacurdd68ada2009-09-24 18:02:49 +020077}
78
Frederic Weisbecker872a8782011-06-29 03:14:52 +020079struct sort_entry sort_thread = {
Namhyung Kim8246de82014-07-31 14:47:35 +090080 .se_header = " Pid:Command",
Frederic Weisbecker872a8782011-06-29 03:14:52 +020081 .se_cmp = sort__thread_cmp,
82 .se_snprintf = hist_entry__thread_snprintf,
83 .se_width_idx = HISTC_THREAD,
84};
85
86/* --sort comm */
87
88static int64_t
89sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
90{
Frederic Weisbeckerfedd63d2013-09-11 17:18:09 +020091 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020092 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +020093}
94
95static int64_t
96sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
97{
Namhyung Kim4dfced32013-09-13 16:28:57 +090098 /* Compare the addr that should be unique among comm */
Jiri Olsa2f15bd82015-05-15 17:54:28 +020099 return strcmp(comm__str(right->comm), comm__str(left->comm));
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200100}
101
Namhyung Kim202e7a62014-03-04 11:01:41 +0900102static int64_t
103sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
104{
105 return strcmp(comm__str(right->comm), comm__str(left->comm));
106}
107
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300108static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300109 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200110{
Namhyung Kim5b591662014-07-31 14:47:38 +0900111 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
John Kacurdd68ada2009-09-24 18:02:49 +0200112}
113
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900114struct sort_entry sort_comm = {
115 .se_header = "Command",
116 .se_cmp = sort__comm_cmp,
117 .se_collapse = sort__comm_collapse,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900118 .se_sort = sort__comm_sort,
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900119 .se_snprintf = hist_entry__comm_snprintf,
120 .se_width_idx = HISTC_COMM,
121};
122
123/* --sort dso */
124
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100125static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200126{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100127 struct dso *dso_l = map_l ? map_l->dso : NULL;
128 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300129 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200130
131 if (!dso_l || !dso_r)
Namhyung Kim202e7a62014-03-04 11:01:41 +0900132 return cmp_null(dso_r, dso_l);
John Kacurdd68ada2009-09-24 18:02:49 +0200133
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300134 if (verbose) {
135 dso_name_l = dso_l->long_name;
136 dso_name_r = dso_r->long_name;
137 } else {
138 dso_name_l = dso_l->short_name;
139 dso_name_r = dso_r->short_name;
140 }
141
142 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200143}
144
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100145static int64_t
146sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200147{
Namhyung Kim202e7a62014-03-04 11:01:41 +0900148 return _sort__dso_cmp(right->ms.map, left->ms.map);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100149}
150
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100151static int _hist_entry__dso_snprintf(struct map *map, char *bf,
152 size_t size, unsigned int width)
153{
154 if (map && map->dso) {
155 const char *dso_name = !verbose ? map->dso->short_name :
156 map->dso->long_name;
Namhyung Kim5b591662014-07-31 14:47:38 +0900157 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300158 }
John Kacurdd68ada2009-09-24 18:02:49 +0200159
Namhyung Kim5b591662014-07-31 14:47:38 +0900160 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200161}
162
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300163static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100164 size_t size, unsigned int width)
165{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300166 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100167}
168
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900169struct sort_entry sort_dso = {
170 .se_header = "Shared Object",
171 .se_cmp = sort__dso_cmp,
172 .se_snprintf = hist_entry__dso_snprintf,
173 .se_width_idx = HISTC_DSO,
174};
175
176/* --sort symbol */
177
Namhyung Kim2037be52013-12-18 14:21:09 +0900178static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
179{
180 return (int64_t)(right_ip - left_ip);
181}
182
Namhyung Kim51f27d12013-02-06 14:57:15 +0900183static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900184{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900185 u64 ip_l, ip_r;
186
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900187 if (!sym_l || !sym_r)
188 return cmp_null(sym_l, sym_r);
189
190 if (sym_l == sym_r)
191 return 0;
192
193 ip_l = sym_l->start;
194 ip_r = sym_r->start;
195
196 return (int64_t)(ip_r - ip_l);
197}
198
199static int64_t
200sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
201{
Namhyung Kim09600e02013-10-15 11:01:56 +0900202 int64_t ret;
203
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900204 if (!left->ms.sym && !right->ms.sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900205 return _sort__addr_cmp(left->ip, right->ip);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900206
Namhyung Kim09600e02013-10-15 11:01:56 +0900207 /*
208 * comparing symbol address alone is not enough since it's a
209 * relative address within a dso.
210 */
Namhyung Kim68f6d022013-12-18 14:21:10 +0900211 if (!sort__has_dso) {
212 ret = sort__dso_cmp(left, right);
213 if (ret != 0)
214 return ret;
215 }
Namhyung Kim09600e02013-10-15 11:01:56 +0900216
Namhyung Kim51f27d12013-02-06 14:57:15 +0900217 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900218}
219
Namhyung Kim202e7a62014-03-04 11:01:41 +0900220static int64_t
221sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
222{
223 if (!left->ms.sym || !right->ms.sym)
224 return cmp_null(left->ms.sym, right->ms.sym);
225
226 return strcmp(right->ms.sym->name, left->ms.sym->name);
227}
228
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100229static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
230 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900231 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100232{
233 size_t ret = 0;
234
235 if (verbose) {
236 char o = map ? dso__symtab_origin(map->dso) : '!';
237 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
Namhyung Kimded19d52013-04-01 20:35:19 +0900238 BITS_PER_LONG / 4 + 2, ip, o);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100239 }
240
241 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100242 if (sym && map) {
243 if (map->type == MAP__VARIABLE) {
244 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
245 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100246 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100247 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
248 width - ret, "");
249 } else {
250 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
251 width - ret,
252 sym->name);
253 }
254 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100255 size_t len = BITS_PER_LONG / 4;
256 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
257 len, ip);
258 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
259 width - ret, "");
260 }
261
Namhyung Kim5b591662014-07-31 14:47:38 +0900262 if (ret > width)
263 bf[width] = '\0';
264
265 return width;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100266}
267
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300268static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900269 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100270{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300271 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
272 he->level, bf, size, width);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100273}
John Kacurdd68ada2009-09-24 18:02:49 +0200274
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200275struct sort_entry sort_sym = {
276 .se_header = "Symbol",
277 .se_cmp = sort__sym_cmp,
Namhyung Kim202e7a62014-03-04 11:01:41 +0900278 .se_sort = sort__sym_sort,
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200279 .se_snprintf = hist_entry__sym_snprintf,
280 .se_width_idx = HISTC_SYMBOL,
281};
John Kacurdd68ada2009-09-24 18:02:49 +0200282
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300283/* --sort srcline */
284
285static int64_t
286sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
287{
Namhyung Kim4adcc432013-09-11 14:09:33 +0900288 if (!left->srcline) {
289 if (!left->ms.map)
290 left->srcline = SRCLINE_UNKNOWN;
291 else {
292 struct map *map = left->ms.map;
293 left->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800294 map__rip_2objdump(map, left->ip),
295 left->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900296 }
297 }
298 if (!right->srcline) {
299 if (!right->ms.map)
300 right->srcline = SRCLINE_UNKNOWN;
301 else {
302 struct map *map = right->ms.map;
303 right->srcline = get_srcline(map->dso,
Andi Kleen85c116a2014-11-12 18:05:27 -0800304 map__rip_2objdump(map, right->ip),
305 right->ms.sym, true);
Namhyung Kim4adcc432013-09-11 14:09:33 +0900306 }
307 }
Namhyung Kim202e7a62014-03-04 11:01:41 +0900308 return strcmp(right->srcline, left->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300309}
310
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300311static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim5b591662014-07-31 14:47:38 +0900312 size_t size, unsigned int width)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300313{
Arnaldo Carvalho de Melob2d53672014-11-18 18:02:51 -0300314 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300315}
316
317struct sort_entry sort_srcline = {
318 .se_header = "Source:Line",
319 .se_cmp = sort__srcline_cmp,
320 .se_snprintf = hist_entry__srcline_snprintf,
321 .se_width_idx = HISTC_SRCLINE,
322};
323
John Kacurdd68ada2009-09-24 18:02:49 +0200324/* --sort parent */
325
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200326static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200327sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
328{
329 struct symbol *sym_l = left->parent;
330 struct symbol *sym_r = right->parent;
331
332 if (!sym_l || !sym_r)
333 return cmp_null(sym_l, sym_r);
334
Namhyung Kim202e7a62014-03-04 11:01:41 +0900335 return strcmp(sym_r->name, sym_l->name);
John Kacurdd68ada2009-09-24 18:02:49 +0200336}
337
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300338static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300339 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200340{
Namhyung Kim5b591662014-07-31 14:47:38 +0900341 return repsep_snprintf(bf, size, "%-*.*s", width, width,
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300342 he->parent ? he->parent->name : "[other]");
John Kacurdd68ada2009-09-24 18:02:49 +0200343}
344
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200345struct sort_entry sort_parent = {
346 .se_header = "Parent symbol",
347 .se_cmp = sort__parent_cmp,
348 .se_snprintf = hist_entry__parent_snprintf,
349 .se_width_idx = HISTC_PARENT,
350};
351
Arun Sharmaf60f3592010-06-04 11:27:10 -0300352/* --sort cpu */
353
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200354static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300355sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
356{
357 return right->cpu - left->cpu;
358}
359
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300360static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
361 size_t size, unsigned int width)
Arun Sharmaf60f3592010-06-04 11:27:10 -0300362{
Namhyung Kim5b591662014-07-31 14:47:38 +0900363 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300364}
365
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200366struct sort_entry sort_cpu = {
367 .se_header = "CPU",
368 .se_cmp = sort__cpu_cmp,
369 .se_snprintf = hist_entry__cpu_snprintf,
370 .se_width_idx = HISTC_CPU,
371};
372
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900373/* sort keys for branch stacks */
374
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100375static int64_t
376sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
377{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200378 if (!left->branch_info || !right->branch_info)
379 return cmp_null(left->branch_info, right->branch_info);
380
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100381 return _sort__dso_cmp(left->branch_info->from.map,
382 right->branch_info->from.map);
383}
384
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300385static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100386 size_t size, unsigned int width)
387{
Jiri Olsa288a4b92014-10-16 16:07:07 +0200388 if (he->branch_info)
389 return _hist_entry__dso_snprintf(he->branch_info->from.map,
390 bf, size, width);
391 else
392 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100393}
394
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100395static int64_t
396sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
397{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200398 if (!left->branch_info || !right->branch_info)
399 return cmp_null(left->branch_info, right->branch_info);
400
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100401 return _sort__dso_cmp(left->branch_info->to.map,
402 right->branch_info->to.map);
403}
404
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300405static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100406 size_t size, unsigned int width)
407{
Jiri Olsa8b62fa52014-10-16 16:07:06 +0200408 if (he->branch_info)
409 return _hist_entry__dso_snprintf(he->branch_info->to.map,
410 bf, size, width);
411 else
412 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100413}
414
415static int64_t
416sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
417{
418 struct addr_map_symbol *from_l = &left->branch_info->from;
419 struct addr_map_symbol *from_r = &right->branch_info->from;
420
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200421 if (!left->branch_info || !right->branch_info)
422 return cmp_null(left->branch_info, right->branch_info);
423
424 from_l = &left->branch_info->from;
425 from_r = &right->branch_info->from;
426
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100427 if (!from_l->sym && !from_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900428 return _sort__addr_cmp(from_l->addr, from_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100429
Namhyung Kim51f27d12013-02-06 14:57:15 +0900430 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100431}
432
433static int64_t
434sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
435{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200436 struct addr_map_symbol *to_l, *to_r;
437
438 if (!left->branch_info || !right->branch_info)
439 return cmp_null(left->branch_info, right->branch_info);
440
441 to_l = &left->branch_info->to;
442 to_r = &right->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100443
444 if (!to_l->sym && !to_r->sym)
Namhyung Kim2037be52013-12-18 14:21:09 +0900445 return _sort__addr_cmp(to_l->addr, to_r->addr);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100446
Namhyung Kim51f27d12013-02-06 14:57:15 +0900447 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100448}
449
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300450static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900451 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100452{
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200453 if (he->branch_info) {
454 struct addr_map_symbol *from = &he->branch_info->from;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100455
Jiri Olsa1b9e97a2014-10-16 16:07:05 +0200456 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
457 he->level, bf, size, width);
458 }
459
460 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100461}
462
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300463static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900464 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100465{
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200466 if (he->branch_info) {
467 struct addr_map_symbol *to = &he->branch_info->to;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100468
Jiri Olsa38cdbd32014-10-16 16:07:04 +0200469 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
470 he->level, bf, size, width);
471 }
472
473 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100474}
475
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900476struct sort_entry sort_dso_from = {
477 .se_header = "Source Shared Object",
478 .se_cmp = sort__dso_from_cmp,
479 .se_snprintf = hist_entry__dso_from_snprintf,
480 .se_width_idx = HISTC_DSO_FROM,
481};
482
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100483struct sort_entry sort_dso_to = {
484 .se_header = "Target Shared Object",
485 .se_cmp = sort__dso_to_cmp,
486 .se_snprintf = hist_entry__dso_to_snprintf,
487 .se_width_idx = HISTC_DSO_TO,
488};
489
490struct sort_entry sort_sym_from = {
491 .se_header = "Source Symbol",
492 .se_cmp = sort__sym_from_cmp,
493 .se_snprintf = hist_entry__sym_from_snprintf,
494 .se_width_idx = HISTC_SYMBOL_FROM,
495};
496
497struct sort_entry sort_sym_to = {
498 .se_header = "Target Symbol",
499 .se_cmp = sort__sym_to_cmp,
500 .se_snprintf = hist_entry__sym_to_snprintf,
501 .se_width_idx = HISTC_SYMBOL_TO,
502};
503
504static int64_t
505sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
506{
Jiri Olsa428560e2014-10-16 16:07:03 +0200507 unsigned char mp, p;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100508
Jiri Olsa428560e2014-10-16 16:07:03 +0200509 if (!left->branch_info || !right->branch_info)
510 return cmp_null(left->branch_info, right->branch_info);
511
512 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
513 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100514 return mp || p;
515}
516
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300517static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100518 size_t size, unsigned int width){
519 static const char *out = "N/A";
520
Jiri Olsa428560e2014-10-16 16:07:03 +0200521 if (he->branch_info) {
522 if (he->branch_info->flags.predicted)
523 out = "N";
524 else if (he->branch_info->flags.mispred)
525 out = "Y";
526 }
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100527
Namhyung Kim5b591662014-07-31 14:47:38 +0900528 return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100529}
530
Stephane Eranian98a3b322013-01-24 16:10:35 +0100531/* --sort daddr_sym */
532static int64_t
533sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
534{
535 uint64_t l = 0, r = 0;
536
537 if (left->mem_info)
538 l = left->mem_info->daddr.addr;
539 if (right->mem_info)
540 r = right->mem_info->daddr.addr;
541
542 return (int64_t)(r - l);
543}
544
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300545static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100546 size_t size, unsigned int width)
547{
548 uint64_t addr = 0;
549 struct map *map = NULL;
550 struct symbol *sym = NULL;
551
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300552 if (he->mem_info) {
553 addr = he->mem_info->daddr.addr;
554 map = he->mem_info->daddr.map;
555 sym = he->mem_info->daddr.sym;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100556 }
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300557 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100558 width);
559}
560
561static int64_t
562sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
563{
564 struct map *map_l = NULL;
565 struct map *map_r = NULL;
566
567 if (left->mem_info)
568 map_l = left->mem_info->daddr.map;
569 if (right->mem_info)
570 map_r = right->mem_info->daddr.map;
571
572 return _sort__dso_cmp(map_l, map_r);
573}
574
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300575static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100576 size_t size, unsigned int width)
577{
578 struct map *map = NULL;
579
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300580 if (he->mem_info)
581 map = he->mem_info->daddr.map;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100582
583 return _hist_entry__dso_snprintf(map, bf, size, width);
584}
585
586static int64_t
587sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
588{
589 union perf_mem_data_src data_src_l;
590 union perf_mem_data_src data_src_r;
591
592 if (left->mem_info)
593 data_src_l = left->mem_info->data_src;
594 else
595 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
596
597 if (right->mem_info)
598 data_src_r = right->mem_info->data_src;
599 else
600 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
601
602 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
603}
604
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300605static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100606 size_t size, unsigned int width)
607{
608 const char *out;
609 u64 mask = PERF_MEM_LOCK_NA;
610
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300611 if (he->mem_info)
612 mask = he->mem_info->data_src.mem_lock;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100613
614 if (mask & PERF_MEM_LOCK_NA)
615 out = "N/A";
616 else if (mask & PERF_MEM_LOCK_LOCKED)
617 out = "Yes";
618 else
619 out = "No";
620
621 return repsep_snprintf(bf, size, "%-*s", width, out);
622}
623
624static int64_t
625sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
626{
627 union perf_mem_data_src data_src_l;
628 union perf_mem_data_src data_src_r;
629
630 if (left->mem_info)
631 data_src_l = left->mem_info->data_src;
632 else
633 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
634
635 if (right->mem_info)
636 data_src_r = right->mem_info->data_src;
637 else
638 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
639
640 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
641}
642
643static const char * const tlb_access[] = {
644 "N/A",
645 "HIT",
646 "MISS",
647 "L1",
648 "L2",
649 "Walker",
650 "Fault",
651};
652#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
653
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300654static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100655 size_t size, unsigned int width)
656{
657 char out[64];
658 size_t sz = sizeof(out) - 1; /* -1 for null termination */
659 size_t l = 0, i;
660 u64 m = PERF_MEM_TLB_NA;
661 u64 hit, miss;
662
663 out[0] = '\0';
664
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300665 if (he->mem_info)
666 m = he->mem_info->data_src.mem_dtlb;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100667
668 hit = m & PERF_MEM_TLB_HIT;
669 miss = m & PERF_MEM_TLB_MISS;
670
671 /* already taken care of */
672 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
673
674 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
675 if (!(m & 0x1))
676 continue;
677 if (l) {
678 strcat(out, " or ");
679 l += 4;
680 }
681 strncat(out, tlb_access[i], sz - l);
682 l += strlen(tlb_access[i]);
683 }
684 if (*out == '\0')
685 strcpy(out, "N/A");
686 if (hit)
687 strncat(out, " hit", sz - l);
688 if (miss)
689 strncat(out, " miss", sz - l);
690
691 return repsep_snprintf(bf, size, "%-*s", width, out);
692}
693
694static int64_t
695sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
696{
697 union perf_mem_data_src data_src_l;
698 union perf_mem_data_src data_src_r;
699
700 if (left->mem_info)
701 data_src_l = left->mem_info->data_src;
702 else
703 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
704
705 if (right->mem_info)
706 data_src_r = right->mem_info->data_src;
707 else
708 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
709
710 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
711}
712
713static const char * const mem_lvl[] = {
714 "N/A",
715 "HIT",
716 "MISS",
717 "L1",
718 "LFB",
719 "L2",
720 "L3",
721 "Local RAM",
722 "Remote RAM (1 hop)",
723 "Remote RAM (2 hops)",
724 "Remote Cache (1 hop)",
725 "Remote Cache (2 hops)",
726 "I/O",
727 "Uncached",
728};
729#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
730
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300731static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100732 size_t size, unsigned int width)
733{
734 char out[64];
735 size_t sz = sizeof(out) - 1; /* -1 for null termination */
736 size_t i, l = 0;
737 u64 m = PERF_MEM_LVL_NA;
738 u64 hit, miss;
739
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300740 if (he->mem_info)
741 m = he->mem_info->data_src.mem_lvl;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100742
743 out[0] = '\0';
744
745 hit = m & PERF_MEM_LVL_HIT;
746 miss = m & PERF_MEM_LVL_MISS;
747
748 /* already taken care of */
749 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
750
751 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
752 if (!(m & 0x1))
753 continue;
754 if (l) {
755 strcat(out, " or ");
756 l += 4;
757 }
758 strncat(out, mem_lvl[i], sz - l);
759 l += strlen(mem_lvl[i]);
760 }
761 if (*out == '\0')
762 strcpy(out, "N/A");
763 if (hit)
764 strncat(out, " hit", sz - l);
765 if (miss)
766 strncat(out, " miss", sz - l);
767
768 return repsep_snprintf(bf, size, "%-*s", width, out);
769}
770
771static int64_t
772sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
773{
774 union perf_mem_data_src data_src_l;
775 union perf_mem_data_src data_src_r;
776
777 if (left->mem_info)
778 data_src_l = left->mem_info->data_src;
779 else
780 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
781
782 if (right->mem_info)
783 data_src_r = right->mem_info->data_src;
784 else
785 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
786
787 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
788}
789
790static const char * const snoop_access[] = {
791 "N/A",
792 "None",
793 "Miss",
794 "Hit",
795 "HitM",
796};
797#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
798
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300799static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
Stephane Eranian98a3b322013-01-24 16:10:35 +0100800 size_t size, unsigned int width)
801{
802 char out[64];
803 size_t sz = sizeof(out) - 1; /* -1 for null termination */
804 size_t i, l = 0;
805 u64 m = PERF_MEM_SNOOP_NA;
806
807 out[0] = '\0';
808
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300809 if (he->mem_info)
810 m = he->mem_info->data_src.mem_snoop;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100811
812 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
813 if (!(m & 0x1))
814 continue;
815 if (l) {
816 strcat(out, " or ");
817 l += 4;
818 }
819 strncat(out, snoop_access[i], sz - l);
820 l += strlen(snoop_access[i]);
821 }
822
823 if (*out == '\0')
824 strcpy(out, "N/A");
825
826 return repsep_snprintf(bf, size, "%-*s", width, out);
827}
828
Don Zickus9b32ba72014-06-01 15:38:29 +0200829static inline u64 cl_address(u64 address)
830{
831 /* return the cacheline of the address */
832 return (address & ~(cacheline_size - 1));
833}
834
835static int64_t
836sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
837{
838 u64 l, r;
839 struct map *l_map, *r_map;
840
841 if (!left->mem_info) return -1;
842 if (!right->mem_info) return 1;
843
844 /* group event types together */
845 if (left->cpumode > right->cpumode) return -1;
846 if (left->cpumode < right->cpumode) return 1;
847
848 l_map = left->mem_info->daddr.map;
849 r_map = right->mem_info->daddr.map;
850
851 /* if both are NULL, jump to sort on al_addr instead */
852 if (!l_map && !r_map)
853 goto addr;
854
855 if (!l_map) return -1;
856 if (!r_map) return 1;
857
858 if (l_map->maj > r_map->maj) return -1;
859 if (l_map->maj < r_map->maj) return 1;
860
861 if (l_map->min > r_map->min) return -1;
862 if (l_map->min < r_map->min) return 1;
863
864 if (l_map->ino > r_map->ino) return -1;
865 if (l_map->ino < r_map->ino) return 1;
866
867 if (l_map->ino_generation > r_map->ino_generation) return -1;
868 if (l_map->ino_generation < r_map->ino_generation) return 1;
869
870 /*
871 * Addresses with no major/minor numbers are assumed to be
872 * anonymous in userspace. Sort those on pid then address.
873 *
874 * The kernel and non-zero major/minor mapped areas are
875 * assumed to be unity mapped. Sort those on address.
876 */
877
878 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
879 (!(l_map->flags & MAP_SHARED)) &&
880 !l_map->maj && !l_map->min && !l_map->ino &&
881 !l_map->ino_generation) {
882 /* userspace anonymous */
883
884 if (left->thread->pid_ > right->thread->pid_) return -1;
885 if (left->thread->pid_ < right->thread->pid_) return 1;
886 }
887
888addr:
889 /* al_addr does all the right addr - start + offset calculations */
890 l = cl_address(left->mem_info->daddr.al_addr);
891 r = cl_address(right->mem_info->daddr.al_addr);
892
893 if (l > r) return -1;
894 if (l < r) return 1;
895
896 return 0;
897}
898
899static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
900 size_t size, unsigned int width)
901{
902
903 uint64_t addr = 0;
904 struct map *map = NULL;
905 struct symbol *sym = NULL;
906 char level = he->level;
907
908 if (he->mem_info) {
909 addr = cl_address(he->mem_info->daddr.al_addr);
910 map = he->mem_info->daddr.map;
911 sym = he->mem_info->daddr.sym;
912
913 /* print [s] for shared data mmaps */
914 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
915 map && (map->type == MAP__VARIABLE) &&
916 (map->flags & MAP_SHARED) &&
917 (map->maj || map->min || map->ino ||
918 map->ino_generation))
919 level = 's';
920 else if (!map)
921 level = 'X';
922 }
923 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
924 width);
925}
926
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100927struct sort_entry sort_mispredict = {
928 .se_header = "Branch Mispredicted",
929 .se_cmp = sort__mispredict_cmp,
930 .se_snprintf = hist_entry__mispredict_snprintf,
931 .se_width_idx = HISTC_MISPREDICT,
932};
933
Andi Kleen05484292013-01-24 16:10:29 +0100934static u64 he_weight(struct hist_entry *he)
935{
936 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
937}
938
939static int64_t
940sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
941{
942 return he_weight(left) - he_weight(right);
943}
944
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300945static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100946 size_t size, unsigned int width)
947{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300948 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
Andi Kleen05484292013-01-24 16:10:29 +0100949}
950
951struct sort_entry sort_local_weight = {
952 .se_header = "Local Weight",
953 .se_cmp = sort__local_weight_cmp,
954 .se_snprintf = hist_entry__local_weight_snprintf,
955 .se_width_idx = HISTC_LOCAL_WEIGHT,
956};
957
958static int64_t
959sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
960{
961 return left->stat.weight - right->stat.weight;
962}
963
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300964static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
Andi Kleen05484292013-01-24 16:10:29 +0100965 size_t size, unsigned int width)
966{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -0300967 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
Andi Kleen05484292013-01-24 16:10:29 +0100968}
969
970struct sort_entry sort_global_weight = {
971 .se_header = "Weight",
972 .se_cmp = sort__global_weight_cmp,
973 .se_snprintf = hist_entry__global_weight_snprintf,
974 .se_width_idx = HISTC_GLOBAL_WEIGHT,
975};
976
Stephane Eranian98a3b322013-01-24 16:10:35 +0100977struct sort_entry sort_mem_daddr_sym = {
978 .se_header = "Data Symbol",
979 .se_cmp = sort__daddr_cmp,
980 .se_snprintf = hist_entry__daddr_snprintf,
981 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
982};
983
984struct sort_entry sort_mem_daddr_dso = {
985 .se_header = "Data Object",
986 .se_cmp = sort__dso_daddr_cmp,
987 .se_snprintf = hist_entry__dso_daddr_snprintf,
988 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
989};
990
991struct sort_entry sort_mem_locked = {
992 .se_header = "Locked",
993 .se_cmp = sort__locked_cmp,
994 .se_snprintf = hist_entry__locked_snprintf,
995 .se_width_idx = HISTC_MEM_LOCKED,
996};
997
998struct sort_entry sort_mem_tlb = {
999 .se_header = "TLB access",
1000 .se_cmp = sort__tlb_cmp,
1001 .se_snprintf = hist_entry__tlb_snprintf,
1002 .se_width_idx = HISTC_MEM_TLB,
1003};
1004
1005struct sort_entry sort_mem_lvl = {
1006 .se_header = "Memory access",
1007 .se_cmp = sort__lvl_cmp,
1008 .se_snprintf = hist_entry__lvl_snprintf,
1009 .se_width_idx = HISTC_MEM_LVL,
1010};
1011
1012struct sort_entry sort_mem_snoop = {
1013 .se_header = "Snoop",
1014 .se_cmp = sort__snoop_cmp,
1015 .se_snprintf = hist_entry__snoop_snprintf,
1016 .se_width_idx = HISTC_MEM_SNOOP,
1017};
1018
Don Zickus9b32ba72014-06-01 15:38:29 +02001019struct sort_entry sort_mem_dcacheline = {
1020 .se_header = "Data Cacheline",
1021 .se_cmp = sort__dcacheline_cmp,
1022 .se_snprintf = hist_entry__dcacheline_snprintf,
1023 .se_width_idx = HISTC_MEM_DCACHELINE,
1024};
1025
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001026static int64_t
1027sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1028{
Jiri Olsa49f47442014-10-16 16:07:01 +02001029 if (!left->branch_info || !right->branch_info)
1030 return cmp_null(left->branch_info, right->branch_info);
1031
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001032 return left->branch_info->flags.abort !=
1033 right->branch_info->flags.abort;
1034}
1035
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001036static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001037 size_t size, unsigned int width)
1038{
Jiri Olsa49f47442014-10-16 16:07:01 +02001039 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001040
Jiri Olsa49f47442014-10-16 16:07:01 +02001041 if (he->branch_info) {
1042 if (he->branch_info->flags.abort)
1043 out = "A";
1044 else
1045 out = ".";
1046 }
1047
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001048 return repsep_snprintf(bf, size, "%-*s", width, out);
1049}
1050
1051struct sort_entry sort_abort = {
1052 .se_header = "Transaction abort",
1053 .se_cmp = sort__abort_cmp,
1054 .se_snprintf = hist_entry__abort_snprintf,
1055 .se_width_idx = HISTC_ABORT,
1056};
1057
1058static int64_t
1059sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1060{
Jiri Olsa0199d242014-10-16 16:07:02 +02001061 if (!left->branch_info || !right->branch_info)
1062 return cmp_null(left->branch_info, right->branch_info);
1063
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001064 return left->branch_info->flags.in_tx !=
1065 right->branch_info->flags.in_tx;
1066}
1067
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001068static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001069 size_t size, unsigned int width)
1070{
Jiri Olsa0199d242014-10-16 16:07:02 +02001071 static const char *out = "N/A";
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001072
Jiri Olsa0199d242014-10-16 16:07:02 +02001073 if (he->branch_info) {
1074 if (he->branch_info->flags.in_tx)
1075 out = "T";
1076 else
1077 out = ".";
1078 }
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001079
1080 return repsep_snprintf(bf, size, "%-*s", width, out);
1081}
1082
1083struct sort_entry sort_in_tx = {
1084 .se_header = "Branch in transaction",
1085 .se_cmp = sort__in_tx_cmp,
1086 .se_snprintf = hist_entry__in_tx_snprintf,
1087 .se_width_idx = HISTC_IN_TX,
1088};
1089
Andi Kleen475eeab2013-09-20 07:40:43 -07001090static int64_t
1091sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1092{
1093 return left->transaction - right->transaction;
1094}
1095
1096static inline char *add_str(char *p, const char *str)
1097{
1098 strcpy(p, str);
1099 return p + strlen(str);
1100}
1101
1102static struct txbit {
1103 unsigned flag;
1104 const char *name;
1105 int skip_for_len;
1106} txbits[] = {
1107 { PERF_TXN_ELISION, "EL ", 0 },
1108 { PERF_TXN_TRANSACTION, "TX ", 1 },
1109 { PERF_TXN_SYNC, "SYNC ", 1 },
1110 { PERF_TXN_ASYNC, "ASYNC ", 0 },
1111 { PERF_TXN_RETRY, "RETRY ", 0 },
1112 { PERF_TXN_CONFLICT, "CON ", 0 },
1113 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1114 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 },
1115 { 0, NULL, 0 }
1116};
1117
1118int hist_entry__transaction_len(void)
1119{
1120 int i;
1121 int len = 0;
1122
1123 for (i = 0; txbits[i].name; i++) {
1124 if (!txbits[i].skip_for_len)
1125 len += strlen(txbits[i].name);
1126 }
1127 len += 4; /* :XX<space> */
1128 return len;
1129}
1130
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001131static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
Andi Kleen475eeab2013-09-20 07:40:43 -07001132 size_t size, unsigned int width)
1133{
Arnaldo Carvalho de Meloc824c432013-10-22 19:01:31 -03001134 u64 t = he->transaction;
Andi Kleen475eeab2013-09-20 07:40:43 -07001135 char buf[128];
1136 char *p = buf;
1137 int i;
1138
1139 buf[0] = 0;
1140 for (i = 0; txbits[i].name; i++)
1141 if (txbits[i].flag & t)
1142 p = add_str(p, txbits[i].name);
1143 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1144 p = add_str(p, "NEITHER ");
1145 if (t & PERF_TXN_ABORT_MASK) {
1146 sprintf(p, ":%" PRIx64,
1147 (t & PERF_TXN_ABORT_MASK) >>
1148 PERF_TXN_ABORT_SHIFT);
1149 p += strlen(p);
1150 }
1151
1152 return repsep_snprintf(bf, size, "%-*s", width, buf);
1153}
1154
1155struct sort_entry sort_transaction = {
1156 .se_header = "Transaction ",
1157 .se_cmp = sort__transaction_cmp,
1158 .se_snprintf = hist_entry__transaction_snprintf,
1159 .se_width_idx = HISTC_TRANSACTION,
1160};
1161
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001162struct sort_dimension {
1163 const char *name;
1164 struct sort_entry *entry;
1165 int taken;
1166};
1167
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001168#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1169
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001170static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001171 DIM(SORT_PID, "pid", sort_thread),
1172 DIM(SORT_COMM, "comm", sort_comm),
1173 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001174 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +01001175 DIM(SORT_PARENT, "parent", sort_parent),
1176 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -03001177 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleenf9ea55d2013-07-18 15:58:53 -07001178 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1179 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Andi Kleen475eeab2013-09-20 07:40:43 -07001180 DIM(SORT_TRANSACTION, "transaction", sort_transaction),
Frederic Weisbecker872a8782011-06-29 03:14:52 +02001181};
1182
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001183#undef DIM
1184
1185#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1186
1187static struct sort_dimension bstack_sort_dimensions[] = {
1188 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1189 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1190 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1191 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1192 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
Andi Kleenf5d05bc2013-09-20 07:40:41 -07001193 DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1194 DIM(SORT_ABORT, "abort", sort_abort),
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001195};
1196
1197#undef DIM
1198
Namhyung Kimafab87b2013-04-03 21:26:11 +09001199#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1200
1201static struct sort_dimension memory_sort_dimensions[] = {
Namhyung Kimafab87b2013-04-03 21:26:11 +09001202 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1203 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1204 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1205 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1206 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1207 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Don Zickus9b32ba72014-06-01 15:38:29 +02001208 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
Namhyung Kimafab87b2013-04-03 21:26:11 +09001209};
1210
1211#undef DIM
1212
Namhyung Kima2ce0672014-03-04 09:06:42 +09001213struct hpp_dimension {
1214 const char *name;
1215 struct perf_hpp_fmt *fmt;
1216 int taken;
1217};
1218
1219#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1220
1221static struct hpp_dimension hpp_sort_dimensions[] = {
1222 DIM(PERF_HPP__OVERHEAD, "overhead"),
1223 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1224 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1225 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1226 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
Namhyung Kim594dcbf2013-10-30 16:06:59 +09001227 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
Namhyung Kima2ce0672014-03-04 09:06:42 +09001228 DIM(PERF_HPP__SAMPLES, "sample"),
1229 DIM(PERF_HPP__PERIOD, "period"),
1230};
1231
1232#undef DIM
1233
Namhyung Kim8b536992014-03-03 11:46:55 +09001234struct hpp_sort_entry {
1235 struct perf_hpp_fmt hpp;
1236 struct sort_entry *se;
1237};
1238
Namhyung Kima7d945b2014-03-04 10:46:34 +09001239bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1240{
1241 struct hpp_sort_entry *hse_a;
1242 struct hpp_sort_entry *hse_b;
1243
1244 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1245 return false;
1246
1247 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1248 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1249
1250 return hse_a->se == hse_b->se;
1251}
1252
Namhyung Kime0d66c72014-07-31 14:47:37 +09001253void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
Namhyung Kim678a5002014-03-20 11:18:54 +09001254{
1255 struct hpp_sort_entry *hse;
1256
1257 if (!perf_hpp__is_sort_entry(fmt))
1258 return;
1259
1260 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001261 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
Namhyung Kim678a5002014-03-20 11:18:54 +09001262}
1263
Namhyung Kim8b536992014-03-03 11:46:55 +09001264static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1265 struct perf_evsel *evsel)
1266{
1267 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001268 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001269
1270 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim8b536992014-03-03 11:46:55 +09001271
Namhyung Kim5b591662014-07-31 14:47:38 +09001272 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001273 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001274
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001275 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
Namhyung Kim8b536992014-03-03 11:46:55 +09001276}
1277
1278static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1279 struct perf_hpp *hpp __maybe_unused,
1280 struct perf_evsel *evsel)
1281{
1282 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001283 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001284
1285 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1286
Namhyung Kim5b591662014-07-31 14:47:38 +09001287 if (!len)
Arnaldo Carvalho de Melo4ea062ed2014-10-09 13:13:41 -03001288 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx);
Namhyung Kim5b591662014-07-31 14:47:38 +09001289
1290 return len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001291}
1292
1293static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1294 struct hist_entry *he)
1295{
1296 struct hpp_sort_entry *hse;
Namhyung Kim5b591662014-07-31 14:47:38 +09001297 size_t len = fmt->user_len;
Namhyung Kim8b536992014-03-03 11:46:55 +09001298
1299 hse = container_of(fmt, struct hpp_sort_entry, hpp);
Namhyung Kim5b591662014-07-31 14:47:38 +09001300
1301 if (!len)
1302 len = hists__col_len(he->hists, hse->se->se_width_idx);
Namhyung Kim8b536992014-03-03 11:46:55 +09001303
1304 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1305}
1306
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001307static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1308 struct hist_entry *a, struct hist_entry *b)
1309{
1310 struct hpp_sort_entry *hse;
1311
1312 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1313 return hse->se->se_cmp(a, b);
1314}
1315
1316static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1317 struct hist_entry *a, struct hist_entry *b)
1318{
1319 struct hpp_sort_entry *hse;
1320 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1321
1322 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1323 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1324 return collapse_fn(a, b);
1325}
1326
1327static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1328 struct hist_entry *a, struct hist_entry *b)
1329{
1330 struct hpp_sort_entry *hse;
1331 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1332
1333 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1334 sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1335 return sort_fn(a, b);
1336}
1337
Namhyung Kima7d945b2014-03-04 10:46:34 +09001338static struct hpp_sort_entry *
1339__sort_dimension__alloc_hpp(struct sort_dimension *sd)
Namhyung Kim8b536992014-03-03 11:46:55 +09001340{
1341 struct hpp_sort_entry *hse;
1342
1343 hse = malloc(sizeof(*hse));
1344 if (hse == NULL) {
1345 pr_err("Memory allocation failed\n");
Namhyung Kima7d945b2014-03-04 10:46:34 +09001346 return NULL;
Namhyung Kim8b536992014-03-03 11:46:55 +09001347 }
1348
1349 hse->se = sd->entry;
Namhyung Kim1ecd4452014-07-31 14:47:40 +09001350 hse->hpp.name = sd->entry->se_header;
Namhyung Kim8b536992014-03-03 11:46:55 +09001351 hse->hpp.header = __sort__hpp_header;
1352 hse->hpp.width = __sort__hpp_width;
1353 hse->hpp.entry = __sort__hpp_entry;
1354 hse->hpp.color = NULL;
1355
Namhyung Kim87bbdf72015-01-08 09:45:46 +09001356 hse->hpp.cmp = __sort__hpp_cmp;
1357 hse->hpp.collapse = __sort__hpp_collapse;
1358 hse->hpp.sort = __sort__hpp_sort;
Namhyung Kim8b536992014-03-03 11:46:55 +09001359
1360 INIT_LIST_HEAD(&hse->hpp.list);
1361 INIT_LIST_HEAD(&hse->hpp.sort_list);
Jiri Olsaf2998422014-05-23 17:15:47 +02001362 hse->hpp.elide = false;
Namhyung Kime0d66c72014-07-31 14:47:37 +09001363 hse->hpp.len = 0;
Namhyung Kim5b591662014-07-31 14:47:38 +09001364 hse->hpp.user_len = 0;
Namhyung Kim8b536992014-03-03 11:46:55 +09001365
Namhyung Kima7d945b2014-03-04 10:46:34 +09001366 return hse;
1367}
1368
1369bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1370{
1371 return format->header == __sort__hpp_header;
1372}
1373
1374static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1375{
1376 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1377
1378 if (hse == NULL)
1379 return -1;
1380
Namhyung Kim8b536992014-03-03 11:46:55 +09001381 perf_hpp__register_sort_field(&hse->hpp);
1382 return 0;
1383}
1384
Namhyung Kima7d945b2014-03-04 10:46:34 +09001385static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1386{
1387 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1388
1389 if (hse == NULL)
1390 return -1;
1391
1392 perf_hpp__column_register(&hse->hpp);
1393 return 0;
1394}
1395
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001396static int __sort_dimension__add(struct sort_dimension *sd)
Namhyung Kim2f532d02013-04-03 21:26:10 +09001397{
1398 if (sd->taken)
Namhyung Kim8b536992014-03-03 11:46:55 +09001399 return 0;
1400
Namhyung Kima7d945b2014-03-04 10:46:34 +09001401 if (__sort_dimension__add_hpp_sort(sd) < 0)
Namhyung Kim8b536992014-03-03 11:46:55 +09001402 return -1;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001403
1404 if (sd->entry->se_collapse)
1405 sort__need_collapse = 1;
1406
Namhyung Kim2f532d02013-04-03 21:26:10 +09001407 sd->taken = 1;
Namhyung Kim8b536992014-03-03 11:46:55 +09001408
1409 return 0;
Namhyung Kim2f532d02013-04-03 21:26:10 +09001410}
1411
Namhyung Kima2ce0672014-03-04 09:06:42 +09001412static int __hpp_dimension__add(struct hpp_dimension *hd)
1413{
1414 if (!hd->taken) {
1415 hd->taken = 1;
1416
1417 perf_hpp__register_sort_field(hd->fmt);
1418 }
1419 return 0;
1420}
1421
Namhyung Kima7d945b2014-03-04 10:46:34 +09001422static int __sort_dimension__add_output(struct sort_dimension *sd)
1423{
1424 if (sd->taken)
1425 return 0;
1426
1427 if (__sort_dimension__add_hpp_output(sd) < 0)
1428 return -1;
1429
1430 sd->taken = 1;
1431 return 0;
1432}
1433
1434static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1435{
1436 if (!hd->taken) {
1437 hd->taken = 1;
1438
1439 perf_hpp__column_register(hd->fmt);
1440 }
1441 return 0;
1442}
1443
John Kacurdd68ada2009-09-24 18:02:49 +02001444int sort_dimension__add(const char *tok)
1445{
1446 unsigned int i;
1447
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001448 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1449 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +02001450
John Kacurdd68ada2009-09-24 18:02:49 +02001451 if (strncasecmp(tok, sd->name, strlen(tok)))
1452 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001453
John Kacurdd68ada2009-09-24 18:02:49 +02001454 if (sd->entry == &sort_parent) {
1455 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
1456 if (ret) {
1457 char err[BUFSIZ];
1458
1459 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -03001460 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
1461 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +02001462 }
1463 sort__has_parent = 1;
Namhyung Kim930477b2013-04-05 10:26:36 +09001464 } else if (sd->entry == &sort_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +09001465 sort__has_sym = 1;
Kan Liang94ba4622015-02-09 05:39:44 +00001466 /*
1467 * perf diff displays the performance difference amongst
1468 * two or more perf.data files. Those files could come
1469 * from different binaries. So we should not compare
1470 * their ips, but the name of symbol.
1471 */
1472 if (sort__mode == SORT_MODE__DIFF)
1473 sd->entry->se_collapse = sort__sym_sort;
1474
Namhyung Kim68f6d022013-12-18 14:21:10 +09001475 } else if (sd->entry == &sort_dso) {
1476 sort__has_dso = 1;
John Kacurdd68ada2009-09-24 18:02:49 +02001477 }
1478
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001479 return __sort_dimension__add(sd);
John Kacurdd68ada2009-09-24 18:02:49 +02001480 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001481
Namhyung Kima2ce0672014-03-04 09:06:42 +09001482 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1483 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1484
1485 if (strncasecmp(tok, hd->name, strlen(tok)))
1486 continue;
1487
1488 return __hpp_dimension__add(hd);
1489 }
1490
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001491 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1492 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1493
1494 if (strncasecmp(tok, sd->name, strlen(tok)))
1495 continue;
1496
Namhyung Kim55369fc2013-04-01 20:35:20 +09001497 if (sort__mode != SORT_MODE__BRANCH)
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001498 return -EINVAL;
1499
1500 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1501 sort__has_sym = 1;
1502
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001503 __sort_dimension__add(sd);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001504 return 0;
1505 }
1506
Namhyung Kimafab87b2013-04-03 21:26:11 +09001507 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1508 struct sort_dimension *sd = &memory_sort_dimensions[i];
1509
1510 if (strncasecmp(tok, sd->name, strlen(tok)))
1511 continue;
1512
1513 if (sort__mode != SORT_MODE__MEMORY)
1514 return -EINVAL;
1515
1516 if (sd->entry == &sort_mem_daddr_sym)
1517 sort__has_sym = 1;
1518
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001519 __sort_dimension__add(sd);
Namhyung Kimafab87b2013-04-03 21:26:11 +09001520 return 0;
1521 }
1522
John Kacurdd68ada2009-09-24 18:02:49 +02001523 return -ESRCH;
1524}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001525
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001526static const char *get_default_sort_order(void)
1527{
1528 const char *default_sort_orders[] = {
1529 default_sort_order,
1530 default_branch_sort_order,
1531 default_mem_sort_order,
1532 default_top_sort_order,
1533 default_diff_sort_order,
1534 };
1535
1536 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1537
1538 return default_sort_orders[sort__mode];
1539}
1540
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001541static int setup_sort_order(void)
1542{
1543 char *new_sort_order;
1544
1545 /*
1546 * Append '+'-prefixed sort order to the default sort
1547 * order string.
1548 */
1549 if (!sort_order || is_strict_order(sort_order))
1550 return 0;
1551
1552 if (sort_order[1] == '\0') {
1553 error("Invalid --sort key: `+'");
1554 return -EINVAL;
1555 }
1556
1557 /*
1558 * We allocate new sort_order string, but we never free it,
1559 * because it's checked over the rest of the code.
1560 */
1561 if (asprintf(&new_sort_order, "%s,%s",
1562 get_default_sort_order(), sort_order + 1) < 0) {
1563 error("Not enough memory to set up --sort");
1564 return -ENOMEM;
1565 }
1566
1567 sort_order = new_sort_order;
1568 return 0;
1569}
1570
Namhyung Kima7d945b2014-03-04 10:46:34 +09001571static int __setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001572{
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001573 char *tmp, *tok, *str;
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001574 const char *sort_keys;
Namhyung Kim55309982013-02-06 14:57:16 +09001575 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001576
Jiri Olsa1a1c0ff2014-08-23 14:59:48 +02001577 ret = setup_sort_order();
1578 if (ret)
1579 return ret;
1580
1581 sort_keys = sort_order;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001582 if (sort_keys == NULL) {
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001583 if (is_strict_order(field_order)) {
Namhyung Kima7d945b2014-03-04 10:46:34 +09001584 /*
1585 * If user specified field order but no sort order,
1586 * we'll honor it and not add default sort orders.
1587 */
1588 return 0;
1589 }
1590
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001591 sort_keys = get_default_sort_order();
Namhyung Kima7d945b2014-03-04 10:46:34 +09001592 }
Namhyung Kim512ae1b2014-03-18 11:31:39 +09001593
1594 str = strdup(sort_keys);
Namhyung Kim5936f542013-02-06 14:57:17 +09001595 if (str == NULL) {
1596 error("Not enough memory to setup sort keys");
1597 return -ENOMEM;
1598 }
1599
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001600 for (tok = strtok_r(str, ", ", &tmp);
1601 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +09001602 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001603 if (ret == -EINVAL) {
1604 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001605 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +09001606 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001607 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +09001608 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001609 }
1610 }
1611
1612 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +09001613 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -02001614}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001615
Jiri Olsaf2998422014-05-23 17:15:47 +02001616void perf_hpp__set_elide(int idx, bool elide)
Namhyung Kime67d49a2014-03-18 13:00:59 +09001617{
Jiri Olsaf2998422014-05-23 17:15:47 +02001618 struct perf_hpp_fmt *fmt;
1619 struct hpp_sort_entry *hse;
Namhyung Kime67d49a2014-03-18 13:00:59 +09001620
Jiri Olsaf2998422014-05-23 17:15:47 +02001621 perf_hpp__for_each_format(fmt) {
1622 if (!perf_hpp__is_sort_entry(fmt))
1623 continue;
1624
1625 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1626 if (hse->se->se_width_idx == idx) {
1627 fmt->elide = elide;
1628 break;
1629 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001630 }
Namhyung Kime67d49a2014-03-18 13:00:59 +09001631}
1632
Jiri Olsaf2998422014-05-23 17:15:47 +02001633static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001634{
1635 if (list && strlist__nr_entries(list) == 1) {
1636 if (fp != NULL)
1637 fprintf(fp, "# %s: %s\n", list_name,
1638 strlist__entry(list, 0)->s);
Jiri Olsaf2998422014-05-23 17:15:47 +02001639 return true;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001640 }
Jiri Olsaf2998422014-05-23 17:15:47 +02001641 return false;
1642}
1643
1644static bool get_elide(int idx, FILE *output)
1645{
1646 switch (idx) {
1647 case HISTC_SYMBOL:
1648 return __get_elide(symbol_conf.sym_list, "symbol", output);
1649 case HISTC_DSO:
1650 return __get_elide(symbol_conf.dso_list, "dso", output);
1651 case HISTC_COMM:
1652 return __get_elide(symbol_conf.comm_list, "comm", output);
1653 default:
1654 break;
1655 }
1656
1657 if (sort__mode != SORT_MODE__BRANCH)
1658 return false;
1659
1660 switch (idx) {
1661 case HISTC_SYMBOL_FROM:
1662 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1663 case HISTC_SYMBOL_TO:
1664 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1665 case HISTC_DSO_FROM:
1666 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1667 case HISTC_DSO_TO:
1668 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1669 default:
1670 break;
1671 }
1672
1673 return false;
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -02001674}
Namhyung Kim08e71542013-04-03 21:26:19 +09001675
1676void sort__setup_elide(FILE *output)
1677{
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001678 struct perf_hpp_fmt *fmt;
1679 struct hpp_sort_entry *hse;
Namhyung Kim7524f632013-11-08 17:53:42 +09001680
Jiri Olsaf2998422014-05-23 17:15:47 +02001681 perf_hpp__for_each_format(fmt) {
1682 if (!perf_hpp__is_sort_entry(fmt))
1683 continue;
Namhyung Kim08e71542013-04-03 21:26:19 +09001684
Jiri Olsaf2998422014-05-23 17:15:47 +02001685 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1686 fmt->elide = get_elide(hse->se->se_width_idx, output);
Namhyung Kim08e71542013-04-03 21:26:19 +09001687 }
1688
Namhyung Kim7524f632013-11-08 17:53:42 +09001689 /*
1690 * It makes no sense to elide all of sort entries.
1691 * Just revert them to show up again.
1692 */
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001693 perf_hpp__for_each_format(fmt) {
1694 if (!perf_hpp__is_sort_entry(fmt))
1695 continue;
1696
Jiri Olsaf2998422014-05-23 17:15:47 +02001697 if (!fmt->elide)
Namhyung Kim7524f632013-11-08 17:53:42 +09001698 return;
1699 }
1700
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001701 perf_hpp__for_each_format(fmt) {
1702 if (!perf_hpp__is_sort_entry(fmt))
1703 continue;
1704
Jiri Olsaf2998422014-05-23 17:15:47 +02001705 fmt->elide = false;
Namhyung Kimcfaa1542014-05-19 14:19:30 +09001706 }
Namhyung Kim08e71542013-04-03 21:26:19 +09001707}
Namhyung Kima7d945b2014-03-04 10:46:34 +09001708
1709static int output_field_add(char *tok)
1710{
1711 unsigned int i;
1712
1713 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1714 struct sort_dimension *sd = &common_sort_dimensions[i];
1715
1716 if (strncasecmp(tok, sd->name, strlen(tok)))
1717 continue;
1718
1719 return __sort_dimension__add_output(sd);
1720 }
1721
1722 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1723 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1724
1725 if (strncasecmp(tok, hd->name, strlen(tok)))
1726 continue;
1727
1728 return __hpp_dimension__add_output(hd);
1729 }
1730
1731 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1732 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1733
1734 if (strncasecmp(tok, sd->name, strlen(tok)))
1735 continue;
1736
1737 return __sort_dimension__add_output(sd);
1738 }
1739
1740 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1741 struct sort_dimension *sd = &memory_sort_dimensions[i];
1742
1743 if (strncasecmp(tok, sd->name, strlen(tok)))
1744 continue;
1745
1746 return __sort_dimension__add_output(sd);
1747 }
1748
1749 return -ESRCH;
1750}
1751
1752static void reset_dimensions(void)
1753{
1754 unsigned int i;
1755
1756 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1757 common_sort_dimensions[i].taken = 0;
1758
1759 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1760 hpp_sort_dimensions[i].taken = 0;
1761
1762 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1763 bstack_sort_dimensions[i].taken = 0;
1764
1765 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1766 memory_sort_dimensions[i].taken = 0;
1767}
1768
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001769bool is_strict_order(const char *order)
1770{
1771 return order && (*order != '+');
1772}
1773
Namhyung Kima7d945b2014-03-04 10:46:34 +09001774static int __setup_output_field(void)
1775{
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001776 char *tmp, *tok, *str, *strp;
1777 int ret = -EINVAL;
Namhyung Kima7d945b2014-03-04 10:46:34 +09001778
1779 if (field_order == NULL)
1780 return 0;
1781
1782 reset_dimensions();
1783
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001784 strp = str = strdup(field_order);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001785 if (str == NULL) {
1786 error("Not enough memory to setup output fields");
1787 return -ENOMEM;
1788 }
1789
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001790 if (!is_strict_order(field_order))
1791 strp++;
1792
1793 if (!strlen(strp)) {
1794 error("Invalid --fields key: `+'");
1795 goto out;
1796 }
1797
1798 for (tok = strtok_r(strp, ", ", &tmp);
Namhyung Kima7d945b2014-03-04 10:46:34 +09001799 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1800 ret = output_field_add(tok);
1801 if (ret == -EINVAL) {
1802 error("Invalid --fields key: `%s'", tok);
1803 break;
1804 } else if (ret == -ESRCH) {
1805 error("Unknown --fields key: `%s'", tok);
1806 break;
1807 }
1808 }
1809
Jiri Olsa2f3f9bc2014-08-22 15:58:38 +02001810out:
Namhyung Kima7d945b2014-03-04 10:46:34 +09001811 free(str);
1812 return ret;
1813}
1814
1815int setup_sorting(void)
1816{
1817 int err;
1818
1819 err = __setup_sorting();
1820 if (err < 0)
1821 return err;
1822
1823 if (parent_pattern != default_parent_pattern) {
1824 err = sort_dimension__add("parent");
1825 if (err < 0)
1826 return err;
1827 }
1828
1829 reset_dimensions();
1830
1831 /*
1832 * perf diff doesn't use default hpp output fields.
1833 */
1834 if (sort__mode != SORT_MODE__DIFF)
1835 perf_hpp__init();
1836
1837 err = __setup_output_field();
1838 if (err < 0)
1839 return err;
1840
1841 /* copy sort keys to output fields */
1842 perf_hpp__setup_output_field();
1843 /* and then copy output fields to sort keys */
1844 perf_hpp__append_sort_keys();
1845
1846 return 0;
1847}
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001848
1849void reset_output_field(void)
1850{
1851 sort__need_collapse = 0;
1852 sort__has_parent = 0;
1853 sort__has_sym = 0;
1854 sort__has_dso = 0;
1855
Namhyung Kimd69b2962014-05-23 10:59:01 +09001856 field_order = NULL;
1857 sort_order = NULL;
1858
Namhyung Kim1c89fe92014-05-07 18:42:24 +09001859 reset_dimensions();
1860 perf_hpp__reset_output_field();
1861}