1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <stdlib.h>
3*4882a593Smuzhiyun #include <string.h>
4*4882a593Smuzhiyun #include <linux/zalloc.h>
5*4882a593Smuzhiyun #include "block-info.h"
6*4882a593Smuzhiyun #include "sort.h"
7*4882a593Smuzhiyun #include "annotate.h"
8*4882a593Smuzhiyun #include "symbol.h"
9*4882a593Smuzhiyun #include "dso.h"
10*4882a593Smuzhiyun #include "map.h"
11*4882a593Smuzhiyun #include "srcline.h"
12*4882a593Smuzhiyun #include "evlist.h"
13*4882a593Smuzhiyun #include "hist.h"
14*4882a593Smuzhiyun #include "ui/browsers/hists.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun static struct block_header_column {
17*4882a593Smuzhiyun const char *name;
18*4882a593Smuzhiyun int width;
19*4882a593Smuzhiyun } block_columns[PERF_HPP_REPORT__BLOCK_MAX_INDEX] = {
20*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT] = {
21*4882a593Smuzhiyun .name = "Sampled Cycles%",
22*4882a593Smuzhiyun .width = 15,
23*4882a593Smuzhiyun },
24*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_LBR_CYCLES] = {
25*4882a593Smuzhiyun .name = "Sampled Cycles",
26*4882a593Smuzhiyun .width = 14,
27*4882a593Smuzhiyun },
28*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_CYCLES_PCT] = {
29*4882a593Smuzhiyun .name = "Avg Cycles%",
30*4882a593Smuzhiyun .width = 11,
31*4882a593Smuzhiyun },
32*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_AVG_CYCLES] = {
33*4882a593Smuzhiyun .name = "Avg Cycles",
34*4882a593Smuzhiyun .width = 10,
35*4882a593Smuzhiyun },
36*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_RANGE] = {
37*4882a593Smuzhiyun .name = "[Program Block Range]",
38*4882a593Smuzhiyun .width = 70,
39*4882a593Smuzhiyun },
40*4882a593Smuzhiyun [PERF_HPP_REPORT__BLOCK_DSO] = {
41*4882a593Smuzhiyun .name = "Shared Object",
42*4882a593Smuzhiyun .width = 20,
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
block_info__get(struct block_info * bi)46*4882a593Smuzhiyun struct block_info *block_info__get(struct block_info *bi)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun if (bi)
49*4882a593Smuzhiyun refcount_inc(&bi->refcnt);
50*4882a593Smuzhiyun return bi;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun
block_info__put(struct block_info * bi)53*4882a593Smuzhiyun void block_info__put(struct block_info *bi)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun if (bi && refcount_dec_and_test(&bi->refcnt))
56*4882a593Smuzhiyun free(bi);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
block_info__new(void)59*4882a593Smuzhiyun struct block_info *block_info__new(void)
60*4882a593Smuzhiyun {
61*4882a593Smuzhiyun struct block_info *bi = zalloc(sizeof(*bi));
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun if (bi)
64*4882a593Smuzhiyun refcount_set(&bi->refcnt, 1);
65*4882a593Smuzhiyun return bi;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
__block_info__cmp(struct hist_entry * left,struct hist_entry * right)68*4882a593Smuzhiyun int64_t __block_info__cmp(struct hist_entry *left, struct hist_entry *right)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct block_info *bi_l = left->block_info;
71*4882a593Smuzhiyun struct block_info *bi_r = right->block_info;
72*4882a593Smuzhiyun int cmp;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (!bi_l->sym || !bi_r->sym) {
75*4882a593Smuzhiyun if (!bi_l->sym && !bi_r->sym)
76*4882a593Smuzhiyun return -1;
77*4882a593Smuzhiyun else if (!bi_l->sym)
78*4882a593Smuzhiyun return -1;
79*4882a593Smuzhiyun else
80*4882a593Smuzhiyun return 1;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
84*4882a593Smuzhiyun if (cmp)
85*4882a593Smuzhiyun return cmp;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (bi_l->start != bi_r->start)
88*4882a593Smuzhiyun return (int64_t)(bi_r->start - bi_l->start);
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun return (int64_t)(bi_r->end - bi_l->end);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
block_info__cmp(struct perf_hpp_fmt * fmt __maybe_unused,struct hist_entry * left,struct hist_entry * right)93*4882a593Smuzhiyun int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
94*4882a593Smuzhiyun struct hist_entry *left, struct hist_entry *right)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun return __block_info__cmp(left, right);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
init_block_info(struct block_info * bi,struct symbol * sym,struct cyc_hist * ch,int offset,u64 total_cycles)99*4882a593Smuzhiyun static void init_block_info(struct block_info *bi, struct symbol *sym,
100*4882a593Smuzhiyun struct cyc_hist *ch, int offset,
101*4882a593Smuzhiyun u64 total_cycles)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun bi->sym = sym;
104*4882a593Smuzhiyun bi->start = ch->start;
105*4882a593Smuzhiyun bi->end = offset;
106*4882a593Smuzhiyun bi->cycles = ch->cycles;
107*4882a593Smuzhiyun bi->cycles_aggr = ch->cycles_aggr;
108*4882a593Smuzhiyun bi->num = ch->num;
109*4882a593Smuzhiyun bi->num_aggr = ch->num_aggr;
110*4882a593Smuzhiyun bi->total_cycles = total_cycles;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun memcpy(bi->cycles_spark, ch->cycles_spark,
113*4882a593Smuzhiyun NUM_SPARKS * sizeof(u64));
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
block_info__process_sym(struct hist_entry * he,struct block_hist * bh,u64 * block_cycles_aggr,u64 total_cycles)116*4882a593Smuzhiyun int block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
117*4882a593Smuzhiyun u64 *block_cycles_aggr, u64 total_cycles)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct annotation *notes;
120*4882a593Smuzhiyun struct cyc_hist *ch;
121*4882a593Smuzhiyun static struct addr_location al;
122*4882a593Smuzhiyun u64 cycles = 0;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if (!he->ms.map || !he->ms.sym)
125*4882a593Smuzhiyun return 0;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun memset(&al, 0, sizeof(al));
128*4882a593Smuzhiyun al.map = he->ms.map;
129*4882a593Smuzhiyun al.sym = he->ms.sym;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun notes = symbol__annotation(he->ms.sym);
132*4882a593Smuzhiyun if (!notes || !notes->src || !notes->src->cycles_hist)
133*4882a593Smuzhiyun return 0;
134*4882a593Smuzhiyun ch = notes->src->cycles_hist;
135*4882a593Smuzhiyun for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
136*4882a593Smuzhiyun if (ch[i].num_aggr) {
137*4882a593Smuzhiyun struct block_info *bi;
138*4882a593Smuzhiyun struct hist_entry *he_block;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun bi = block_info__new();
141*4882a593Smuzhiyun if (!bi)
142*4882a593Smuzhiyun return -1;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun init_block_info(bi, he->ms.sym, &ch[i], i,
145*4882a593Smuzhiyun total_cycles);
146*4882a593Smuzhiyun cycles += bi->cycles_aggr / bi->num_aggr;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun he_block = hists__add_entry_block(&bh->block_hists,
149*4882a593Smuzhiyun &al, bi);
150*4882a593Smuzhiyun if (!he_block) {
151*4882a593Smuzhiyun block_info__put(bi);
152*4882a593Smuzhiyun return -1;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (block_cycles_aggr)
158*4882a593Smuzhiyun *block_cycles_aggr += cycles;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
block_column_header(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hists * hists __maybe_unused,int line __maybe_unused,int * span __maybe_unused)163*4882a593Smuzhiyun static int block_column_header(struct perf_hpp_fmt *fmt,
164*4882a593Smuzhiyun struct perf_hpp *hpp,
165*4882a593Smuzhiyun struct hists *hists __maybe_unused,
166*4882a593Smuzhiyun int line __maybe_unused,
167*4882a593Smuzhiyun int *span __maybe_unused)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
172*4882a593Smuzhiyun block_fmt->header);
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
block_column_width(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp __maybe_unused,struct hists * hists __maybe_unused)175*4882a593Smuzhiyun static int block_column_width(struct perf_hpp_fmt *fmt,
176*4882a593Smuzhiyun struct perf_hpp *hpp __maybe_unused,
177*4882a593Smuzhiyun struct hists *hists __maybe_unused)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return block_fmt->width;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
color_pct(struct perf_hpp * hpp,int width,double pct)184*4882a593Smuzhiyun static int color_pct(struct perf_hpp *hpp, int width, double pct)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun #ifdef HAVE_SLANG_SUPPORT
187*4882a593Smuzhiyun if (use_browser) {
188*4882a593Smuzhiyun return __hpp__slsmg_color_printf(hpp, "%*.2f%%",
189*4882a593Smuzhiyun width - 1, pct);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun #endif
192*4882a593Smuzhiyun return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, pct);
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun
block_total_cycles_pct_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)195*4882a593Smuzhiyun static int block_total_cycles_pct_entry(struct perf_hpp_fmt *fmt,
196*4882a593Smuzhiyun struct perf_hpp *hpp,
197*4882a593Smuzhiyun struct hist_entry *he)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
200*4882a593Smuzhiyun struct block_info *bi = he->block_info;
201*4882a593Smuzhiyun double ratio = 0.0;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (block_fmt->total_cycles)
204*4882a593Smuzhiyun ratio = (double)bi->cycles_aggr / (double)block_fmt->total_cycles;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return color_pct(hpp, block_fmt->width, 100.0 * ratio);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
block_total_cycles_pct_sort(struct perf_hpp_fmt * fmt,struct hist_entry * left,struct hist_entry * right)209*4882a593Smuzhiyun static int64_t block_total_cycles_pct_sort(struct perf_hpp_fmt *fmt,
210*4882a593Smuzhiyun struct hist_entry *left,
211*4882a593Smuzhiyun struct hist_entry *right)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
214*4882a593Smuzhiyun struct block_info *bi_l = left->block_info;
215*4882a593Smuzhiyun struct block_info *bi_r = right->block_info;
216*4882a593Smuzhiyun double l, r;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (block_fmt->total_cycles) {
219*4882a593Smuzhiyun l = ((double)bi_l->cycles_aggr /
220*4882a593Smuzhiyun (double)block_fmt->total_cycles) * 100000.0;
221*4882a593Smuzhiyun r = ((double)bi_r->cycles_aggr /
222*4882a593Smuzhiyun (double)block_fmt->total_cycles) * 100000.0;
223*4882a593Smuzhiyun return (int64_t)l - (int64_t)r;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun return 0;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
cycles_string(u64 cycles,char * buf,int size)229*4882a593Smuzhiyun static void cycles_string(u64 cycles, char *buf, int size)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun if (cycles >= 1000000)
232*4882a593Smuzhiyun scnprintf(buf, size, "%.1fM", (double)cycles / 1000000.0);
233*4882a593Smuzhiyun else if (cycles >= 1000)
234*4882a593Smuzhiyun scnprintf(buf, size, "%.1fK", (double)cycles / 1000.0);
235*4882a593Smuzhiyun else
236*4882a593Smuzhiyun scnprintf(buf, size, "%1d", cycles);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
block_cycles_lbr_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)239*4882a593Smuzhiyun static int block_cycles_lbr_entry(struct perf_hpp_fmt *fmt,
240*4882a593Smuzhiyun struct perf_hpp *hpp, struct hist_entry *he)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
243*4882a593Smuzhiyun struct block_info *bi = he->block_info;
244*4882a593Smuzhiyun char cycles_buf[16];
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun cycles_string(bi->cycles_aggr, cycles_buf, sizeof(cycles_buf));
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
249*4882a593Smuzhiyun cycles_buf);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
block_cycles_pct_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)252*4882a593Smuzhiyun static int block_cycles_pct_entry(struct perf_hpp_fmt *fmt,
253*4882a593Smuzhiyun struct perf_hpp *hpp, struct hist_entry *he)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
256*4882a593Smuzhiyun struct block_info *bi = he->block_info;
257*4882a593Smuzhiyun double ratio = 0.0;
258*4882a593Smuzhiyun u64 avg;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (block_fmt->block_cycles && bi->num_aggr) {
261*4882a593Smuzhiyun avg = bi->cycles_aggr / bi->num_aggr;
262*4882a593Smuzhiyun ratio = (double)avg / (double)block_fmt->block_cycles;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return color_pct(hpp, block_fmt->width, 100.0 * ratio);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
block_avg_cycles_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)268*4882a593Smuzhiyun static int block_avg_cycles_entry(struct perf_hpp_fmt *fmt,
269*4882a593Smuzhiyun struct perf_hpp *hpp,
270*4882a593Smuzhiyun struct hist_entry *he)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
273*4882a593Smuzhiyun struct block_info *bi = he->block_info;
274*4882a593Smuzhiyun char cycles_buf[16];
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun cycles_string(bi->cycles_aggr / bi->num_aggr, cycles_buf,
277*4882a593Smuzhiyun sizeof(cycles_buf));
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
280*4882a593Smuzhiyun cycles_buf);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
block_range_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)283*4882a593Smuzhiyun static int block_range_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
284*4882a593Smuzhiyun struct hist_entry *he)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
287*4882a593Smuzhiyun struct block_info *bi = he->block_info;
288*4882a593Smuzhiyun char buf[128];
289*4882a593Smuzhiyun char *start_line, *end_line;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun symbol_conf.disable_add2line_warn = true;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
294*4882a593Smuzhiyun he->ms.sym);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
297*4882a593Smuzhiyun he->ms.sym);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
300*4882a593Smuzhiyun (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
301*4882a593Smuzhiyun scnprintf(buf, sizeof(buf), "[%s -> %s]",
302*4882a593Smuzhiyun start_line, end_line);
303*4882a593Smuzhiyun } else {
304*4882a593Smuzhiyun scnprintf(buf, sizeof(buf), "[%7lx -> %7lx]",
305*4882a593Smuzhiyun bi->start, bi->end);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun free_srcline(start_line);
309*4882a593Smuzhiyun free_srcline(end_line);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
block_dso_entry(struct perf_hpp_fmt * fmt,struct perf_hpp * hpp,struct hist_entry * he)314*4882a593Smuzhiyun static int block_dso_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
315*4882a593Smuzhiyun struct hist_entry *he)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
318*4882a593Smuzhiyun struct map *map = he->ms.map;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun if (map && map->dso) {
321*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
322*4882a593Smuzhiyun map->dso->short_name);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
326*4882a593Smuzhiyun "[unknown]");
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
init_block_header(struct block_fmt * block_fmt)329*4882a593Smuzhiyun static void init_block_header(struct block_fmt *block_fmt)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct perf_hpp_fmt *fmt = &block_fmt->fmt;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun BUG_ON(block_fmt->idx >= PERF_HPP_REPORT__BLOCK_MAX_INDEX);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun block_fmt->header = block_columns[block_fmt->idx].name;
336*4882a593Smuzhiyun block_fmt->width = block_columns[block_fmt->idx].width;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun fmt->header = block_column_header;
339*4882a593Smuzhiyun fmt->width = block_column_width;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
hpp_register(struct block_fmt * block_fmt,int idx,struct perf_hpp_list * hpp_list)342*4882a593Smuzhiyun static void hpp_register(struct block_fmt *block_fmt, int idx,
343*4882a593Smuzhiyun struct perf_hpp_list *hpp_list)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun struct perf_hpp_fmt *fmt = &block_fmt->fmt;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun block_fmt->idx = idx;
348*4882a593Smuzhiyun INIT_LIST_HEAD(&fmt->list);
349*4882a593Smuzhiyun INIT_LIST_HEAD(&fmt->sort_list);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun switch (idx) {
352*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT:
353*4882a593Smuzhiyun fmt->color = block_total_cycles_pct_entry;
354*4882a593Smuzhiyun fmt->cmp = block_info__cmp;
355*4882a593Smuzhiyun fmt->sort = block_total_cycles_pct_sort;
356*4882a593Smuzhiyun break;
357*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_LBR_CYCLES:
358*4882a593Smuzhiyun fmt->entry = block_cycles_lbr_entry;
359*4882a593Smuzhiyun break;
360*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_CYCLES_PCT:
361*4882a593Smuzhiyun fmt->color = block_cycles_pct_entry;
362*4882a593Smuzhiyun break;
363*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_AVG_CYCLES:
364*4882a593Smuzhiyun fmt->entry = block_avg_cycles_entry;
365*4882a593Smuzhiyun break;
366*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_RANGE:
367*4882a593Smuzhiyun fmt->entry = block_range_entry;
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun case PERF_HPP_REPORT__BLOCK_DSO:
370*4882a593Smuzhiyun fmt->entry = block_dso_entry;
371*4882a593Smuzhiyun break;
372*4882a593Smuzhiyun default:
373*4882a593Smuzhiyun return;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun init_block_header(block_fmt);
377*4882a593Smuzhiyun perf_hpp_list__column_register(hpp_list, fmt);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
register_block_columns(struct perf_hpp_list * hpp_list,struct block_fmt * block_fmts,int * block_hpps,int nr_hpps)380*4882a593Smuzhiyun static void register_block_columns(struct perf_hpp_list *hpp_list,
381*4882a593Smuzhiyun struct block_fmt *block_fmts,
382*4882a593Smuzhiyun int *block_hpps, int nr_hpps)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun for (int i = 0; i < nr_hpps; i++)
385*4882a593Smuzhiyun hpp_register(&block_fmts[i], block_hpps[i], hpp_list);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
init_block_hist(struct block_hist * bh,struct block_fmt * block_fmts,int * block_hpps,int nr_hpps)388*4882a593Smuzhiyun static void init_block_hist(struct block_hist *bh, struct block_fmt *block_fmts,
389*4882a593Smuzhiyun int *block_hpps, int nr_hpps)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun __hists__init(&bh->block_hists, &bh->block_list);
392*4882a593Smuzhiyun perf_hpp_list__init(&bh->block_list);
393*4882a593Smuzhiyun bh->block_list.nr_header_lines = 1;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun register_block_columns(&bh->block_list, block_fmts,
396*4882a593Smuzhiyun block_hpps, nr_hpps);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun /* Sort by the first fmt */
399*4882a593Smuzhiyun perf_hpp_list__register_sort_field(&bh->block_list, &block_fmts[0].fmt);
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
process_block_report(struct hists * hists,struct block_report * block_report,u64 total_cycles,int * block_hpps,int nr_hpps)402*4882a593Smuzhiyun static int process_block_report(struct hists *hists,
403*4882a593Smuzhiyun struct block_report *block_report,
404*4882a593Smuzhiyun u64 total_cycles, int *block_hpps,
405*4882a593Smuzhiyun int nr_hpps)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun struct rb_node *next = rb_first_cached(&hists->entries);
408*4882a593Smuzhiyun struct block_hist *bh = &block_report->hist;
409*4882a593Smuzhiyun struct hist_entry *he;
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun if (nr_hpps > PERF_HPP_REPORT__BLOCK_MAX_INDEX)
412*4882a593Smuzhiyun return -1;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun block_report->nr_fmts = nr_hpps;
415*4882a593Smuzhiyun init_block_hist(bh, block_report->fmts, block_hpps, nr_hpps);
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun while (next) {
418*4882a593Smuzhiyun he = rb_entry(next, struct hist_entry, rb_node);
419*4882a593Smuzhiyun block_info__process_sym(he, bh, &block_report->cycles,
420*4882a593Smuzhiyun total_cycles);
421*4882a593Smuzhiyun next = rb_next(&he->rb_node);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun for (int i = 0; i < nr_hpps; i++) {
425*4882a593Smuzhiyun block_report->fmts[i].total_cycles = total_cycles;
426*4882a593Smuzhiyun block_report->fmts[i].block_cycles = block_report->cycles;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun hists__output_resort(&bh->block_hists, NULL);
430*4882a593Smuzhiyun return 0;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
block_info__create_report(struct evlist * evlist,u64 total_cycles,int * block_hpps,int nr_hpps,int * nr_reps)433*4882a593Smuzhiyun struct block_report *block_info__create_report(struct evlist *evlist,
434*4882a593Smuzhiyun u64 total_cycles,
435*4882a593Smuzhiyun int *block_hpps, int nr_hpps,
436*4882a593Smuzhiyun int *nr_reps)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun struct block_report *block_reports;
439*4882a593Smuzhiyun int nr_hists = evlist->core.nr_entries, i = 0;
440*4882a593Smuzhiyun struct evsel *pos;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun block_reports = calloc(nr_hists, sizeof(struct block_report));
443*4882a593Smuzhiyun if (!block_reports)
444*4882a593Smuzhiyun return NULL;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun evlist__for_each_entry(evlist, pos) {
447*4882a593Smuzhiyun struct hists *hists = evsel__hists(pos);
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun process_block_report(hists, &block_reports[i], total_cycles,
450*4882a593Smuzhiyun block_hpps, nr_hpps);
451*4882a593Smuzhiyun i++;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun *nr_reps = nr_hists;
455*4882a593Smuzhiyun return block_reports;
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
block_info__free_report(struct block_report * reps,int nr_reps)458*4882a593Smuzhiyun void block_info__free_report(struct block_report *reps, int nr_reps)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun for (int i = 0; i < nr_reps; i++)
461*4882a593Smuzhiyun hists__delete_entries(&reps[i].hist.block_hists);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun free(reps);
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
report__browse_block_hists(struct block_hist * bh,float min_percent,struct evsel * evsel,struct perf_env * env,struct annotation_options * annotation_opts)466*4882a593Smuzhiyun int report__browse_block_hists(struct block_hist *bh, float min_percent,
467*4882a593Smuzhiyun struct evsel *evsel, struct perf_env *env,
468*4882a593Smuzhiyun struct annotation_options *annotation_opts)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun int ret;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun switch (use_browser) {
473*4882a593Smuzhiyun case 0:
474*4882a593Smuzhiyun symbol_conf.report_individual_block = true;
475*4882a593Smuzhiyun hists__fprintf(&bh->block_hists, true, 0, 0, min_percent,
476*4882a593Smuzhiyun stdout, true);
477*4882a593Smuzhiyun return 0;
478*4882a593Smuzhiyun case 1:
479*4882a593Smuzhiyun symbol_conf.report_individual_block = true;
480*4882a593Smuzhiyun ret = block_hists_tui_browse(bh, evsel, min_percent,
481*4882a593Smuzhiyun env, annotation_opts);
482*4882a593Smuzhiyun return ret;
483*4882a593Smuzhiyun default:
484*4882a593Smuzhiyun return -1;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun return 0;
488*4882a593Smuzhiyun }
489*4882a593Smuzhiyun
block_info__total_cycles_percent(struct hist_entry * he)490*4882a593Smuzhiyun float block_info__total_cycles_percent(struct hist_entry *he)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct block_info *bi = he->block_info;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (bi->total_cycles)
495*4882a593Smuzhiyun return bi->cycles * 100.0 / bi->total_cycles;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun return 0.0;
498*4882a593Smuzhiyun }
499