Root/tools/perf/util/sort.c

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

Archive Download this file



interactive