blob: 5f52d492590c02dff879b4558b51b151dafe7204 [file] [log] [blame]
John Kacurdd68ada2009-09-24 18:02:49 +02001#include "sort.h"
Arnaldo Carvalho de Melo8a6c5b22010-07-20 14:42:52 -03002#include "hist.h"
John Kacurdd68ada2009-09-24 18:02:49 +02003
4regex_t parent_regex;
Arnaldo Carvalho de Meloedb7c602010-05-17 16:22:41 -03005const char default_parent_pattern[] = "^sys_|^do_page_fault";
6const char *parent_pattern = default_parent_pattern;
7const char default_sort_order[] = "comm,dso,symbol";
8const char *sort_order = default_sort_order;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +02009int sort__need_collapse = 0;
10int sort__has_parent = 0;
Namhyung Kim1af556402012-09-14 17:35:27 +090011int sort__has_sym = 0;
Stephane Eranian993ac882012-03-08 23:47:47 +010012int sort__branch_mode = -1; /* -1 = means not set */
Frederic Weisbeckera4fb5812009-10-22 23:23:23 +020013
14enum sort_type sort__first_dimension;
John Kacurdd68ada2009-09-24 18:02:49 +020015
John Kacurdd68ada2009-09-24 18:02:49 +020016LIST_HEAD(hist_entry__sort_list);
17
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030018static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
John Kacurdd68ada2009-09-24 18:02:49 +020019{
20 int n;
21 va_list ap;
22
23 va_start(ap, fmt);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030024 n = vsnprintf(bf, size, fmt, ap);
Jiri Olsa0ca0c132012-09-06 17:46:56 +020025 if (symbol_conf.field_sep && n > 0) {
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030026 char *sep = bf;
John Kacurdd68ada2009-09-24 18:02:49 +020027
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030028 while (1) {
Jiri Olsa0ca0c132012-09-06 17:46:56 +020029 sep = strchr(sep, *symbol_conf.field_sep);
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030030 if (sep == NULL)
31 break;
32 *sep = '.';
John Kacurdd68ada2009-09-24 18:02:49 +020033 }
John Kacurdd68ada2009-09-24 18:02:49 +020034 }
35 va_end(ap);
Anton Blanchardb8327962012-03-07 11:42:49 +110036
37 if (n >= (int)size)
38 return size - 1;
John Kacurdd68ada2009-09-24 18:02:49 +020039 return n;
40}
41
Frederic Weisbecker872a8782011-06-29 03:14:52 +020042static int64_t cmp_null(void *l, void *r)
43{
44 if (!l && !r)
45 return 0;
46 else if (!l)
47 return -1;
48 else
49 return 1;
50}
51
52/* --sort pid */
53
54static int64_t
55sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
56{
57 return right->thread->pid - left->thread->pid;
58}
59
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030060static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
61 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020062{
Namhyung Kimfb29a332012-12-27 18:11:40 +090063 return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
John Kacurdd68ada2009-09-24 18:02:49 +020064 self->thread->comm ?: "", self->thread->pid);
65}
66
Frederic Weisbecker872a8782011-06-29 03:14:52 +020067struct sort_entry sort_thread = {
68 .se_header = "Command: Pid",
69 .se_cmp = sort__thread_cmp,
70 .se_snprintf = hist_entry__thread_snprintf,
71 .se_width_idx = HISTC_THREAD,
72};
73
74/* --sort comm */
75
76static int64_t
77sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
78{
79 return right->thread->pid - left->thread->pid;
80}
81
82static int64_t
83sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
84{
85 char *comm_l = left->thread->comm;
86 char *comm_r = right->thread->comm;
87
88 if (!comm_l || !comm_r)
89 return cmp_null(comm_l, comm_r);
90
91 return strcmp(comm_l, comm_r);
92}
93
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030094static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
95 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +020096{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -030097 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
John Kacurdd68ada2009-09-24 18:02:49 +020098}
99
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900100struct sort_entry sort_comm = {
101 .se_header = "Command",
102 .se_cmp = sort__comm_cmp,
103 .se_collapse = sort__comm_collapse,
104 .se_snprintf = hist_entry__comm_snprintf,
105 .se_width_idx = HISTC_COMM,
106};
107
108/* --sort dso */
109
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100110static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
John Kacurdd68ada2009-09-24 18:02:49 +0200111{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100112 struct dso *dso_l = map_l ? map_l->dso : NULL;
113 struct dso *dso_r = map_r ? map_r->dso : NULL;
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300114 const char *dso_name_l, *dso_name_r;
John Kacurdd68ada2009-09-24 18:02:49 +0200115
116 if (!dso_l || !dso_r)
117 return cmp_null(dso_l, dso_r);
118
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300119 if (verbose) {
120 dso_name_l = dso_l->long_name;
121 dso_name_r = dso_r->long_name;
122 } else {
123 dso_name_l = dso_l->short_name;
124 dso_name_r = dso_r->short_name;
125 }
126
127 return strcmp(dso_name_l, dso_name_r);
John Kacurdd68ada2009-09-24 18:02:49 +0200128}
129
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100130static int64_t
131sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
John Kacurdd68ada2009-09-24 18:02:49 +0200132{
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100133 return _sort__dso_cmp(left->ms.map, right->ms.map);
134}
135
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100136static int _hist_entry__dso_snprintf(struct map *map, char *bf,
137 size_t size, unsigned int width)
138{
139 if (map && map->dso) {
140 const char *dso_name = !verbose ? map->dso->short_name :
141 map->dso->long_name;
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300142 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
Arnaldo Carvalho de Melo439d4732009-10-02 03:29:58 -0300143 }
John Kacurdd68ada2009-09-24 18:02:49 +0200144
Ian Munsie1437a302010-12-06 13:37:04 +1100145 return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
John Kacurdd68ada2009-09-24 18:02:49 +0200146}
147
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100148static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
149 size_t size, unsigned int width)
150{
151 return _hist_entry__dso_snprintf(self->ms.map, bf, size, width);
152}
153
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900154struct sort_entry sort_dso = {
155 .se_header = "Shared Object",
156 .se_cmp = sort__dso_cmp,
157 .se_snprintf = hist_entry__dso_snprintf,
158 .se_width_idx = HISTC_DSO,
159};
160
161/* --sort symbol */
162
Namhyung Kim51f27d12013-02-06 14:57:15 +0900163static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900164{
Namhyung Kim51f27d12013-02-06 14:57:15 +0900165 u64 ip_l, ip_r;
166
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900167 if (!sym_l || !sym_r)
168 return cmp_null(sym_l, sym_r);
169
170 if (sym_l == sym_r)
171 return 0;
172
173 ip_l = sym_l->start;
174 ip_r = sym_r->start;
175
176 return (int64_t)(ip_r - ip_l);
177}
178
179static int64_t
180sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
181{
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900182 if (!left->ms.sym && !right->ms.sym)
183 return right->level - left->level;
184
Namhyung Kim51f27d12013-02-06 14:57:15 +0900185 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900186}
187
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100188static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
189 u64 ip, char level, char *bf, size_t size,
Namhyung Kim43355522012-12-27 18:11:39 +0900190 unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100191{
192 size_t ret = 0;
193
194 if (verbose) {
195 char o = map ? dso__symtab_origin(map->dso) : '!';
196 ret += repsep_snprintf(bf, size, "%-#*llx %c ",
197 BITS_PER_LONG / 4, ip, o);
198 }
199
200 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
Stephane Eranian98a3b322013-01-24 16:10:35 +0100201 if (sym && map) {
202 if (map->type == MAP__VARIABLE) {
203 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
204 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
Namhyung Kim62667742013-01-24 16:10:42 +0100205 ip - map->unmap_ip(map, sym->start));
Stephane Eranian98a3b322013-01-24 16:10:35 +0100206 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
207 width - ret, "");
208 } else {
209 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
210 width - ret,
211 sym->name);
212 }
213 } else {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100214 size_t len = BITS_PER_LONG / 4;
215 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
216 len, ip);
217 ret += repsep_snprintf(bf + ret, size - ret, "%-*s",
218 width - ret, "");
219 }
220
221 return ret;
222}
223
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100224static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900225 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100226{
227 return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip,
228 self->level, bf, size, width);
229}
John Kacurdd68ada2009-09-24 18:02:49 +0200230
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200231struct sort_entry sort_sym = {
232 .se_header = "Symbol",
233 .se_cmp = sort__sym_cmp,
234 .se_snprintf = hist_entry__sym_snprintf,
235 .se_width_idx = HISTC_SYMBOL,
236};
John Kacurdd68ada2009-09-24 18:02:49 +0200237
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300238/* --sort srcline */
239
240static int64_t
241sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
242{
243 return (int64_t)(right->ip - left->ip);
244}
245
246static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300247 size_t size,
248 unsigned int width __maybe_unused)
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300249{
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100250 FILE *fp = NULL;
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300251 char cmd[PATH_MAX + 2], *path = self->srcline, *nl;
252 size_t line_len;
253
254 if (path != NULL)
255 goto out_path;
256
Namhyung Kimffe10c62012-10-15 12:39:42 +0900257 if (!self->ms.map)
258 goto out_ip;
259
Namhyung Kim88481b62012-10-15 12:39:43 +0900260 if (!strncmp(self->ms.map->dso->long_name, "/tmp/perf-", 10))
261 goto out_ip;
262
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300263 snprintf(cmd, sizeof(cmd), "addr2line -e %s %016" PRIx64,
264 self->ms.map->dso->long_name, self->ip);
265 fp = popen(cmd, "r");
266 if (!fp)
267 goto out_ip;
268
269 if (getline(&path, &line_len, fp) < 0 || !line_len)
270 goto out_ip;
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300271 self->srcline = strdup(path);
272 if (self->srcline == NULL)
273 goto out_ip;
274
275 nl = strchr(self->srcline, '\n');
276 if (nl != NULL)
277 *nl = '\0';
278 path = self->srcline;
279out_path:
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100280 if (fp)
281 pclose(fp);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300282 return repsep_snprintf(bf, size, "%s", path);
283out_ip:
Thomas Jarosch8eb44dd2013-01-25 11:02:13 +0100284 if (fp)
285 pclose(fp);
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300286 return repsep_snprintf(bf, size, "%-#*llx", BITS_PER_LONG / 4, self->ip);
287}
288
289struct sort_entry sort_srcline = {
290 .se_header = "Source:Line",
291 .se_cmp = sort__srcline_cmp,
292 .se_snprintf = hist_entry__srcline_snprintf,
293 .se_width_idx = HISTC_SRCLINE,
294};
295
John Kacurdd68ada2009-09-24 18:02:49 +0200296/* --sort parent */
297
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200298static int64_t
John Kacurdd68ada2009-09-24 18:02:49 +0200299sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
300{
301 struct symbol *sym_l = left->parent;
302 struct symbol *sym_r = right->parent;
303
304 if (!sym_l || !sym_r)
305 return cmp_null(sym_l, sym_r);
306
307 return strcmp(sym_l->name, sym_r->name);
308}
309
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300310static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
311 size_t size, unsigned int width)
John Kacurdd68ada2009-09-24 18:02:49 +0200312{
Arnaldo Carvalho de Meloa4e3b952010-03-31 11:33:40 -0300313 return repsep_snprintf(bf, size, "%-*s", width,
John Kacurdd68ada2009-09-24 18:02:49 +0200314 self->parent ? self->parent->name : "[other]");
315}
316
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200317struct sort_entry sort_parent = {
318 .se_header = "Parent symbol",
319 .se_cmp = sort__parent_cmp,
320 .se_snprintf = hist_entry__parent_snprintf,
321 .se_width_idx = HISTC_PARENT,
322};
323
Arun Sharmaf60f3592010-06-04 11:27:10 -0300324/* --sort cpu */
325
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200326static int64_t
Arun Sharmaf60f3592010-06-04 11:27:10 -0300327sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
328{
329 return right->cpu - left->cpu;
330}
331
332static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
333 size_t size, unsigned int width)
334{
Namhyung Kimdccf1802012-12-27 18:11:41 +0900335 return repsep_snprintf(bf, size, "%*d", width, self->cpu);
Arun Sharmaf60f3592010-06-04 11:27:10 -0300336}
337
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200338struct sort_entry sort_cpu = {
339 .se_header = "CPU",
340 .se_cmp = sort__cpu_cmp,
341 .se_snprintf = hist_entry__cpu_snprintf,
342 .se_width_idx = HISTC_CPU,
343};
344
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900345/* sort keys for branch stacks */
346
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100347static int64_t
348sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
349{
350 return _sort__dso_cmp(left->branch_info->from.map,
351 right->branch_info->from.map);
352}
353
354static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf,
355 size_t size, unsigned int width)
356{
357 return _hist_entry__dso_snprintf(self->branch_info->from.map,
358 bf, size, width);
359}
360
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100361static int64_t
362sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
363{
364 return _sort__dso_cmp(left->branch_info->to.map,
365 right->branch_info->to.map);
366}
367
368static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf,
369 size_t size, unsigned int width)
370{
371 return _hist_entry__dso_snprintf(self->branch_info->to.map,
372 bf, size, width);
373}
374
375static int64_t
376sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
377{
378 struct addr_map_symbol *from_l = &left->branch_info->from;
379 struct addr_map_symbol *from_r = &right->branch_info->from;
380
381 if (!from_l->sym && !from_r->sym)
382 return right->level - left->level;
383
Namhyung Kim51f27d12013-02-06 14:57:15 +0900384 return _sort__sym_cmp(from_l->sym, from_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100385}
386
387static int64_t
388sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
389{
390 struct addr_map_symbol *to_l = &left->branch_info->to;
391 struct addr_map_symbol *to_r = &right->branch_info->to;
392
393 if (!to_l->sym && !to_r->sym)
394 return right->level - left->level;
395
Namhyung Kim51f27d12013-02-06 14:57:15 +0900396 return _sort__sym_cmp(to_l->sym, to_r->sym);
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100397}
398
399static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900400 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100401{
402 struct addr_map_symbol *from = &self->branch_info->from;
403 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
404 self->level, bf, size, width);
405
406}
407
408static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf,
Namhyung Kim43355522012-12-27 18:11:39 +0900409 size_t size, unsigned int width)
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100410{
411 struct addr_map_symbol *to = &self->branch_info->to;
412 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
413 self->level, bf, size, width);
414
415}
416
Namhyung Kim14d1ac72012-12-27 18:11:38 +0900417struct sort_entry sort_dso_from = {
418 .se_header = "Source Shared Object",
419 .se_cmp = sort__dso_from_cmp,
420 .se_snprintf = hist_entry__dso_from_snprintf,
421 .se_width_idx = HISTC_DSO_FROM,
422};
423
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100424struct sort_entry sort_dso_to = {
425 .se_header = "Target Shared Object",
426 .se_cmp = sort__dso_to_cmp,
427 .se_snprintf = hist_entry__dso_to_snprintf,
428 .se_width_idx = HISTC_DSO_TO,
429};
430
431struct sort_entry sort_sym_from = {
432 .se_header = "Source Symbol",
433 .se_cmp = sort__sym_from_cmp,
434 .se_snprintf = hist_entry__sym_from_snprintf,
435 .se_width_idx = HISTC_SYMBOL_FROM,
436};
437
438struct sort_entry sort_sym_to = {
439 .se_header = "Target Symbol",
440 .se_cmp = sort__sym_to_cmp,
441 .se_snprintf = hist_entry__sym_to_snprintf,
442 .se_width_idx = HISTC_SYMBOL_TO,
443};
444
445static int64_t
446sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
447{
448 const unsigned char mp = left->branch_info->flags.mispred !=
449 right->branch_info->flags.mispred;
450 const unsigned char p = left->branch_info->flags.predicted !=
451 right->branch_info->flags.predicted;
452
453 return mp || p;
454}
455
456static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf,
457 size_t size, unsigned int width){
458 static const char *out = "N/A";
459
460 if (self->branch_info->flags.predicted)
461 out = "N";
462 else if (self->branch_info->flags.mispred)
463 out = "Y";
464
465 return repsep_snprintf(bf, size, "%-*s", width, out);
466}
467
Stephane Eranian98a3b322013-01-24 16:10:35 +0100468/* --sort daddr_sym */
469static int64_t
470sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
471{
472 uint64_t l = 0, r = 0;
473
474 if (left->mem_info)
475 l = left->mem_info->daddr.addr;
476 if (right->mem_info)
477 r = right->mem_info->daddr.addr;
478
479 return (int64_t)(r - l);
480}
481
482static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf,
483 size_t size, unsigned int width)
484{
485 uint64_t addr = 0;
486 struct map *map = NULL;
487 struct symbol *sym = NULL;
488
489 if (self->mem_info) {
490 addr = self->mem_info->daddr.addr;
491 map = self->mem_info->daddr.map;
492 sym = self->mem_info->daddr.sym;
493 }
494 return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size,
495 width);
496}
497
498static int64_t
499sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
500{
501 struct map *map_l = NULL;
502 struct map *map_r = NULL;
503
504 if (left->mem_info)
505 map_l = left->mem_info->daddr.map;
506 if (right->mem_info)
507 map_r = right->mem_info->daddr.map;
508
509 return _sort__dso_cmp(map_l, map_r);
510}
511
512static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf,
513 size_t size, unsigned int width)
514{
515 struct map *map = NULL;
516
517 if (self->mem_info)
518 map = self->mem_info->daddr.map;
519
520 return _hist_entry__dso_snprintf(map, bf, size, width);
521}
522
523static int64_t
524sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
525{
526 union perf_mem_data_src data_src_l;
527 union perf_mem_data_src data_src_r;
528
529 if (left->mem_info)
530 data_src_l = left->mem_info->data_src;
531 else
532 data_src_l.mem_lock = PERF_MEM_LOCK_NA;
533
534 if (right->mem_info)
535 data_src_r = right->mem_info->data_src;
536 else
537 data_src_r.mem_lock = PERF_MEM_LOCK_NA;
538
539 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
540}
541
542static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf,
543 size_t size, unsigned int width)
544{
545 const char *out;
546 u64 mask = PERF_MEM_LOCK_NA;
547
548 if (self->mem_info)
549 mask = self->mem_info->data_src.mem_lock;
550
551 if (mask & PERF_MEM_LOCK_NA)
552 out = "N/A";
553 else if (mask & PERF_MEM_LOCK_LOCKED)
554 out = "Yes";
555 else
556 out = "No";
557
558 return repsep_snprintf(bf, size, "%-*s", width, out);
559}
560
561static int64_t
562sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
563{
564 union perf_mem_data_src data_src_l;
565 union perf_mem_data_src data_src_r;
566
567 if (left->mem_info)
568 data_src_l = left->mem_info->data_src;
569 else
570 data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
571
572 if (right->mem_info)
573 data_src_r = right->mem_info->data_src;
574 else
575 data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
576
577 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
578}
579
580static const char * const tlb_access[] = {
581 "N/A",
582 "HIT",
583 "MISS",
584 "L1",
585 "L2",
586 "Walker",
587 "Fault",
588};
589#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
590
591static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
592 size_t size, unsigned int width)
593{
594 char out[64];
595 size_t sz = sizeof(out) - 1; /* -1 for null termination */
596 size_t l = 0, i;
597 u64 m = PERF_MEM_TLB_NA;
598 u64 hit, miss;
599
600 out[0] = '\0';
601
602 if (self->mem_info)
603 m = self->mem_info->data_src.mem_dtlb;
604
605 hit = m & PERF_MEM_TLB_HIT;
606 miss = m & PERF_MEM_TLB_MISS;
607
608 /* already taken care of */
609 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
610
611 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) {
612 if (!(m & 0x1))
613 continue;
614 if (l) {
615 strcat(out, " or ");
616 l += 4;
617 }
618 strncat(out, tlb_access[i], sz - l);
619 l += strlen(tlb_access[i]);
620 }
621 if (*out == '\0')
622 strcpy(out, "N/A");
623 if (hit)
624 strncat(out, " hit", sz - l);
625 if (miss)
626 strncat(out, " miss", sz - l);
627
628 return repsep_snprintf(bf, size, "%-*s", width, out);
629}
630
631static int64_t
632sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
633{
634 union perf_mem_data_src data_src_l;
635 union perf_mem_data_src data_src_r;
636
637 if (left->mem_info)
638 data_src_l = left->mem_info->data_src;
639 else
640 data_src_l.mem_lvl = PERF_MEM_LVL_NA;
641
642 if (right->mem_info)
643 data_src_r = right->mem_info->data_src;
644 else
645 data_src_r.mem_lvl = PERF_MEM_LVL_NA;
646
647 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
648}
649
650static const char * const mem_lvl[] = {
651 "N/A",
652 "HIT",
653 "MISS",
654 "L1",
655 "LFB",
656 "L2",
657 "L3",
658 "Local RAM",
659 "Remote RAM (1 hop)",
660 "Remote RAM (2 hops)",
661 "Remote Cache (1 hop)",
662 "Remote Cache (2 hops)",
663 "I/O",
664 "Uncached",
665};
666#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
667
668static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
669 size_t size, unsigned int width)
670{
671 char out[64];
672 size_t sz = sizeof(out) - 1; /* -1 for null termination */
673 size_t i, l = 0;
674 u64 m = PERF_MEM_LVL_NA;
675 u64 hit, miss;
676
677 if (self->mem_info)
678 m = self->mem_info->data_src.mem_lvl;
679
680 out[0] = '\0';
681
682 hit = m & PERF_MEM_LVL_HIT;
683 miss = m & PERF_MEM_LVL_MISS;
684
685 /* already taken care of */
686 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
687
688 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) {
689 if (!(m & 0x1))
690 continue;
691 if (l) {
692 strcat(out, " or ");
693 l += 4;
694 }
695 strncat(out, mem_lvl[i], sz - l);
696 l += strlen(mem_lvl[i]);
697 }
698 if (*out == '\0')
699 strcpy(out, "N/A");
700 if (hit)
701 strncat(out, " hit", sz - l);
702 if (miss)
703 strncat(out, " miss", sz - l);
704
705 return repsep_snprintf(bf, size, "%-*s", width, out);
706}
707
708static int64_t
709sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
710{
711 union perf_mem_data_src data_src_l;
712 union perf_mem_data_src data_src_r;
713
714 if (left->mem_info)
715 data_src_l = left->mem_info->data_src;
716 else
717 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
718
719 if (right->mem_info)
720 data_src_r = right->mem_info->data_src;
721 else
722 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
723
724 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
725}
726
727static const char * const snoop_access[] = {
728 "N/A",
729 "None",
730 "Miss",
731 "Hit",
732 "HitM",
733};
734#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
735
736static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
737 size_t size, unsigned int width)
738{
739 char out[64];
740 size_t sz = sizeof(out) - 1; /* -1 for null termination */
741 size_t i, l = 0;
742 u64 m = PERF_MEM_SNOOP_NA;
743
744 out[0] = '\0';
745
746 if (self->mem_info)
747 m = self->mem_info->data_src.mem_snoop;
748
749 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
750 if (!(m & 0x1))
751 continue;
752 if (l) {
753 strcat(out, " or ");
754 l += 4;
755 }
756 strncat(out, snoop_access[i], sz - l);
757 l += strlen(snoop_access[i]);
758 }
759
760 if (*out == '\0')
761 strcpy(out, "N/A");
762
763 return repsep_snprintf(bf, size, "%-*s", width, out);
764}
765
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100766struct sort_entry sort_mispredict = {
767 .se_header = "Branch Mispredicted",
768 .se_cmp = sort__mispredict_cmp,
769 .se_snprintf = hist_entry__mispredict_snprintf,
770 .se_width_idx = HISTC_MISPREDICT,
771};
772
Andi Kleen05484292013-01-24 16:10:29 +0100773static u64 he_weight(struct hist_entry *he)
774{
775 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
776}
777
778static int64_t
779sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
780{
781 return he_weight(left) - he_weight(right);
782}
783
784static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
785 size_t size, unsigned int width)
786{
787 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
788}
789
790struct sort_entry sort_local_weight = {
791 .se_header = "Local Weight",
792 .se_cmp = sort__local_weight_cmp,
793 .se_snprintf = hist_entry__local_weight_snprintf,
794 .se_width_idx = HISTC_LOCAL_WEIGHT,
795};
796
797static int64_t
798sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
799{
800 return left->stat.weight - right->stat.weight;
801}
802
803static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
804 size_t size, unsigned int width)
805{
806 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
807}
808
809struct sort_entry sort_global_weight = {
810 .se_header = "Weight",
811 .se_cmp = sort__global_weight_cmp,
812 .se_snprintf = hist_entry__global_weight_snprintf,
813 .se_width_idx = HISTC_GLOBAL_WEIGHT,
814};
815
Stephane Eranian98a3b322013-01-24 16:10:35 +0100816struct sort_entry sort_mem_daddr_sym = {
817 .se_header = "Data Symbol",
818 .se_cmp = sort__daddr_cmp,
819 .se_snprintf = hist_entry__daddr_snprintf,
820 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
821};
822
823struct sort_entry sort_mem_daddr_dso = {
824 .se_header = "Data Object",
825 .se_cmp = sort__dso_daddr_cmp,
826 .se_snprintf = hist_entry__dso_daddr_snprintf,
827 .se_width_idx = HISTC_MEM_DADDR_SYMBOL,
828};
829
830struct sort_entry sort_mem_locked = {
831 .se_header = "Locked",
832 .se_cmp = sort__locked_cmp,
833 .se_snprintf = hist_entry__locked_snprintf,
834 .se_width_idx = HISTC_MEM_LOCKED,
835};
836
837struct sort_entry sort_mem_tlb = {
838 .se_header = "TLB access",
839 .se_cmp = sort__tlb_cmp,
840 .se_snprintf = hist_entry__tlb_snprintf,
841 .se_width_idx = HISTC_MEM_TLB,
842};
843
844struct sort_entry sort_mem_lvl = {
845 .se_header = "Memory access",
846 .se_cmp = sort__lvl_cmp,
847 .se_snprintf = hist_entry__lvl_snprintf,
848 .se_width_idx = HISTC_MEM_LVL,
849};
850
851struct sort_entry sort_mem_snoop = {
852 .se_header = "Snoop",
853 .se_cmp = sort__snoop_cmp,
854 .se_snprintf = hist_entry__snoop_snprintf,
855 .se_width_idx = HISTC_MEM_SNOOP,
856};
857
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200858struct sort_dimension {
859 const char *name;
860 struct sort_entry *entry;
861 int taken;
862};
863
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100864#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
865
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900866static struct sort_dimension common_sort_dimensions[] = {
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100867 DIM(SORT_PID, "pid", sort_thread),
868 DIM(SORT_COMM, "comm", sort_comm),
869 DIM(SORT_DSO, "dso", sort_dso),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100870 DIM(SORT_SYM, "symbol", sort_sym),
Roberto Agostino Vitillob5387522012-02-09 23:21:01 +0100871 DIM(SORT_PARENT, "parent", sort_parent),
872 DIM(SORT_CPU, "cpu", sort_cpu),
Arnaldo Carvalho de Melo409a8be2012-05-30 10:33:24 -0300873 DIM(SORT_SRCLINE, "srcline", sort_srcline),
Andi Kleen05484292013-01-24 16:10:29 +0100874 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
875 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
Stephane Eranian98a3b322013-01-24 16:10:35 +0100876 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
877 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
878 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
879 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
880 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
881 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
Frederic Weisbecker872a8782011-06-29 03:14:52 +0200882};
883
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900884#undef DIM
885
886#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
887
888static struct sort_dimension bstack_sort_dimensions[] = {
889 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
890 DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
891 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
892 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
893 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
894};
895
896#undef DIM
897
John Kacurdd68ada2009-09-24 18:02:49 +0200898int sort_dimension__add(const char *tok)
899{
900 unsigned int i;
901
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900902 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
903 struct sort_dimension *sd = &common_sort_dimensions[i];
John Kacurdd68ada2009-09-24 18:02:49 +0200904
John Kacurdd68ada2009-09-24 18:02:49 +0200905 if (strncasecmp(tok, sd->name, strlen(tok)))
906 continue;
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900907
John Kacurdd68ada2009-09-24 18:02:49 +0200908 if (sd->entry == &sort_parent) {
909 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
910 if (ret) {
911 char err[BUFSIZ];
912
913 regerror(ret, &parent_regex, err, sizeof(err));
Arnaldo Carvalho de Melo2aefa4f2010-04-02 12:30:57 -0300914 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
915 return -EINVAL;
John Kacurdd68ada2009-09-24 18:02:49 +0200916 }
917 sort__has_parent = 1;
Stephane Eranian98a3b322013-01-24 16:10:35 +0100918 } else if (sd->entry == &sort_sym ||
919 sd->entry == &sort_sym_from ||
920 sd->entry == &sort_sym_to ||
921 sd->entry == &sort_mem_daddr_sym) {
Namhyung Kim1af556402012-09-14 17:35:27 +0900922 sort__has_sym = 1;
John Kacurdd68ada2009-09-24 18:02:49 +0200923 }
924
Frederic Weisbeckerfd8ea212011-06-29 23:08:14 +0200925 if (sd->taken)
926 return 0;
927
928 if (sd->entry->se_collapse)
929 sort__need_collapse = 1;
930
Namhyung Kim6f38cf22012-12-27 18:11:45 +0900931 if (list_empty(&hist_entry__sort_list))
932 sort__first_dimension = i;
Frederic Weisbeckeraf0a6fa2009-10-22 23:23:22 +0200933
John Kacurdd68ada2009-09-24 18:02:49 +0200934 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
935 sd->taken = 1;
936
937 return 0;
938 }
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900939
940 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
941 struct sort_dimension *sd = &bstack_sort_dimensions[i];
942
943 if (strncasecmp(tok, sd->name, strlen(tok)))
944 continue;
945
946 if (sort__branch_mode != 1)
947 return -EINVAL;
948
949 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
950 sort__has_sym = 1;
951
952 if (sd->taken)
953 return 0;
954
955 if (sd->entry->se_collapse)
956 sort__need_collapse = 1;
957
958 if (list_empty(&hist_entry__sort_list))
959 sort__first_dimension = i + __SORT_BRANCH_STACK;
960
961 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
962 sd->taken = 1;
963
964 return 0;
965 }
966
John Kacurdd68ada2009-09-24 18:02:49 +0200967 return -ESRCH;
968}
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200969
Namhyung Kim55309982013-02-06 14:57:16 +0900970int setup_sorting(void)
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200971{
972 char *tmp, *tok, *str = strdup(sort_order);
Namhyung Kim55309982013-02-06 14:57:16 +0900973 int ret = 0;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200974
Namhyung Kim5936f542013-02-06 14:57:17 +0900975 if (str == NULL) {
976 error("Not enough memory to setup sort keys");
977 return -ENOMEM;
978 }
979
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200980 for (tok = strtok_r(str, ", ", &tmp);
981 tok; tok = strtok_r(NULL, ", ", &tmp)) {
Namhyung Kim55309982013-02-06 14:57:16 +0900982 ret = sort_dimension__add(tok);
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900983 if (ret == -EINVAL) {
984 error("Invalid --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +0900985 break;
Namhyung Kimfc5871e2012-12-27 18:11:46 +0900986 } else if (ret == -ESRCH) {
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200987 error("Unknown --sort key: `%s'", tok);
Namhyung Kim55309982013-02-06 14:57:16 +0900988 break;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200989 }
990 }
991
992 free(str);
Namhyung Kim55309982013-02-06 14:57:16 +0900993 return ret;
Arnaldo Carvalho de Meloc8829c72009-12-14 20:09:29 -0200994}
Arnaldo Carvalho de Meloc351c282009-12-16 13:49:27 -0200995
996void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
997 const char *list_name, FILE *fp)
998{
999 if (list && strlist__nr_entries(list) == 1) {
1000 if (fp != NULL)
1001 fprintf(fp, "# %s: %s\n", list_name,
1002 strlist__entry(list, 0)->s);
1003 self->elide = true;
1004 }
1005}