1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <stdio.h>
3*4882a593Smuzhiyun #include <stdlib.h>
4*4882a593Smuzhiyun #include <linux/string.h>
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include "../../util/callchain.h"
7*4882a593Smuzhiyun #include "../../util/debug.h"
8*4882a593Smuzhiyun #include "../../util/event.h"
9*4882a593Smuzhiyun #include "../../util/hist.h"
10*4882a593Smuzhiyun #include "../../util/map.h"
11*4882a593Smuzhiyun #include "../../util/maps.h"
12*4882a593Smuzhiyun #include "../../util/symbol.h"
13*4882a593Smuzhiyun #include "../../util/sort.h"
14*4882a593Smuzhiyun #include "../../util/evsel.h"
15*4882a593Smuzhiyun #include "../../util/srcline.h"
16*4882a593Smuzhiyun #include "../../util/string2.h"
17*4882a593Smuzhiyun #include "../../util/thread.h"
18*4882a593Smuzhiyun #include "../../util/block-info.h"
19*4882a593Smuzhiyun #include <linux/ctype.h>
20*4882a593Smuzhiyun #include <linux/zalloc.h>
21*4882a593Smuzhiyun
callchain__fprintf_left_margin(FILE * fp,int left_margin)22*4882a593Smuzhiyun static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin)
23*4882a593Smuzhiyun {
24*4882a593Smuzhiyun int i;
25*4882a593Smuzhiyun int ret = fprintf(fp, " ");
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun for (i = 0; i < left_margin; i++)
28*4882a593Smuzhiyun ret += fprintf(fp, " ");
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun return ret;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
ipchain__fprintf_graph_line(FILE * fp,int depth,int depth_mask,int left_margin)33*4882a593Smuzhiyun static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
34*4882a593Smuzhiyun int left_margin)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun int i;
37*4882a593Smuzhiyun size_t ret = callchain__fprintf_left_margin(fp, left_margin);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun for (i = 0; i < depth; i++)
40*4882a593Smuzhiyun if (depth_mask & (1 << i))
41*4882a593Smuzhiyun ret += fprintf(fp, "| ");
42*4882a593Smuzhiyun else
43*4882a593Smuzhiyun ret += fprintf(fp, " ");
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun ret += fprintf(fp, "\n");
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun return ret;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
ipchain__fprintf_graph(FILE * fp,struct callchain_node * node,struct callchain_list * chain,int depth,int depth_mask,int period,u64 total_samples,int left_margin)50*4882a593Smuzhiyun static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
51*4882a593Smuzhiyun struct callchain_list *chain,
52*4882a593Smuzhiyun int depth, int depth_mask, int period,
53*4882a593Smuzhiyun u64 total_samples, int left_margin)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun int i;
56*4882a593Smuzhiyun size_t ret = 0;
57*4882a593Smuzhiyun char bf[1024], *alloc_str = NULL;
58*4882a593Smuzhiyun char buf[64];
59*4882a593Smuzhiyun const char *str;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun ret += callchain__fprintf_left_margin(fp, left_margin);
62*4882a593Smuzhiyun for (i = 0; i < depth; i++) {
63*4882a593Smuzhiyun if (depth_mask & (1 << i))
64*4882a593Smuzhiyun ret += fprintf(fp, "|");
65*4882a593Smuzhiyun else
66*4882a593Smuzhiyun ret += fprintf(fp, " ");
67*4882a593Smuzhiyun if (!period && i == depth - 1) {
68*4882a593Smuzhiyun ret += fprintf(fp, "--");
69*4882a593Smuzhiyun ret += callchain_node__fprintf_value(node, fp, total_samples);
70*4882a593Smuzhiyun ret += fprintf(fp, "--");
71*4882a593Smuzhiyun } else
72*4882a593Smuzhiyun ret += fprintf(fp, "%s", " ");
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun str = callchain_list__sym_name(chain, bf, sizeof(bf), false);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun if (symbol_conf.show_branchflag_count) {
78*4882a593Smuzhiyun callchain_list_counts__printf_value(chain, NULL,
79*4882a593Smuzhiyun buf, sizeof(buf));
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun if (asprintf(&alloc_str, "%s%s", str, buf) < 0)
82*4882a593Smuzhiyun str = "Not enough memory!";
83*4882a593Smuzhiyun else
84*4882a593Smuzhiyun str = alloc_str;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun fputs(str, fp);
88*4882a593Smuzhiyun fputc('\n', fp);
89*4882a593Smuzhiyun free(alloc_str);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun return ret;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun static struct symbol *rem_sq_bracket;
95*4882a593Smuzhiyun static struct callchain_list rem_hits;
96*4882a593Smuzhiyun
init_rem_hits(void)97*4882a593Smuzhiyun static void init_rem_hits(void)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6);
100*4882a593Smuzhiyun if (!rem_sq_bracket) {
101*4882a593Smuzhiyun fprintf(stderr, "Not enough memory to display remaining hits\n");
102*4882a593Smuzhiyun return;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun strcpy(rem_sq_bracket->name, "[...]");
106*4882a593Smuzhiyun rem_hits.ms.sym = rem_sq_bracket;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
__callchain__fprintf_graph(FILE * fp,struct rb_root * root,u64 total_samples,int depth,int depth_mask,int left_margin)109*4882a593Smuzhiyun static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
110*4882a593Smuzhiyun u64 total_samples, int depth,
111*4882a593Smuzhiyun int depth_mask, int left_margin)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun struct rb_node *node, *next;
114*4882a593Smuzhiyun struct callchain_node *child = NULL;
115*4882a593Smuzhiyun struct callchain_list *chain;
116*4882a593Smuzhiyun int new_depth_mask = depth_mask;
117*4882a593Smuzhiyun u64 remaining;
118*4882a593Smuzhiyun size_t ret = 0;
119*4882a593Smuzhiyun int i;
120*4882a593Smuzhiyun uint entries_printed = 0;
121*4882a593Smuzhiyun int cumul_count = 0;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun remaining = total_samples;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun node = rb_first(root);
126*4882a593Smuzhiyun while (node) {
127*4882a593Smuzhiyun u64 new_total;
128*4882a593Smuzhiyun u64 cumul;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun child = rb_entry(node, struct callchain_node, rb_node);
131*4882a593Smuzhiyun cumul = callchain_cumul_hits(child);
132*4882a593Smuzhiyun remaining -= cumul;
133*4882a593Smuzhiyun cumul_count += callchain_cumul_counts(child);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun /*
136*4882a593Smuzhiyun * The depth mask manages the output of pipes that show
137*4882a593Smuzhiyun * the depth. We don't want to keep the pipes of the current
138*4882a593Smuzhiyun * level for the last child of this depth.
139*4882a593Smuzhiyun * Except if we have remaining filtered hits. They will
140*4882a593Smuzhiyun * supersede the last child
141*4882a593Smuzhiyun */
142*4882a593Smuzhiyun next = rb_next(node);
143*4882a593Smuzhiyun if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining))
144*4882a593Smuzhiyun new_depth_mask &= ~(1 << (depth - 1));
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun * But we keep the older depth mask for the line separator
148*4882a593Smuzhiyun * to keep the level link until we reach the last child
149*4882a593Smuzhiyun */
150*4882a593Smuzhiyun ret += ipchain__fprintf_graph_line(fp, depth, depth_mask,
151*4882a593Smuzhiyun left_margin);
152*4882a593Smuzhiyun i = 0;
153*4882a593Smuzhiyun list_for_each_entry(chain, &child->val, list) {
154*4882a593Smuzhiyun ret += ipchain__fprintf_graph(fp, child, chain, depth,
155*4882a593Smuzhiyun new_depth_mask, i++,
156*4882a593Smuzhiyun total_samples,
157*4882a593Smuzhiyun left_margin);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun if (callchain_param.mode == CHAIN_GRAPH_REL)
161*4882a593Smuzhiyun new_total = child->children_hit;
162*4882a593Smuzhiyun else
163*4882a593Smuzhiyun new_total = total_samples;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total,
166*4882a593Smuzhiyun depth + 1,
167*4882a593Smuzhiyun new_depth_mask | (1 << depth),
168*4882a593Smuzhiyun left_margin);
169*4882a593Smuzhiyun node = next;
170*4882a593Smuzhiyun if (++entries_printed == callchain_param.print_limit)
171*4882a593Smuzhiyun break;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (callchain_param.mode == CHAIN_GRAPH_REL &&
175*4882a593Smuzhiyun remaining && remaining != total_samples) {
176*4882a593Smuzhiyun struct callchain_node rem_node = {
177*4882a593Smuzhiyun .hit = remaining,
178*4882a593Smuzhiyun };
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (!rem_sq_bracket)
181*4882a593Smuzhiyun return ret;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
184*4882a593Smuzhiyun rem_node.count = child->parent->children_count - cumul_count;
185*4882a593Smuzhiyun if (rem_node.count <= 0)
186*4882a593Smuzhiyun return ret;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun new_depth_mask &= ~(1 << (depth - 1));
190*4882a593Smuzhiyun ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
191*4882a593Smuzhiyun new_depth_mask, 0, total_samples,
192*4882a593Smuzhiyun left_margin);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun return ret;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /*
199*4882a593Smuzhiyun * If have one single callchain root, don't bother printing
200*4882a593Smuzhiyun * its percentage (100 % in fractal mode and the same percentage
201*4882a593Smuzhiyun * than the hist in graph mode). This also avoid one level of column.
202*4882a593Smuzhiyun *
203*4882a593Smuzhiyun * However when percent-limit applied, it's possible that single callchain
204*4882a593Smuzhiyun * node have different (non-100% in fractal mode) percentage.
205*4882a593Smuzhiyun */
need_percent_display(struct rb_node * node,u64 parent_samples)206*4882a593Smuzhiyun static bool need_percent_display(struct rb_node *node, u64 parent_samples)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun struct callchain_node *cnode;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (rb_next(node))
211*4882a593Smuzhiyun return true;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun cnode = rb_entry(node, struct callchain_node, rb_node);
214*4882a593Smuzhiyun return callchain_cumul_hits(cnode) != parent_samples;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
callchain__fprintf_graph(FILE * fp,struct rb_root * root,u64 total_samples,u64 parent_samples,int left_margin)217*4882a593Smuzhiyun static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
218*4882a593Smuzhiyun u64 total_samples, u64 parent_samples,
219*4882a593Smuzhiyun int left_margin)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct callchain_node *cnode;
222*4882a593Smuzhiyun struct callchain_list *chain;
223*4882a593Smuzhiyun u32 entries_printed = 0;
224*4882a593Smuzhiyun bool printed = false;
225*4882a593Smuzhiyun struct rb_node *node;
226*4882a593Smuzhiyun int i = 0;
227*4882a593Smuzhiyun int ret = 0;
228*4882a593Smuzhiyun char bf[1024];
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun node = rb_first(root);
231*4882a593Smuzhiyun if (node && !need_percent_display(node, parent_samples)) {
232*4882a593Smuzhiyun cnode = rb_entry(node, struct callchain_node, rb_node);
233*4882a593Smuzhiyun list_for_each_entry(chain, &cnode->val, list) {
234*4882a593Smuzhiyun /*
235*4882a593Smuzhiyun * If we sort by symbol, the first entry is the same than
236*4882a593Smuzhiyun * the symbol. No need to print it otherwise it appears as
237*4882a593Smuzhiyun * displayed twice.
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun if (!i++ && field_order == NULL &&
240*4882a593Smuzhiyun sort_order && strstarts(sort_order, "sym"))
241*4882a593Smuzhiyun continue;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun if (!printed) {
244*4882a593Smuzhiyun ret += callchain__fprintf_left_margin(fp, left_margin);
245*4882a593Smuzhiyun ret += fprintf(fp, "|\n");
246*4882a593Smuzhiyun ret += callchain__fprintf_left_margin(fp, left_margin);
247*4882a593Smuzhiyun ret += fprintf(fp, "---");
248*4882a593Smuzhiyun left_margin += 3;
249*4882a593Smuzhiyun printed = true;
250*4882a593Smuzhiyun } else
251*4882a593Smuzhiyun ret += callchain__fprintf_left_margin(fp, left_margin);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun ret += fprintf(fp, "%s",
254*4882a593Smuzhiyun callchain_list__sym_name(chain, bf,
255*4882a593Smuzhiyun sizeof(bf),
256*4882a593Smuzhiyun false));
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun if (symbol_conf.show_branchflag_count)
259*4882a593Smuzhiyun ret += callchain_list_counts__printf_value(
260*4882a593Smuzhiyun chain, fp, NULL, 0);
261*4882a593Smuzhiyun ret += fprintf(fp, "\n");
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (++entries_printed == callchain_param.print_limit)
264*4882a593Smuzhiyun break;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun root = &cnode->rb_root;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (callchain_param.mode == CHAIN_GRAPH_REL)
270*4882a593Smuzhiyun total_samples = parent_samples;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun ret += __callchain__fprintf_graph(fp, root, total_samples,
273*4882a593Smuzhiyun 1, 1, left_margin);
274*4882a593Smuzhiyun if (ret) {
275*4882a593Smuzhiyun /* do not add a blank line if it printed nothing */
276*4882a593Smuzhiyun ret += fprintf(fp, "\n");
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return ret;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
__callchain__fprintf_flat(FILE * fp,struct callchain_node * node,u64 total_samples)282*4882a593Smuzhiyun static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
283*4882a593Smuzhiyun u64 total_samples)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun struct callchain_list *chain;
286*4882a593Smuzhiyun size_t ret = 0;
287*4882a593Smuzhiyun char bf[1024];
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (!node)
290*4882a593Smuzhiyun return 0;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun ret += __callchain__fprintf_flat(fp, node->parent, total_samples);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun list_for_each_entry(chain, &node->val, list) {
296*4882a593Smuzhiyun if (chain->ip >= PERF_CONTEXT_MAX)
297*4882a593Smuzhiyun continue;
298*4882a593Smuzhiyun ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain,
299*4882a593Smuzhiyun bf, sizeof(bf), false));
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun return ret;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
callchain__fprintf_flat(FILE * fp,struct rb_root * tree,u64 total_samples)305*4882a593Smuzhiyun static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
306*4882a593Smuzhiyun u64 total_samples)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun size_t ret = 0;
309*4882a593Smuzhiyun u32 entries_printed = 0;
310*4882a593Smuzhiyun struct callchain_node *chain;
311*4882a593Smuzhiyun struct rb_node *rb_node = rb_first(tree);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun while (rb_node) {
314*4882a593Smuzhiyun chain = rb_entry(rb_node, struct callchain_node, rb_node);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun ret += fprintf(fp, " ");
317*4882a593Smuzhiyun ret += callchain_node__fprintf_value(chain, fp, total_samples);
318*4882a593Smuzhiyun ret += fprintf(fp, "\n");
319*4882a593Smuzhiyun ret += __callchain__fprintf_flat(fp, chain, total_samples);
320*4882a593Smuzhiyun ret += fprintf(fp, "\n");
321*4882a593Smuzhiyun if (++entries_printed == callchain_param.print_limit)
322*4882a593Smuzhiyun break;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun rb_node = rb_next(rb_node);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return ret;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
__callchain__fprintf_folded(FILE * fp,struct callchain_node * node)330*4882a593Smuzhiyun static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep ?: ";";
333*4882a593Smuzhiyun struct callchain_list *chain;
334*4882a593Smuzhiyun size_t ret = 0;
335*4882a593Smuzhiyun char bf[1024];
336*4882a593Smuzhiyun bool first;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (!node)
339*4882a593Smuzhiyun return 0;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun ret += __callchain__fprintf_folded(fp, node->parent);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun first = (ret == 0);
344*4882a593Smuzhiyun list_for_each_entry(chain, &node->val, list) {
345*4882a593Smuzhiyun if (chain->ip >= PERF_CONTEXT_MAX)
346*4882a593Smuzhiyun continue;
347*4882a593Smuzhiyun ret += fprintf(fp, "%s%s", first ? "" : sep,
348*4882a593Smuzhiyun callchain_list__sym_name(chain,
349*4882a593Smuzhiyun bf, sizeof(bf), false));
350*4882a593Smuzhiyun first = false;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
callchain__fprintf_folded(FILE * fp,struct rb_root * tree,u64 total_samples)356*4882a593Smuzhiyun static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
357*4882a593Smuzhiyun u64 total_samples)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun size_t ret = 0;
360*4882a593Smuzhiyun u32 entries_printed = 0;
361*4882a593Smuzhiyun struct callchain_node *chain;
362*4882a593Smuzhiyun struct rb_node *rb_node = rb_first(tree);
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun while (rb_node) {
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun chain = rb_entry(rb_node, struct callchain_node, rb_node);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret += callchain_node__fprintf_value(chain, fp, total_samples);
369*4882a593Smuzhiyun ret += fprintf(fp, " ");
370*4882a593Smuzhiyun ret += __callchain__fprintf_folded(fp, chain);
371*4882a593Smuzhiyun ret += fprintf(fp, "\n");
372*4882a593Smuzhiyun if (++entries_printed == callchain_param.print_limit)
373*4882a593Smuzhiyun break;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun rb_node = rb_next(rb_node);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun return ret;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
hist_entry_callchain__fprintf(struct hist_entry * he,u64 total_samples,int left_margin,FILE * fp)381*4882a593Smuzhiyun static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
382*4882a593Smuzhiyun u64 total_samples, int left_margin,
383*4882a593Smuzhiyun FILE *fp)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun u64 parent_samples = he->stat.period;
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (symbol_conf.cumulate_callchain)
388*4882a593Smuzhiyun parent_samples = he->stat_acc->period;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun switch (callchain_param.mode) {
391*4882a593Smuzhiyun case CHAIN_GRAPH_REL:
392*4882a593Smuzhiyun return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
393*4882a593Smuzhiyun parent_samples, left_margin);
394*4882a593Smuzhiyun break;
395*4882a593Smuzhiyun case CHAIN_GRAPH_ABS:
396*4882a593Smuzhiyun return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples,
397*4882a593Smuzhiyun parent_samples, left_margin);
398*4882a593Smuzhiyun break;
399*4882a593Smuzhiyun case CHAIN_FLAT:
400*4882a593Smuzhiyun return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
401*4882a593Smuzhiyun break;
402*4882a593Smuzhiyun case CHAIN_FOLDED:
403*4882a593Smuzhiyun return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
404*4882a593Smuzhiyun break;
405*4882a593Smuzhiyun case CHAIN_NONE:
406*4882a593Smuzhiyun break;
407*4882a593Smuzhiyun default:
408*4882a593Smuzhiyun pr_err("Bad callchain mode\n");
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
__hist_entry__snprintf(struct hist_entry * he,struct perf_hpp * hpp,struct perf_hpp_list * hpp_list)414*4882a593Smuzhiyun int __hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp,
415*4882a593Smuzhiyun struct perf_hpp_list *hpp_list)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
418*4882a593Smuzhiyun struct perf_hpp_fmt *fmt;
419*4882a593Smuzhiyun char *start = hpp->buf;
420*4882a593Smuzhiyun int ret;
421*4882a593Smuzhiyun bool first = true;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun if (symbol_conf.exclude_other && !he->parent)
424*4882a593Smuzhiyun return 0;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun perf_hpp_list__for_each_format(hpp_list, fmt) {
427*4882a593Smuzhiyun if (perf_hpp__should_skip(fmt, he->hists))
428*4882a593Smuzhiyun continue;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /*
431*4882a593Smuzhiyun * If there's no field_sep, we still need
432*4882a593Smuzhiyun * to display initial ' '.
433*4882a593Smuzhiyun */
434*4882a593Smuzhiyun if (!sep || !first) {
435*4882a593Smuzhiyun ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
436*4882a593Smuzhiyun advance_hpp(hpp, ret);
437*4882a593Smuzhiyun } else
438*4882a593Smuzhiyun first = false;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (perf_hpp__use_color() && fmt->color)
441*4882a593Smuzhiyun ret = fmt->color(fmt, hpp, he);
442*4882a593Smuzhiyun else
443*4882a593Smuzhiyun ret = fmt->entry(fmt, hpp, he);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
446*4882a593Smuzhiyun advance_hpp(hpp, ret);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun return hpp->buf - start;
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
hist_entry__snprintf(struct hist_entry * he,struct perf_hpp * hpp)452*4882a593Smuzhiyun static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun return __hist_entry__snprintf(he, hpp, he->hists->hpp_list);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun
hist_entry__hierarchy_fprintf(struct hist_entry * he,struct perf_hpp * hpp,struct hists * hists,FILE * fp)457*4882a593Smuzhiyun static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
458*4882a593Smuzhiyun struct perf_hpp *hpp,
459*4882a593Smuzhiyun struct hists *hists,
460*4882a593Smuzhiyun FILE *fp)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
463*4882a593Smuzhiyun struct perf_hpp_fmt *fmt;
464*4882a593Smuzhiyun struct perf_hpp_list_node *fmt_node;
465*4882a593Smuzhiyun char *buf = hpp->buf;
466*4882a593Smuzhiyun size_t size = hpp->size;
467*4882a593Smuzhiyun int ret, printed = 0;
468*4882a593Smuzhiyun bool first = true;
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (symbol_conf.exclude_other && !he->parent)
471*4882a593Smuzhiyun return 0;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun ret = scnprintf(hpp->buf, hpp->size, "%*s", he->depth * HIERARCHY_INDENT, "");
474*4882a593Smuzhiyun advance_hpp(hpp, ret);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* the first hpp_list_node is for overhead columns */
477*4882a593Smuzhiyun fmt_node = list_first_entry(&hists->hpp_formats,
478*4882a593Smuzhiyun struct perf_hpp_list_node, list);
479*4882a593Smuzhiyun perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
480*4882a593Smuzhiyun /*
481*4882a593Smuzhiyun * If there's no field_sep, we still need
482*4882a593Smuzhiyun * to display initial ' '.
483*4882a593Smuzhiyun */
484*4882a593Smuzhiyun if (!sep || !first) {
485*4882a593Smuzhiyun ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
486*4882a593Smuzhiyun advance_hpp(hpp, ret);
487*4882a593Smuzhiyun } else
488*4882a593Smuzhiyun first = false;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (perf_hpp__use_color() && fmt->color)
491*4882a593Smuzhiyun ret = fmt->color(fmt, hpp, he);
492*4882a593Smuzhiyun else
493*4882a593Smuzhiyun ret = fmt->entry(fmt, hpp, he);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun ret = hist_entry__snprintf_alignment(he, hpp, fmt, ret);
496*4882a593Smuzhiyun advance_hpp(hpp, ret);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (!sep)
500*4882a593Smuzhiyun ret = scnprintf(hpp->buf, hpp->size, "%*s",
501*4882a593Smuzhiyun (hists->nr_hpp_node - 2) * HIERARCHY_INDENT, "");
502*4882a593Smuzhiyun advance_hpp(hpp, ret);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun printed += fprintf(fp, "%s", buf);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun perf_hpp_list__for_each_format(he->hpp_list, fmt) {
507*4882a593Smuzhiyun hpp->buf = buf;
508*4882a593Smuzhiyun hpp->size = size;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun /*
511*4882a593Smuzhiyun * No need to call hist_entry__snprintf_alignment() since this
512*4882a593Smuzhiyun * fmt is always the last column in the hierarchy mode.
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun if (perf_hpp__use_color() && fmt->color)
515*4882a593Smuzhiyun fmt->color(fmt, hpp, he);
516*4882a593Smuzhiyun else
517*4882a593Smuzhiyun fmt->entry(fmt, hpp, he);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun /*
520*4882a593Smuzhiyun * dynamic entries are right-aligned but we want left-aligned
521*4882a593Smuzhiyun * in the hierarchy mode
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun printed += fprintf(fp, "%s%s", sep ?: " ", skip_spaces(buf));
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun printed += putc('\n', fp);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
528*4882a593Smuzhiyun u64 total = hists__total_period(hists);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun printed += hist_entry_callchain__fprintf(he, total, 0, fp);
531*4882a593Smuzhiyun goto out;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun out:
535*4882a593Smuzhiyun return printed;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
hist_entry__block_fprintf(struct hist_entry * he,char * bf,size_t size,FILE * fp)538*4882a593Smuzhiyun static int hist_entry__block_fprintf(struct hist_entry *he,
539*4882a593Smuzhiyun char *bf, size_t size,
540*4882a593Smuzhiyun FILE *fp)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun struct block_hist *bh = container_of(he, struct block_hist, he);
543*4882a593Smuzhiyun int ret = 0;
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun for (unsigned int i = 0; i < bh->block_hists.nr_entries; i++) {
546*4882a593Smuzhiyun struct perf_hpp hpp = {
547*4882a593Smuzhiyun .buf = bf,
548*4882a593Smuzhiyun .size = size,
549*4882a593Smuzhiyun .skip = false,
550*4882a593Smuzhiyun };
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun bh->block_idx = i;
553*4882a593Smuzhiyun hist_entry__snprintf(he, &hpp);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun if (!hpp.skip)
556*4882a593Smuzhiyun ret += fprintf(fp, "%s\n", bf);
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return ret;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
hist_entry__individual_block_fprintf(struct hist_entry * he,char * bf,size_t size,FILE * fp)562*4882a593Smuzhiyun static int hist_entry__individual_block_fprintf(struct hist_entry *he,
563*4882a593Smuzhiyun char *bf, size_t size,
564*4882a593Smuzhiyun FILE *fp)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun int ret = 0;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun struct perf_hpp hpp = {
569*4882a593Smuzhiyun .buf = bf,
570*4882a593Smuzhiyun .size = size,
571*4882a593Smuzhiyun .skip = false,
572*4882a593Smuzhiyun };
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun hist_entry__snprintf(he, &hpp);
575*4882a593Smuzhiyun if (!hpp.skip)
576*4882a593Smuzhiyun ret += fprintf(fp, "%s\n", bf);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun return ret;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
hist_entry__fprintf(struct hist_entry * he,size_t size,char * bf,size_t bfsz,FILE * fp,bool ignore_callchains)581*4882a593Smuzhiyun static int hist_entry__fprintf(struct hist_entry *he, size_t size,
582*4882a593Smuzhiyun char *bf, size_t bfsz, FILE *fp,
583*4882a593Smuzhiyun bool ignore_callchains)
584*4882a593Smuzhiyun {
585*4882a593Smuzhiyun int ret;
586*4882a593Smuzhiyun int callchain_ret = 0;
587*4882a593Smuzhiyun struct perf_hpp hpp = {
588*4882a593Smuzhiyun .buf = bf,
589*4882a593Smuzhiyun .size = size,
590*4882a593Smuzhiyun };
591*4882a593Smuzhiyun struct hists *hists = he->hists;
592*4882a593Smuzhiyun u64 total_period = hists->stats.total_period;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun if (size == 0 || size > bfsz)
595*4882a593Smuzhiyun size = hpp.size = bfsz;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (symbol_conf.report_hierarchy)
598*4882a593Smuzhiyun return hist_entry__hierarchy_fprintf(he, &hpp, hists, fp);
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun if (symbol_conf.report_block)
601*4882a593Smuzhiyun return hist_entry__block_fprintf(he, bf, size, fp);
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun if (symbol_conf.report_individual_block)
604*4882a593Smuzhiyun return hist_entry__individual_block_fprintf(he, bf, size, fp);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun hist_entry__snprintf(he, &hpp);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun ret = fprintf(fp, "%s\n", bf);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun if (hist_entry__has_callchains(he) && !ignore_callchains)
611*4882a593Smuzhiyun callchain_ret = hist_entry_callchain__fprintf(he, total_period,
612*4882a593Smuzhiyun 0, fp);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun ret += callchain_ret;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun return ret;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
print_hierarchy_indent(const char * sep,int indent,const char * line,FILE * fp)619*4882a593Smuzhiyun static int print_hierarchy_indent(const char *sep, int indent,
620*4882a593Smuzhiyun const char *line, FILE *fp)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun int width;
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun if (sep != NULL || indent < 2)
625*4882a593Smuzhiyun return 0;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun width = (indent - 2) * HIERARCHY_INDENT;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun return fprintf(fp, "%-*.*s", width, width, line);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
hists__fprintf_hierarchy_headers(struct hists * hists,struct perf_hpp * hpp,FILE * fp)632*4882a593Smuzhiyun static int hists__fprintf_hierarchy_headers(struct hists *hists,
633*4882a593Smuzhiyun struct perf_hpp *hpp, FILE *fp)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun bool first_node, first_col;
636*4882a593Smuzhiyun int indent;
637*4882a593Smuzhiyun int depth;
638*4882a593Smuzhiyun unsigned width = 0;
639*4882a593Smuzhiyun unsigned header_width = 0;
640*4882a593Smuzhiyun struct perf_hpp_fmt *fmt;
641*4882a593Smuzhiyun struct perf_hpp_list_node *fmt_node;
642*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun indent = hists->nr_hpp_node;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun /* preserve max indent depth for column headers */
647*4882a593Smuzhiyun print_hierarchy_indent(sep, indent, " ", fp);
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun /* the first hpp_list_node is for overhead columns */
650*4882a593Smuzhiyun fmt_node = list_first_entry(&hists->hpp_formats,
651*4882a593Smuzhiyun struct perf_hpp_list_node, list);
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
654*4882a593Smuzhiyun fmt->header(fmt, hpp, hists, 0, NULL);
655*4882a593Smuzhiyun fprintf(fp, "%s%s", hpp->buf, sep ?: " ");
656*4882a593Smuzhiyun }
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun /* combine sort headers with ' / ' */
659*4882a593Smuzhiyun first_node = true;
660*4882a593Smuzhiyun list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
661*4882a593Smuzhiyun if (!first_node)
662*4882a593Smuzhiyun header_width += fprintf(fp, " / ");
663*4882a593Smuzhiyun first_node = false;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun first_col = true;
666*4882a593Smuzhiyun perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
667*4882a593Smuzhiyun if (perf_hpp__should_skip(fmt, hists))
668*4882a593Smuzhiyun continue;
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (!first_col)
671*4882a593Smuzhiyun header_width += fprintf(fp, "+");
672*4882a593Smuzhiyun first_col = false;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun fmt->header(fmt, hpp, hists, 0, NULL);
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun header_width += fprintf(fp, "%s", strim(hpp->buf));
677*4882a593Smuzhiyun }
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun fprintf(fp, "\n# ");
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun /* preserve max indent depth for initial dots */
683*4882a593Smuzhiyun print_hierarchy_indent(sep, indent, dots, fp);
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun /* the first hpp_list_node is for overhead columns */
686*4882a593Smuzhiyun fmt_node = list_first_entry(&hists->hpp_formats,
687*4882a593Smuzhiyun struct perf_hpp_list_node, list);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun first_col = true;
690*4882a593Smuzhiyun perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
691*4882a593Smuzhiyun if (!first_col)
692*4882a593Smuzhiyun fprintf(fp, "%s", sep ?: "..");
693*4882a593Smuzhiyun first_col = false;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun width = fmt->width(fmt, hpp, hists);
696*4882a593Smuzhiyun fprintf(fp, "%.*s", width, dots);
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun depth = 0;
700*4882a593Smuzhiyun list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
701*4882a593Smuzhiyun first_col = true;
702*4882a593Smuzhiyun width = depth * HIERARCHY_INDENT;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
705*4882a593Smuzhiyun if (perf_hpp__should_skip(fmt, hists))
706*4882a593Smuzhiyun continue;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (!first_col)
709*4882a593Smuzhiyun width++; /* for '+' sign between column header */
710*4882a593Smuzhiyun first_col = false;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun width += fmt->width(fmt, hpp, hists);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun if (width > header_width)
716*4882a593Smuzhiyun header_width = width;
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun depth++;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun fprintf(fp, "\n#\n");
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun return 2;
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun
fprintf_line(struct hists * hists,struct perf_hpp * hpp,int line,FILE * fp)728*4882a593Smuzhiyun static void fprintf_line(struct hists *hists, struct perf_hpp *hpp,
729*4882a593Smuzhiyun int line, FILE *fp)
730*4882a593Smuzhiyun {
731*4882a593Smuzhiyun struct perf_hpp_fmt *fmt;
732*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
733*4882a593Smuzhiyun bool first = true;
734*4882a593Smuzhiyun int span = 0;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun hists__for_each_format(hists, fmt) {
737*4882a593Smuzhiyun if (perf_hpp__should_skip(fmt, hists))
738*4882a593Smuzhiyun continue;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun if (!first && !span)
741*4882a593Smuzhiyun fprintf(fp, "%s", sep ?: " ");
742*4882a593Smuzhiyun else
743*4882a593Smuzhiyun first = false;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun fmt->header(fmt, hpp, hists, line, &span);
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (!span)
748*4882a593Smuzhiyun fprintf(fp, "%s", hpp->buf);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun }
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun static int
hists__fprintf_standard_headers(struct hists * hists,struct perf_hpp * hpp,FILE * fp)753*4882a593Smuzhiyun hists__fprintf_standard_headers(struct hists *hists,
754*4882a593Smuzhiyun struct perf_hpp *hpp,
755*4882a593Smuzhiyun FILE *fp)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun struct perf_hpp_list *hpp_list = hists->hpp_list;
758*4882a593Smuzhiyun struct perf_hpp_fmt *fmt;
759*4882a593Smuzhiyun unsigned int width;
760*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
761*4882a593Smuzhiyun bool first = true;
762*4882a593Smuzhiyun int line;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun for (line = 0; line < hpp_list->nr_header_lines; line++) {
765*4882a593Smuzhiyun /* first # is displayed one level up */
766*4882a593Smuzhiyun if (line)
767*4882a593Smuzhiyun fprintf(fp, "# ");
768*4882a593Smuzhiyun fprintf_line(hists, hpp, line, fp);
769*4882a593Smuzhiyun fprintf(fp, "\n");
770*4882a593Smuzhiyun }
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (sep)
773*4882a593Smuzhiyun return hpp_list->nr_header_lines;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun first = true;
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun fprintf(fp, "# ");
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun hists__for_each_format(hists, fmt) {
780*4882a593Smuzhiyun unsigned int i;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if (perf_hpp__should_skip(fmt, hists))
783*4882a593Smuzhiyun continue;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (!first)
786*4882a593Smuzhiyun fprintf(fp, "%s", sep ?: " ");
787*4882a593Smuzhiyun else
788*4882a593Smuzhiyun first = false;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun width = fmt->width(fmt, hpp, hists);
791*4882a593Smuzhiyun for (i = 0; i < width; i++)
792*4882a593Smuzhiyun fprintf(fp, ".");
793*4882a593Smuzhiyun }
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun fprintf(fp, "\n");
796*4882a593Smuzhiyun fprintf(fp, "#\n");
797*4882a593Smuzhiyun return hpp_list->nr_header_lines + 2;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
hists__fprintf_headers(struct hists * hists,FILE * fp)800*4882a593Smuzhiyun int hists__fprintf_headers(struct hists *hists, FILE *fp)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun char bf[1024];
803*4882a593Smuzhiyun struct perf_hpp dummy_hpp = {
804*4882a593Smuzhiyun .buf = bf,
805*4882a593Smuzhiyun .size = sizeof(bf),
806*4882a593Smuzhiyun };
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun fprintf(fp, "# ");
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun if (symbol_conf.report_hierarchy)
811*4882a593Smuzhiyun return hists__fprintf_hierarchy_headers(hists, &dummy_hpp, fp);
812*4882a593Smuzhiyun else
813*4882a593Smuzhiyun return hists__fprintf_standard_headers(hists, &dummy_hpp, fp);
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
hists__fprintf(struct hists * hists,bool show_header,int max_rows,int max_cols,float min_pcnt,FILE * fp,bool ignore_callchains)817*4882a593Smuzhiyun size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
818*4882a593Smuzhiyun int max_cols, float min_pcnt, FILE *fp,
819*4882a593Smuzhiyun bool ignore_callchains)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun struct rb_node *nd;
822*4882a593Smuzhiyun size_t ret = 0;
823*4882a593Smuzhiyun const char *sep = symbol_conf.field_sep;
824*4882a593Smuzhiyun int nr_rows = 0;
825*4882a593Smuzhiyun size_t linesz;
826*4882a593Smuzhiyun char *line = NULL;
827*4882a593Smuzhiyun unsigned indent;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun init_rem_hits();
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun hists__reset_column_width(hists);
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun if (symbol_conf.col_width_list_str)
834*4882a593Smuzhiyun perf_hpp__set_user_width(symbol_conf.col_width_list_str);
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun if (show_header)
837*4882a593Smuzhiyun nr_rows += hists__fprintf_headers(hists, fp);
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun if (max_rows && nr_rows >= max_rows)
840*4882a593Smuzhiyun goto out;
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun linesz = hists__sort_list_width(hists) + 3 + 1;
843*4882a593Smuzhiyun linesz += perf_hpp__color_overhead();
844*4882a593Smuzhiyun line = malloc(linesz);
845*4882a593Smuzhiyun if (line == NULL) {
846*4882a593Smuzhiyun ret = -1;
847*4882a593Smuzhiyun goto out;
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun indent = hists__overhead_width(hists) + 4;
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun for (nd = rb_first_cached(&hists->entries); nd;
853*4882a593Smuzhiyun nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
854*4882a593Smuzhiyun struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
855*4882a593Smuzhiyun float percent;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if (h->filtered)
858*4882a593Smuzhiyun continue;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun if (symbol_conf.report_individual_block)
861*4882a593Smuzhiyun percent = block_info__total_cycles_percent(h);
862*4882a593Smuzhiyun else
863*4882a593Smuzhiyun percent = hist_entry__get_percent_limit(h);
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun if (percent < min_pcnt)
866*4882a593Smuzhiyun continue;
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun ret += hist_entry__fprintf(h, max_cols, line, linesz, fp, ignore_callchains);
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun if (max_rows && ++nr_rows >= max_rows)
871*4882a593Smuzhiyun break;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun /*
874*4882a593Smuzhiyun * If all children are filtered out or percent-limited,
875*4882a593Smuzhiyun * display "no entry >= x.xx%" message.
876*4882a593Smuzhiyun */
877*4882a593Smuzhiyun if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
878*4882a593Smuzhiyun int depth = hists->nr_hpp_node + h->depth + 1;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun print_hierarchy_indent(sep, depth, " ", fp);
881*4882a593Smuzhiyun fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun if (max_rows && ++nr_rows >= max_rows)
884*4882a593Smuzhiyun break;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun if (h->ms.map == NULL && verbose > 1) {
888*4882a593Smuzhiyun maps__fprintf(h->thread->maps, fp);
889*4882a593Smuzhiyun fprintf(fp, "%.10s end\n", graph_dotted_line);
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun free(line);
894*4882a593Smuzhiyun out:
895*4882a593Smuzhiyun zfree(&rem_sq_bracket);
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun return ret;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun
events_stats__fprintf(struct events_stats * stats,FILE * fp)900*4882a593Smuzhiyun size_t events_stats__fprintf(struct events_stats *stats, FILE *fp)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun int i;
903*4882a593Smuzhiyun size_t ret = 0;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) {
906*4882a593Smuzhiyun const char *name;
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun name = perf_event__name(i);
909*4882a593Smuzhiyun if (!strcmp(name, "UNKNOWN"))
910*4882a593Smuzhiyun continue;
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun ret += fprintf(fp, "%16s events: %10d\n", name, stats->nr_events[i]);
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun return ret;
916*4882a593Smuzhiyun }
917