perf tools: Fix missing top level callchain
[safe/jmp/linux-2.6] / tools / perf / util / sort.c
1 #include "sort.h"
2
3 regex_t         parent_regex;
4 char            default_parent_pattern[] = "^sys_|^do_page_fault";
5 char            *parent_pattern = default_parent_pattern;
6 char            default_sort_order[] = "comm,dso,symbol";
7 char            *sort_order = default_sort_order;
8 int             sort__need_collapse = 0;
9 int             sort__has_parent = 0;
10 int             sort_by_sym_first;
11
12 unsigned int dsos__col_width;
13 unsigned int comms__col_width;
14 unsigned int threads__col_width;
15 static unsigned int parent_symbol__col_width;
16 char * field_sep;
17
18 LIST_HEAD(hist_entry__sort_list);
19
20 struct sort_entry sort_thread = {
21         .header = "Command:  Pid",
22         .cmp    = sort__thread_cmp,
23         .print  = sort__thread_print,
24         .width  = &threads__col_width,
25 };
26
27 struct sort_entry sort_comm = {
28         .header         = "Command",
29         .cmp            = sort__comm_cmp,
30         .collapse       = sort__comm_collapse,
31         .print          = sort__comm_print,
32         .width          = &comms__col_width,
33 };
34
35 struct sort_entry sort_dso = {
36         .header = "Shared Object",
37         .cmp    = sort__dso_cmp,
38         .print  = sort__dso_print,
39         .width  = &dsos__col_width,
40 };
41
42 struct sort_entry sort_sym = {
43         .header = "Symbol",
44         .cmp    = sort__sym_cmp,
45         .print  = sort__sym_print,
46 };
47
48 struct sort_entry sort_parent = {
49         .header = "Parent symbol",
50         .cmp    = sort__parent_cmp,
51         .print  = sort__parent_print,
52         .width  = &parent_symbol__col_width,
53 };
54
55 struct sort_dimension {
56         const char              *name;
57         struct sort_entry       *entry;
58         int                     taken;
59 };
60
61 static struct sort_dimension sort_dimensions[] = {
62         { .name = "pid",        .entry = &sort_thread,  },
63         { .name = "comm",       .entry = &sort_comm,    },
64         { .name = "dso",        .entry = &sort_dso,     },
65         { .name = "symbol",     .entry = &sort_sym,     },
66         { .name = "parent",     .entry = &sort_parent,  },
67 };
68
69 int64_t cmp_null(void *l, void *r)
70 {
71         if (!l && !r)
72                 return 0;
73         else if (!l)
74                 return -1;
75         else
76                 return 1;
77 }
78
79 /* --sort pid */
80
81 int64_t
82 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
83 {
84         return right->thread->pid - left->thread->pid;
85 }
86
87 int repsep_fprintf(FILE *fp, const char *fmt, ...)
88 {
89         int n;
90         va_list ap;
91
92         va_start(ap, fmt);
93         if (!field_sep)
94                 n = vfprintf(fp, fmt, ap);
95         else {
96                 char *bf = NULL;
97                 n = vasprintf(&bf, fmt, ap);
98                 if (n > 0) {
99                         char *sep = bf;
100
101                         while (1) {
102                                 sep = strchr(sep, *field_sep);
103                                 if (sep == NULL)
104                                         break;
105                                 *sep = '.';
106                         }
107                 }
108                 fputs(bf, fp);
109                 free(bf);
110         }
111         va_end(ap);
112         return n;
113 }
114
115 size_t
116 sort__thread_print(FILE *fp, struct hist_entry *self, unsigned int width)
117 {
118         return repsep_fprintf(fp, "%*s:%5d", width - 6,
119                               self->thread->comm ?: "", self->thread->pid);
120 }
121
122 size_t
123 sort__comm_print(FILE *fp, struct hist_entry *self, unsigned int width)
124 {
125         return repsep_fprintf(fp, "%*s", width, self->thread->comm);
126 }
127
128 /* --sort dso */
129
130 int64_t
131 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
132 {
133         struct dso *dso_l = left->map ? left->map->dso : NULL;
134         struct dso *dso_r = right->map ? right->map->dso : NULL;
135         const char *dso_name_l, *dso_name_r;
136
137         if (!dso_l || !dso_r)
138                 return cmp_null(dso_l, dso_r);
139
140         if (verbose) {
141                 dso_name_l = dso_l->long_name;
142                 dso_name_r = dso_r->long_name;
143         } else {
144                 dso_name_l = dso_l->short_name;
145                 dso_name_r = dso_r->short_name;
146         }
147
148         return strcmp(dso_name_l, dso_name_r);
149 }
150
151 size_t
152 sort__dso_print(FILE *fp, struct hist_entry *self, unsigned int width)
153 {
154         if (self->map && self->map->dso) {
155                 const char *dso_name = !verbose ? self->map->dso->short_name :
156                                                   self->map->dso->long_name;
157                 return repsep_fprintf(fp, "%-*s", width, dso_name);
158         }
159
160         return repsep_fprintf(fp, "%*llx", width, (u64)self->ip);
161 }
162
163 /* --sort symbol */
164
165 int64_t
166 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
167 {
168         u64 ip_l, ip_r;
169
170         if (left->sym == right->sym)
171                 return 0;
172
173         ip_l = left->sym ? left->sym->start : left->ip;
174         ip_r = right->sym ? right->sym->start : right->ip;
175
176         return (int64_t)(ip_r - ip_l);
177 }
178
179
180 size_t
181 sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
182 {
183         size_t ret = 0;
184
185         if (verbose) {
186                 char o = self->map ? dso__symtab_origin(self->map->dso) : '!';
187                 ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip, o);
188         }
189
190         ret += repsep_fprintf(fp, "[%c] ", self->level);
191         if (self->sym)
192                 ret += repsep_fprintf(fp, "%s", self->sym->name);
193         else
194                 ret += repsep_fprintf(fp, "%#016llx", (u64)self->ip);
195
196         return ret;
197 }
198
199 /* --sort comm */
200
201 int64_t
202 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
203 {
204         return right->thread->pid - left->thread->pid;
205 }
206
207 int64_t
208 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
209 {
210         char *comm_l = left->thread->comm;
211         char *comm_r = right->thread->comm;
212
213         if (!comm_l || !comm_r)
214                 return cmp_null(comm_l, comm_r);
215
216         return strcmp(comm_l, comm_r);
217 }
218
219 /* --sort parent */
220
221 int64_t
222 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
223 {
224         struct symbol *sym_l = left->parent;
225         struct symbol *sym_r = right->parent;
226
227         if (!sym_l || !sym_r)
228                 return cmp_null(sym_l, sym_r);
229
230         return strcmp(sym_l->name, sym_r->name);
231 }
232
233 size_t
234 sort__parent_print(FILE *fp, struct hist_entry *self, unsigned int width)
235 {
236         return repsep_fprintf(fp, "%-*s", width,
237                               self->parent ? self->parent->name : "[other]");
238 }
239
240 int sort_dimension__add(const char *tok)
241 {
242         unsigned int i;
243
244         for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
245                 struct sort_dimension *sd = &sort_dimensions[i];
246
247                 if (sd->taken)
248                         continue;
249
250                 if (strncasecmp(tok, sd->name, strlen(tok)))
251                         continue;
252
253                 if (sd->entry->collapse)
254                         sort__need_collapse = 1;
255
256                 if (sd->entry == &sort_parent) {
257                         int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
258                         if (ret) {
259                                 char err[BUFSIZ];
260
261                                 regerror(ret, &parent_regex, err, sizeof(err));
262                                 fprintf(stderr, "Invalid regex: %s\n%s",
263                                         parent_pattern, err);
264                                 exit(-1);
265                         }
266                         sort__has_parent = 1;
267                 }
268
269                 if (list_empty(&hist_entry__sort_list) &&
270                     !strcmp(sd->name, "symbol"))
271                         sort_by_sym_first = true;
272
273                 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
274                 sd->taken = 1;
275
276                 return 0;
277         }
278
279         return -ESRCH;
280 }