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