162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <stdlib.h>
362306a36Sopenharmony_ci#include <string.h>
462306a36Sopenharmony_ci#include <linux/zalloc.h>
562306a36Sopenharmony_ci#include "block-info.h"
662306a36Sopenharmony_ci#include "sort.h"
762306a36Sopenharmony_ci#include "annotate.h"
862306a36Sopenharmony_ci#include "symbol.h"
962306a36Sopenharmony_ci#include "dso.h"
1062306a36Sopenharmony_ci#include "map.h"
1162306a36Sopenharmony_ci#include "srcline.h"
1262306a36Sopenharmony_ci#include "evlist.h"
1362306a36Sopenharmony_ci#include "hist.h"
1462306a36Sopenharmony_ci#include "ui/browsers/hists.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic struct block_header_column {
1762306a36Sopenharmony_ci	const char *name;
1862306a36Sopenharmony_ci	int width;
1962306a36Sopenharmony_ci} block_columns[PERF_HPP_REPORT__BLOCK_MAX_INDEX] = {
2062306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT] = {
2162306a36Sopenharmony_ci		.name = "Sampled Cycles%",
2262306a36Sopenharmony_ci		.width = 15,
2362306a36Sopenharmony_ci	},
2462306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_LBR_CYCLES] = {
2562306a36Sopenharmony_ci		.name = "Sampled Cycles",
2662306a36Sopenharmony_ci		.width = 14,
2762306a36Sopenharmony_ci	},
2862306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_CYCLES_PCT] = {
2962306a36Sopenharmony_ci		.name = "Avg Cycles%",
3062306a36Sopenharmony_ci		.width = 11,
3162306a36Sopenharmony_ci	},
3262306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_AVG_CYCLES] = {
3362306a36Sopenharmony_ci		.name = "Avg Cycles",
3462306a36Sopenharmony_ci		.width = 10,
3562306a36Sopenharmony_ci	},
3662306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_RANGE] = {
3762306a36Sopenharmony_ci		.name = "[Program Block Range]",
3862306a36Sopenharmony_ci		.width = 70,
3962306a36Sopenharmony_ci	},
4062306a36Sopenharmony_ci	[PERF_HPP_REPORT__BLOCK_DSO] = {
4162306a36Sopenharmony_ci		.name = "Shared Object",
4262306a36Sopenharmony_ci		.width = 20,
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct block_info *block_info__get(struct block_info *bi)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	if (bi)
4962306a36Sopenharmony_ci		refcount_inc(&bi->refcnt);
5062306a36Sopenharmony_ci	return bi;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_civoid block_info__put(struct block_info *bi)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	if (bi && refcount_dec_and_test(&bi->refcnt))
5662306a36Sopenharmony_ci		free(bi);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistruct block_info *block_info__new(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct block_info *bi = zalloc(sizeof(*bi));
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (bi)
6462306a36Sopenharmony_ci		refcount_set(&bi->refcnt, 1);
6562306a36Sopenharmony_ci	return bi;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciint64_t __block_info__cmp(struct hist_entry *left, struct hist_entry *right)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct block_info *bi_l = left->block_info;
7162306a36Sopenharmony_ci	struct block_info *bi_r = right->block_info;
7262306a36Sopenharmony_ci	int cmp;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (!bi_l->sym || !bi_r->sym) {
7562306a36Sopenharmony_ci		if (!bi_l->sym && !bi_r->sym)
7662306a36Sopenharmony_ci			return -1;
7762306a36Sopenharmony_ci		else if (!bi_l->sym)
7862306a36Sopenharmony_ci			return -1;
7962306a36Sopenharmony_ci		else
8062306a36Sopenharmony_ci			return 1;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
8462306a36Sopenharmony_ci	if (cmp)
8562306a36Sopenharmony_ci		return cmp;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (bi_l->start != bi_r->start)
8862306a36Sopenharmony_ci		return (int64_t)(bi_r->start - bi_l->start);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return (int64_t)(bi_r->end - bi_l->end);
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
9462306a36Sopenharmony_ci			struct hist_entry *left, struct hist_entry *right)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	return __block_info__cmp(left, right);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic void init_block_info(struct block_info *bi, struct symbol *sym,
10062306a36Sopenharmony_ci			    struct cyc_hist *ch, int offset,
10162306a36Sopenharmony_ci			    u64 total_cycles)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	bi->sym = sym;
10462306a36Sopenharmony_ci	bi->start = ch->start;
10562306a36Sopenharmony_ci	bi->end = offset;
10662306a36Sopenharmony_ci	bi->cycles = ch->cycles;
10762306a36Sopenharmony_ci	bi->cycles_aggr = ch->cycles_aggr;
10862306a36Sopenharmony_ci	bi->num = ch->num;
10962306a36Sopenharmony_ci	bi->num_aggr = ch->num_aggr;
11062306a36Sopenharmony_ci	bi->total_cycles = total_cycles;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	memcpy(bi->cycles_spark, ch->cycles_spark,
11362306a36Sopenharmony_ci	       NUM_SPARKS * sizeof(u64));
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
11762306a36Sopenharmony_ci			    u64 *block_cycles_aggr, u64 total_cycles)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct annotation *notes;
12062306a36Sopenharmony_ci	struct cyc_hist *ch;
12162306a36Sopenharmony_ci	static struct addr_location al;
12262306a36Sopenharmony_ci	u64 cycles = 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!he->ms.map || !he->ms.sym)
12562306a36Sopenharmony_ci		return 0;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	memset(&al, 0, sizeof(al));
12862306a36Sopenharmony_ci	al.map = he->ms.map;
12962306a36Sopenharmony_ci	al.sym = he->ms.sym;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	notes = symbol__annotation(he->ms.sym);
13262306a36Sopenharmony_ci	if (!notes || !notes->src || !notes->src->cycles_hist)
13362306a36Sopenharmony_ci		return 0;
13462306a36Sopenharmony_ci	ch = notes->src->cycles_hist;
13562306a36Sopenharmony_ci	for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
13662306a36Sopenharmony_ci		if (ch[i].num_aggr) {
13762306a36Sopenharmony_ci			struct block_info *bi;
13862306a36Sopenharmony_ci			struct hist_entry *he_block;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			bi = block_info__new();
14162306a36Sopenharmony_ci			if (!bi)
14262306a36Sopenharmony_ci				return -1;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci			init_block_info(bi, he->ms.sym, &ch[i], i,
14562306a36Sopenharmony_ci					total_cycles);
14662306a36Sopenharmony_ci			cycles += bi->cycles_aggr / bi->num_aggr;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci			he_block = hists__add_entry_block(&bh->block_hists,
14962306a36Sopenharmony_ci							  &al, bi);
15062306a36Sopenharmony_ci			if (!he_block) {
15162306a36Sopenharmony_ci				block_info__put(bi);
15262306a36Sopenharmony_ci				return -1;
15362306a36Sopenharmony_ci			}
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (block_cycles_aggr)
15862306a36Sopenharmony_ci		*block_cycles_aggr += cycles;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return 0;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int block_column_header(struct perf_hpp_fmt *fmt,
16462306a36Sopenharmony_ci			       struct perf_hpp *hpp,
16562306a36Sopenharmony_ci			       struct hists *hists __maybe_unused,
16662306a36Sopenharmony_ci			       int line __maybe_unused,
16762306a36Sopenharmony_ci			       int *span __maybe_unused)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
17262306a36Sopenharmony_ci			 block_fmt->header);
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic int block_column_width(struct perf_hpp_fmt *fmt,
17662306a36Sopenharmony_ci			      struct perf_hpp *hpp __maybe_unused,
17762306a36Sopenharmony_ci			      struct hists *hists __maybe_unused)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return block_fmt->width;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int color_pct(struct perf_hpp *hpp, int width, double pct)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci#ifdef HAVE_SLANG_SUPPORT
18762306a36Sopenharmony_ci	if (use_browser) {
18862306a36Sopenharmony_ci		return __hpp__slsmg_color_printf(hpp, "%*.2f%%",
18962306a36Sopenharmony_ci						 width - 1, pct);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci#endif
19262306a36Sopenharmony_ci	return hpp_color_scnprintf(hpp, "%*.2f%%", width - 1, pct);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int block_total_cycles_pct_entry(struct perf_hpp_fmt *fmt,
19662306a36Sopenharmony_ci					struct perf_hpp *hpp,
19762306a36Sopenharmony_ci					struct hist_entry *he)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
20062306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
20162306a36Sopenharmony_ci	double ratio = 0.0;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (block_fmt->total_cycles)
20462306a36Sopenharmony_ci		ratio = (double)bi->cycles_aggr / (double)block_fmt->total_cycles;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return color_pct(hpp, block_fmt->width, 100.0 * ratio);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int64_t block_total_cycles_pct_sort(struct perf_hpp_fmt *fmt,
21062306a36Sopenharmony_ci					   struct hist_entry *left,
21162306a36Sopenharmony_ci					   struct hist_entry *right)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
21462306a36Sopenharmony_ci	struct block_info *bi_l = left->block_info;
21562306a36Sopenharmony_ci	struct block_info *bi_r = right->block_info;
21662306a36Sopenharmony_ci	double l, r;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	if (block_fmt->total_cycles) {
21962306a36Sopenharmony_ci		l = ((double)bi_l->cycles_aggr /
22062306a36Sopenharmony_ci			(double)block_fmt->total_cycles) * 100000.0;
22162306a36Sopenharmony_ci		r = ((double)bi_r->cycles_aggr /
22262306a36Sopenharmony_ci			(double)block_fmt->total_cycles) * 100000.0;
22362306a36Sopenharmony_ci		return (int64_t)l - (int64_t)r;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void cycles_string(u64 cycles, char *buf, int size)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	if (cycles >= 1000000)
23262306a36Sopenharmony_ci		scnprintf(buf, size, "%.1fM", (double)cycles / 1000000.0);
23362306a36Sopenharmony_ci	else if (cycles >= 1000)
23462306a36Sopenharmony_ci		scnprintf(buf, size, "%.1fK", (double)cycles / 1000.0);
23562306a36Sopenharmony_ci	else
23662306a36Sopenharmony_ci		scnprintf(buf, size, "%1d", cycles);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int block_cycles_lbr_entry(struct perf_hpp_fmt *fmt,
24062306a36Sopenharmony_ci				  struct perf_hpp *hpp, struct hist_entry *he)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
24362306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
24462306a36Sopenharmony_ci	char cycles_buf[16];
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	cycles_string(bi->cycles_aggr, cycles_buf, sizeof(cycles_buf));
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
24962306a36Sopenharmony_ci			 cycles_buf);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic int block_cycles_pct_entry(struct perf_hpp_fmt *fmt,
25362306a36Sopenharmony_ci				  struct perf_hpp *hpp, struct hist_entry *he)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
25662306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
25762306a36Sopenharmony_ci	double ratio = 0.0;
25862306a36Sopenharmony_ci	u64 avg;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (block_fmt->block_cycles && bi->num_aggr) {
26162306a36Sopenharmony_ci		avg = bi->cycles_aggr / bi->num_aggr;
26262306a36Sopenharmony_ci		ratio = (double)avg / (double)block_fmt->block_cycles;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return color_pct(hpp, block_fmt->width, 100.0 * ratio);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int block_avg_cycles_entry(struct perf_hpp_fmt *fmt,
26962306a36Sopenharmony_ci				  struct perf_hpp *hpp,
27062306a36Sopenharmony_ci				  struct hist_entry *he)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
27362306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
27462306a36Sopenharmony_ci	char cycles_buf[16];
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	cycles_string(bi->cycles_aggr / bi->num_aggr, cycles_buf,
27762306a36Sopenharmony_ci		      sizeof(cycles_buf));
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
28062306a36Sopenharmony_ci			 cycles_buf);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int block_range_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
28462306a36Sopenharmony_ci			     struct hist_entry *he)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
28762306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
28862306a36Sopenharmony_ci	char buf[128];
28962306a36Sopenharmony_ci	char *start_line, *end_line;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	symbol_conf.disable_add2line_warn = true;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
29462306a36Sopenharmony_ci				  he->ms.sym);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
29762306a36Sopenharmony_ci				he->ms.sym);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (start_line != SRCLINE_UNKNOWN &&
30062306a36Sopenharmony_ci	    end_line != SRCLINE_UNKNOWN) {
30162306a36Sopenharmony_ci		scnprintf(buf, sizeof(buf), "[%s -> %s]",
30262306a36Sopenharmony_ci			  start_line, end_line);
30362306a36Sopenharmony_ci	} else {
30462306a36Sopenharmony_ci		scnprintf(buf, sizeof(buf), "[%7lx -> %7lx]",
30562306a36Sopenharmony_ci			  bi->start, bi->end);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	zfree_srcline(&start_line);
30962306a36Sopenharmony_ci	zfree_srcline(&end_line);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_cistatic int block_dso_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
31562306a36Sopenharmony_ci			   struct hist_entry *he)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
31862306a36Sopenharmony_ci	struct map *map = he->ms.map;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (map && map__dso(map)) {
32162306a36Sopenharmony_ci		return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
32262306a36Sopenharmony_ci				 map__dso(map)->short_name);
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
32662306a36Sopenharmony_ci			 "[unknown]");
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void init_block_header(struct block_fmt *block_fmt)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt = &block_fmt->fmt;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	BUG_ON(block_fmt->idx >= PERF_HPP_REPORT__BLOCK_MAX_INDEX);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	block_fmt->header = block_columns[block_fmt->idx].name;
33662306a36Sopenharmony_ci	block_fmt->width = block_columns[block_fmt->idx].width;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	fmt->header = block_column_header;
33962306a36Sopenharmony_ci	fmt->width = block_column_width;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void hpp_register(struct block_fmt *block_fmt, int idx,
34362306a36Sopenharmony_ci			 struct perf_hpp_list *hpp_list)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct perf_hpp_fmt *fmt = &block_fmt->fmt;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	block_fmt->idx = idx;
34862306a36Sopenharmony_ci	INIT_LIST_HEAD(&fmt->list);
34962306a36Sopenharmony_ci	INIT_LIST_HEAD(&fmt->sort_list);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	switch (idx) {
35262306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT:
35362306a36Sopenharmony_ci		fmt->color = block_total_cycles_pct_entry;
35462306a36Sopenharmony_ci		fmt->cmp = block_info__cmp;
35562306a36Sopenharmony_ci		fmt->sort = block_total_cycles_pct_sort;
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_LBR_CYCLES:
35862306a36Sopenharmony_ci		fmt->entry = block_cycles_lbr_entry;
35962306a36Sopenharmony_ci		break;
36062306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_CYCLES_PCT:
36162306a36Sopenharmony_ci		fmt->color = block_cycles_pct_entry;
36262306a36Sopenharmony_ci		break;
36362306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_AVG_CYCLES:
36462306a36Sopenharmony_ci		fmt->entry = block_avg_cycles_entry;
36562306a36Sopenharmony_ci		break;
36662306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_RANGE:
36762306a36Sopenharmony_ci		fmt->entry = block_range_entry;
36862306a36Sopenharmony_ci		break;
36962306a36Sopenharmony_ci	case PERF_HPP_REPORT__BLOCK_DSO:
37062306a36Sopenharmony_ci		fmt->entry = block_dso_entry;
37162306a36Sopenharmony_ci		break;
37262306a36Sopenharmony_ci	default:
37362306a36Sopenharmony_ci		return;
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	init_block_header(block_fmt);
37762306a36Sopenharmony_ci	perf_hpp_list__column_register(hpp_list, fmt);
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic void register_block_columns(struct perf_hpp_list *hpp_list,
38162306a36Sopenharmony_ci				   struct block_fmt *block_fmts,
38262306a36Sopenharmony_ci				   int *block_hpps, int nr_hpps)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	for (int i = 0; i < nr_hpps; i++)
38562306a36Sopenharmony_ci		hpp_register(&block_fmts[i], block_hpps[i], hpp_list);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic void init_block_hist(struct block_hist *bh, struct block_fmt *block_fmts,
38962306a36Sopenharmony_ci			    int *block_hpps, int nr_hpps)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	__hists__init(&bh->block_hists, &bh->block_list);
39262306a36Sopenharmony_ci	perf_hpp_list__init(&bh->block_list);
39362306a36Sopenharmony_ci	bh->block_list.nr_header_lines = 1;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	register_block_columns(&bh->block_list, block_fmts,
39662306a36Sopenharmony_ci			       block_hpps, nr_hpps);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Sort by the first fmt */
39962306a36Sopenharmony_ci	perf_hpp_list__register_sort_field(&bh->block_list, &block_fmts[0].fmt);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int process_block_report(struct hists *hists,
40362306a36Sopenharmony_ci				struct block_report *block_report,
40462306a36Sopenharmony_ci				u64 total_cycles, int *block_hpps,
40562306a36Sopenharmony_ci				int nr_hpps)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	struct rb_node *next = rb_first_cached(&hists->entries);
40862306a36Sopenharmony_ci	struct block_hist *bh = &block_report->hist;
40962306a36Sopenharmony_ci	struct hist_entry *he;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	if (nr_hpps > PERF_HPP_REPORT__BLOCK_MAX_INDEX)
41262306a36Sopenharmony_ci		return -1;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	block_report->nr_fmts = nr_hpps;
41562306a36Sopenharmony_ci	init_block_hist(bh, block_report->fmts, block_hpps, nr_hpps);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	while (next) {
41862306a36Sopenharmony_ci		he = rb_entry(next, struct hist_entry, rb_node);
41962306a36Sopenharmony_ci		block_info__process_sym(he, bh, &block_report->cycles,
42062306a36Sopenharmony_ci					total_cycles);
42162306a36Sopenharmony_ci		next = rb_next(&he->rb_node);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	for (int i = 0; i < nr_hpps; i++) {
42562306a36Sopenharmony_ci		block_report->fmts[i].total_cycles = total_cycles;
42662306a36Sopenharmony_ci		block_report->fmts[i].block_cycles = block_report->cycles;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	hists__output_resort(&bh->block_hists, NULL);
43062306a36Sopenharmony_ci	return 0;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistruct block_report *block_info__create_report(struct evlist *evlist,
43462306a36Sopenharmony_ci					       u64 total_cycles,
43562306a36Sopenharmony_ci					       int *block_hpps, int nr_hpps,
43662306a36Sopenharmony_ci					       int *nr_reps)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	struct block_report *block_reports;
43962306a36Sopenharmony_ci	int nr_hists = evlist->core.nr_entries, i = 0;
44062306a36Sopenharmony_ci	struct evsel *pos;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	block_reports = calloc(nr_hists, sizeof(struct block_report));
44362306a36Sopenharmony_ci	if (!block_reports)
44462306a36Sopenharmony_ci		return NULL;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
44762306a36Sopenharmony_ci		struct hists *hists = evsel__hists(pos);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		process_block_report(hists, &block_reports[i], total_cycles,
45062306a36Sopenharmony_ci				     block_hpps, nr_hpps);
45162306a36Sopenharmony_ci		i++;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	*nr_reps = nr_hists;
45562306a36Sopenharmony_ci	return block_reports;
45662306a36Sopenharmony_ci}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_civoid block_info__free_report(struct block_report *reps, int nr_reps)
45962306a36Sopenharmony_ci{
46062306a36Sopenharmony_ci	for (int i = 0; i < nr_reps; i++)
46162306a36Sopenharmony_ci		hists__delete_entries(&reps[i].hist.block_hists);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	free(reps);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ciint report__browse_block_hists(struct block_hist *bh, float min_percent,
46762306a36Sopenharmony_ci			       struct evsel *evsel, struct perf_env *env,
46862306a36Sopenharmony_ci			       struct annotation_options *annotation_opts)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	int ret;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	switch (use_browser) {
47362306a36Sopenharmony_ci	case 0:
47462306a36Sopenharmony_ci		symbol_conf.report_individual_block = true;
47562306a36Sopenharmony_ci		hists__fprintf(&bh->block_hists, true, 0, 0, min_percent,
47662306a36Sopenharmony_ci			       stdout, true);
47762306a36Sopenharmony_ci		return 0;
47862306a36Sopenharmony_ci	case 1:
47962306a36Sopenharmony_ci		symbol_conf.report_individual_block = true;
48062306a36Sopenharmony_ci		ret = block_hists_tui_browse(bh, evsel, min_percent,
48162306a36Sopenharmony_ci					     env, annotation_opts);
48262306a36Sopenharmony_ci		return ret;
48362306a36Sopenharmony_ci	default:
48462306a36Sopenharmony_ci		return -1;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	return 0;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cifloat block_info__total_cycles_percent(struct hist_entry *he)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct block_info *bi = he->block_info;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (bi->total_cycles)
49562306a36Sopenharmony_ci		return bi->cycles * 100.0 / bi->total_cycles;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return 0.0;
49862306a36Sopenharmony_ci}
499