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