3 #include "../../util/util.h"
4 #include "../../util/hist.h"
5 #include "../../util/sort.h"
6 #include "../../util/evsel.h"
9 static size_t callchain__fprintf_left_margin(FILE *fp
, int left_margin
)
12 int ret
= fprintf(fp
, " ");
14 for (i
= 0; i
< left_margin
; i
++)
15 ret
+= fprintf(fp
, " ");
20 static size_t ipchain__fprintf_graph_line(FILE *fp
, int depth
, int depth_mask
,
24 size_t ret
= callchain__fprintf_left_margin(fp
, left_margin
);
26 for (i
= 0; i
< depth
; i
++)
27 if (depth_mask
& (1 << i
))
28 ret
+= fprintf(fp
, "| ");
30 ret
+= fprintf(fp
, " ");
32 ret
+= fprintf(fp
, "\n");
37 static size_t ipchain__fprintf_graph(FILE *fp
, struct callchain_list
*chain
,
38 int depth
, int depth_mask
, int period
,
39 u64 total_samples
, u64 hits
,
45 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
46 for (i
= 0; i
< depth
; i
++) {
47 if (depth_mask
& (1 << i
))
48 ret
+= fprintf(fp
, "|");
50 ret
+= fprintf(fp
, " ");
51 if (!period
&& i
== depth
- 1) {
54 percent
= hits
* 100.0 / total_samples
;
55 ret
+= percent_color_fprintf(fp
, "--%2.2f%%-- ", percent
);
57 ret
+= fprintf(fp
, "%s", " ");
60 ret
+= fprintf(fp
, "%s\n", chain
->ms
.sym
->name
);
62 ret
+= fprintf(fp
, "0x%0" PRIx64
"\n", chain
->ip
);
67 static struct symbol
*rem_sq_bracket
;
68 static struct callchain_list rem_hits
;
70 static void init_rem_hits(void)
72 rem_sq_bracket
= malloc(sizeof(*rem_sq_bracket
) + 6);
73 if (!rem_sq_bracket
) {
74 fprintf(stderr
, "Not enough memory to display remaining hits\n");
78 strcpy(rem_sq_bracket
->name
, "[...]");
79 rem_hits
.ms
.sym
= rem_sq_bracket
;
82 static size_t __callchain__fprintf_graph(FILE *fp
, struct rb_root
*root
,
83 u64 total_samples
, int depth
,
84 int depth_mask
, int left_margin
)
86 struct rb_node
*node
, *next
;
87 struct callchain_node
*child
;
88 struct callchain_list
*chain
;
89 int new_depth_mask
= depth_mask
;
93 uint entries_printed
= 0;
95 remaining
= total_samples
;
97 node
= rb_first(root
);
102 child
= rb_entry(node
, struct callchain_node
, rb_node
);
103 cumul
= callchain_cumul_hits(child
);
107 * The depth mask manages the output of pipes that show
108 * the depth. We don't want to keep the pipes of the current
109 * level for the last child of this depth.
110 * Except if we have remaining filtered hits. They will
111 * supersede the last child
113 next
= rb_next(node
);
114 if (!next
&& (callchain_param
.mode
!= CHAIN_GRAPH_REL
|| !remaining
))
115 new_depth_mask
&= ~(1 << (depth
- 1));
118 * But we keep the older depth mask for the line separator
119 * to keep the level link until we reach the last child
121 ret
+= ipchain__fprintf_graph_line(fp
, depth
, depth_mask
,
124 list_for_each_entry(chain
, &child
->val
, list
) {
125 ret
+= ipchain__fprintf_graph(fp
, chain
, depth
,
132 if (callchain_param
.mode
== CHAIN_GRAPH_REL
)
133 new_total
= child
->children_hit
;
135 new_total
= total_samples
;
137 ret
+= __callchain__fprintf_graph(fp
, &child
->rb_root
, new_total
,
139 new_depth_mask
| (1 << depth
),
142 if (++entries_printed
== callchain_param
.print_limit
)
146 if (callchain_param
.mode
== CHAIN_GRAPH_REL
&&
147 remaining
&& remaining
!= total_samples
) {
152 new_depth_mask
&= ~(1 << (depth
- 1));
153 ret
+= ipchain__fprintf_graph(fp
, &rem_hits
, depth
,
154 new_depth_mask
, 0, total_samples
,
155 remaining
, left_margin
);
161 static size_t callchain__fprintf_graph(FILE *fp
, struct rb_root
*root
,
162 u64 total_samples
, int left_margin
)
164 struct callchain_node
*cnode
;
165 struct callchain_list
*chain
;
166 u32 entries_printed
= 0;
167 bool printed
= false;
168 struct rb_node
*node
;
173 * If have one single callchain root, don't bother printing
174 * its percentage (100 % in fractal mode and the same percentage
175 * than the hist in graph mode). This also avoid one level of column.
177 node
= rb_first(root
);
178 if (node
&& !rb_next(node
)) {
179 cnode
= rb_entry(node
, struct callchain_node
, rb_node
);
180 list_for_each_entry(chain
, &cnode
->val
, list
) {
182 * If we sort by symbol, the first entry is the same than
183 * the symbol. No need to print it otherwise it appears as
186 if (!i
++ && field_order
== NULL
&&
187 sort_order
&& !prefixcmp(sort_order
, "sym"))
190 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
191 ret
+= fprintf(fp
, "|\n");
192 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
193 ret
+= fprintf(fp
, "---");
197 ret
+= callchain__fprintf_left_margin(fp
, left_margin
);
200 ret
+= fprintf(fp
, " %s\n", chain
->ms
.sym
->name
);
202 ret
+= fprintf(fp
, " %p\n", (void *)(long)chain
->ip
);
204 if (++entries_printed
== callchain_param
.print_limit
)
207 root
= &cnode
->rb_root
;
210 ret
+= __callchain__fprintf_graph(fp
, root
, total_samples
,
212 ret
+= fprintf(fp
, "\n");
217 static size_t __callchain__fprintf_flat(FILE *fp
, struct callchain_node
*node
,
220 struct callchain_list
*chain
;
226 ret
+= __callchain__fprintf_flat(fp
, node
->parent
, total_samples
);
229 list_for_each_entry(chain
, &node
->val
, list
) {
230 if (chain
->ip
>= PERF_CONTEXT_MAX
)
233 ret
+= fprintf(fp
, " %s\n", chain
->ms
.sym
->name
);
235 ret
+= fprintf(fp
, " %p\n",
236 (void *)(long)chain
->ip
);
242 static size_t callchain__fprintf_flat(FILE *fp
, struct rb_root
*tree
,
246 u32 entries_printed
= 0;
247 struct callchain_node
*chain
;
248 struct rb_node
*rb_node
= rb_first(tree
);
253 chain
= rb_entry(rb_node
, struct callchain_node
, rb_node
);
254 percent
= chain
->hit
* 100.0 / total_samples
;
256 ret
= percent_color_fprintf(fp
, " %6.2f%%\n", percent
);
257 ret
+= __callchain__fprintf_flat(fp
, chain
, total_samples
);
258 ret
+= fprintf(fp
, "\n");
259 if (++entries_printed
== callchain_param
.print_limit
)
262 rb_node
= rb_next(rb_node
);
268 static size_t hist_entry_callchain__fprintf(struct hist_entry
*he
,
269 u64 total_samples
, int left_margin
,
272 switch (callchain_param
.mode
) {
273 case CHAIN_GRAPH_REL
:
274 return callchain__fprintf_graph(fp
, &he
->sorted_chain
,
275 symbol_conf
.cumulate_callchain
?
276 he
->stat_acc
->period
: he
->stat
.period
,
279 case CHAIN_GRAPH_ABS
:
280 return callchain__fprintf_graph(fp
, &he
->sorted_chain
, total_samples
,
284 return callchain__fprintf_flat(fp
, &he
->sorted_chain
, total_samples
);
289 pr_err("Bad callchain mode\n");
295 static size_t hist_entry__callchain_fprintf(struct hist_entry
*he
,
300 u64 total_period
= hists
->stats
.total_period
;
302 if (field_order
== NULL
&& (sort_order
== NULL
||
303 !prefixcmp(sort_order
, "comm"))) {
304 struct perf_hpp_fmt
*fmt
;
306 perf_hpp__for_each_format(fmt
) {
307 if (!perf_hpp__is_sort_entry(fmt
))
310 /* must be 'comm' sort entry */
311 left_margin
= fmt
->width(fmt
, NULL
, hists_to_evsel(hists
));
312 left_margin
-= thread__comm_len(he
->thread
);
316 return hist_entry_callchain__fprintf(he
, total_period
, left_margin
, fp
);
319 static int hist_entry__snprintf(struct hist_entry
*he
, struct perf_hpp
*hpp
)
321 const char *sep
= symbol_conf
.field_sep
;
322 struct perf_hpp_fmt
*fmt
;
323 char *start
= hpp
->buf
;
327 if (symbol_conf
.exclude_other
&& !he
->parent
)
330 perf_hpp__for_each_format(fmt
) {
331 if (perf_hpp__should_skip(fmt
))
335 * If there's no field_sep, we still need
336 * to display initial ' '.
338 if (!sep
|| !first
) {
339 ret
= scnprintf(hpp
->buf
, hpp
->size
, "%s", sep
?: " ");
340 advance_hpp(hpp
, ret
);
344 if (perf_hpp__use_color() && fmt
->color
)
345 ret
= fmt
->color(fmt
, hpp
, he
);
347 ret
= fmt
->entry(fmt
, hpp
, he
);
349 advance_hpp(hpp
, ret
);
352 return hpp
->buf
- start
;
355 static int hist_entry__fprintf(struct hist_entry
*he
, size_t size
,
357 char *bf
, size_t bfsz
, FILE *fp
)
360 struct perf_hpp hpp
= {
365 if (size
== 0 || size
> bfsz
)
366 size
= hpp
.size
= bfsz
;
368 hist_entry__snprintf(he
, &hpp
);
370 ret
= fprintf(fp
, "%s\n", bf
);
372 if (symbol_conf
.use_callchain
)
373 ret
+= hist_entry__callchain_fprintf(he
, hists
, fp
);
378 size_t hists__fprintf(struct hists
*hists
, bool show_header
, int max_rows
,
379 int max_cols
, float min_pcnt
, FILE *fp
)
381 struct perf_hpp_fmt
*fmt
;
385 const char *sep
= symbol_conf
.field_sep
;
388 struct perf_hpp dummy_hpp
= {
399 perf_hpp__for_each_format(fmt
)
400 perf_hpp__reset_width(fmt
, hists
);
407 perf_hpp__for_each_format(fmt
) {
408 if (perf_hpp__should_skip(fmt
))
412 fprintf(fp
, "%s", sep
?: " ");
416 fmt
->header(fmt
, &dummy_hpp
, hists_to_evsel(hists
));
417 fprintf(fp
, "%s", bf
);
421 if (max_rows
&& ++nr_rows
>= max_rows
)
431 perf_hpp__for_each_format(fmt
) {
434 if (perf_hpp__should_skip(fmt
))
438 fprintf(fp
, "%s", sep
?: " ");
442 width
= fmt
->width(fmt
, &dummy_hpp
, hists_to_evsel(hists
));
443 for (i
= 0; i
< width
; i
++)
448 if (max_rows
&& ++nr_rows
>= max_rows
)
452 if (max_rows
&& ++nr_rows
>= max_rows
)
456 linesz
= hists__sort_list_width(hists
) + 3 + 1;
457 linesz
+= perf_hpp__color_overhead();
458 line
= malloc(linesz
);
464 for (nd
= rb_first(&hists
->entries
); nd
; nd
= rb_next(nd
)) {
465 struct hist_entry
*h
= rb_entry(nd
, struct hist_entry
, rb_node
);
471 percent
= hist_entry__get_percent_limit(h
);
472 if (percent
< min_pcnt
)
475 ret
+= hist_entry__fprintf(h
, max_cols
, hists
, line
, linesz
, fp
);
477 if (max_rows
&& ++nr_rows
>= max_rows
)
480 if (h
->ms
.map
== NULL
&& verbose
> 1) {
481 __map_groups__fprintf_maps(h
->thread
->mg
,
483 fprintf(fp
, "%.10s end\n", graph_dotted_line
);
489 zfree(&rem_sq_bracket
);
494 size_t events_stats__fprintf(struct events_stats
*stats
, FILE *fp
)
499 for (i
= 0; i
< PERF_RECORD_HEADER_MAX
; ++i
) {
502 if (stats
->nr_events
[i
] == 0)
505 name
= perf_event__name(i
);
506 if (!strcmp(name
, "UNKNOWN"))
509 ret
+= fprintf(fp
, "%16s events: %10d\n", name
,
510 stats
->nr_events
[i
]);
This page took 0.043462 seconds and 5 git commands to generate.