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
);