brintos

brintos / linux-shallow public Read only

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