4 const char default_parent_pattern[] = "^sys_|^do_page_fault";
5 const char *parent_pattern = default_parent_pattern;
6 const char default_sort_order[] = "comm,dso,symbol";
7 const char *sort_order = default_sort_order;
8 int sort__need_collapse = 0;
9 int sort__has_parent = 0;
11 enum sort_type sort__first_dimension;
13 unsigned int dsos__col_width;
14 unsigned int comms__col_width;
15 unsigned int threads__col_width;
16 unsigned int cpus__col_width;
17 static unsigned int parent_symbol__col_width;
20 LIST_HEAD(hist_entry__sort_list);
22 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
23 size_t size, unsigned int width);
24 static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
25 size_t size, unsigned int width);
26 static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
27 size_t size, unsigned int width);
28 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
29 size_t size, unsigned int width);
30 static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
31 size_t size, unsigned int width);
32 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
33 size_t size, unsigned int width);
35 struct sort_entry sort_thread = {
36 .se_header = "Command: Pid",
37 .se_cmp = sort__thread_cmp,
38 .se_snprintf = hist_entry__thread_snprintf,
39 .se_width = &threads__col_width,
42 struct sort_entry sort_comm = {
43 .se_header = "Command",
44 .se_cmp = sort__comm_cmp,
45 .se_collapse = sort__comm_collapse,
46 .se_snprintf = hist_entry__comm_snprintf,
47 .se_width = &comms__col_width,
50 struct sort_entry sort_dso = {
51 .se_header = "Shared Object",
52 .se_cmp = sort__dso_cmp,
53 .se_snprintf = hist_entry__dso_snprintf,
54 .se_width = &dsos__col_width,
57 struct sort_entry sort_sym = {
58 .se_header = "Symbol",
59 .se_cmp = sort__sym_cmp,
60 .se_snprintf = hist_entry__sym_snprintf,
63 struct sort_entry sort_parent = {
64 .se_header = "Parent symbol",
65 .se_cmp = sort__parent_cmp,
66 .se_snprintf = hist_entry__parent_snprintf,
67 .se_width = &parent_symbol__col_width,
70 struct sort_entry sort_cpu = {
72 .se_cmp = sort__cpu_cmp,
73 .se_snprintf = hist_entry__cpu_snprintf,
74 .se_width = &cpus__col_width,
77 struct sort_dimension {
79 struct sort_entry *entry;
83 static struct sort_dimension sort_dimensions[] = {
84 { .name = "pid", .entry = &sort_thread, },
85 { .name = "comm", .entry = &sort_comm, },
86 { .name = "dso", .entry = &sort_dso, },
87 { .name = "symbol", .entry = &sort_sym, },
88 { .name = "parent", .entry = &sort_parent, },
89 { .name = "cpu", .entry = &sort_cpu, },
92 int64_t cmp_null(void *l, void *r)
105 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
107 return right->thread->pid - left->thread->pid;
110 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
116 n = vsnprintf(bf, size, fmt, ap);
117 if (field_sep && n > 0) {
121 sep = strchr(sep, *field_sep);
131 static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf,
132 size_t size, unsigned int width)
134 return repsep_snprintf(bf, size, "%*s:%5d", width,
135 self->thread->comm ?: "", self->thread->pid);
138 static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf,
139 size_t size, unsigned int width)
141 return repsep_snprintf(bf, size, "%*s", width, self->thread->comm);
147 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
149 struct dso *dso_l = left->ms.map ? left->ms.map->dso : NULL;
150 struct dso *dso_r = right->ms.map ? right->ms.map->dso : NULL;
151 const char *dso_name_l, *dso_name_r;
153 if (!dso_l || !dso_r)
154 return cmp_null(dso_l, dso_r);
157 dso_name_l = dso_l->long_name;
158 dso_name_r = dso_r->long_name;
160 dso_name_l = dso_l->short_name;
161 dso_name_r = dso_r->short_name;
164 return strcmp(dso_name_l, dso_name_r);
167 static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf,
168 size_t size, unsigned int width)
170 if (self->ms.map && self->ms.map->dso) {
171 const char *dso_name = !verbose ? self->ms.map->dso->short_name :
172 self->ms.map->dso->long_name;
173 return repsep_snprintf(bf, size, "%-*s", width, dso_name);
176 return repsep_snprintf(bf, size, "%*Lx", width, self->ip);
182 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
186 if (left->ms.sym == right->ms.sym)
189 ip_l = left->ms.sym ? left->ms.sym->start : left->ip;
190 ip_r = right->ms.sym ? right->ms.sym->start : right->ip;
192 return (int64_t)(ip_r - ip_l);
195 static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
196 size_t size, unsigned int width __used)
201 char o = self->ms.map ? dso__symtab_origin(self->ms.map->dso) : '!';
202 ret += repsep_snprintf(bf, size, "%#018llx %c ", self->ip, o);
205 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", self->level);
207 ret += repsep_snprintf(bf + ret, size - ret, "%s",
210 ret += repsep_snprintf(bf + ret, size - ret, "%#016llx", self->ip);
218 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
220 return right->thread->pid - left->thread->pid;
224 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
226 char *comm_l = left->thread->comm;
227 char *comm_r = right->thread->comm;
229 if (!comm_l || !comm_r)
230 return cmp_null(comm_l, comm_r);
232 return strcmp(comm_l, comm_r);
238 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
240 struct symbol *sym_l = left->parent;
241 struct symbol *sym_r = right->parent;
243 if (!sym_l || !sym_r)
244 return cmp_null(sym_l, sym_r);
246 return strcmp(sym_l->name, sym_r->name);
249 static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
250 size_t size, unsigned int width)
252 return repsep_snprintf(bf, size, "%-*s", width,
253 self->parent ? self->parent->name : "[other]");
259 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
261 return right->cpu - left->cpu;
264 static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
265 size_t size, unsigned int width)
267 return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
270 int sort_dimension__add(const char *tok)
274 for (i = 0; i < ARRAY_SIZE(sort_dimensions); i++) {
275 struct sort_dimension *sd = &sort_dimensions[i];
280 if (strncasecmp(tok, sd->name, strlen(tok)))
283 if (sd->entry->se_collapse)
284 sort__need_collapse = 1;
286 if (sd->entry == &sort_parent) {
287 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
291 regerror(ret, &parent_regex, err, sizeof(err));
292 pr_err("Invalid regex: %s\n%s", parent_pattern, err);
295 sort__has_parent = 1;
298 if (list_empty(&hist_entry__sort_list)) {
299 if (!strcmp(sd->name, "pid"))
300 sort__first_dimension = SORT_PID;
301 else if (!strcmp(sd->name, "comm"))
302 sort__first_dimension = SORT_COMM;
303 else if (!strcmp(sd->name, "dso"))
304 sort__first_dimension = SORT_DSO;
305 else if (!strcmp(sd->name, "symbol"))
306 sort__first_dimension = SORT_SYM;
307 else if (!strcmp(sd->name, "parent"))
308 sort__first_dimension = SORT_PARENT;
309 else if (!strcmp(sd->name, "cpu"))
310 sort__first_dimension = SORT_CPU;
313 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
322 void setup_sorting(const char * const usagestr[], const struct option *opts)
324 char *tmp, *tok, *str = strdup(sort_order);
326 for (tok = strtok_r(str, ", ", &tmp);
327 tok; tok = strtok_r(NULL, ", ", &tmp)) {
328 if (sort_dimension__add(tok) < 0) {
329 error("Unknown --sort key: `%s'", tok);
330 usage_with_options(usagestr, opts);
337 void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
338 const char *list_name, FILE *fp)
340 if (list && strlist__nr_entries(list) == 1) {
342 fprintf(fp, "# %s: %s\n", list_name,
343 strlist__entry(list, 0)->s);