All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jin, Yao" <yao.jin@linux.intel.com>
To: Arnaldo Carvalho de Melo <arnaldo.melo@gmail.com>
Cc: jolsa@kernel.org, peterz@infradead.org, mingo@redhat.com,
	alexander.shishkin@linux.intel.com, Linux-kernel@vger.kernel.org,
	ak@linux.intel.com, kan.liang@intel.com, yao.jin@intel.com
Subject: Re: [PATCH v7 4/7] perf util: Support block formats with compare/sort/display
Date: Thu, 7 Nov 2019 21:05:21 +0800	[thread overview]
Message-ID: <37278655-c021-113b-4dcb-80af4ab638d7@linux.intel.com> (raw)
In-Reply-To: <20191107124538.GC11372@kernel.org>



On 11/7/2019 8:45 PM, Arnaldo Carvalho de Melo wrote:
> Em Thu, Nov 07, 2019 at 03:47:16PM +0800, Jin Yao escreveu:
>> This patch provides helper routines to support new
>> columns for block info output.
> 
> This breaks bisection, some of my build containers complained about:
> 
> util/block-info.c:395:20: error: unused function 'set_fmt' [-Werror,-Wunused-function]
> static inline void set_fmt(struct block_fmt *block_fmt,
>                     ^
> 1 error generated.
> mv: can't rename '/tmp/build/perf/util/.block-info.o.tmp': No such file or directory
> 
> 
> Because you add a static inline function to a .c file and don't use it,
> I'll try moving it to when it finally gets used.
>   

Oh, very sorry, my fault. I should delete the set_fmt(). In new version, 
it's not used. But unfortunately my build machine didn't report the 
error. :(

Thanks
Jin Yao

>> The new columns are:
>>
>> Sampled Cycles%
>> Sampled Cycles
>> Avg Cycles%
>> Avg Cycles
>> [Program Block Range]
>> Shared Object
>>
>>   v5:
>>   ---
>>   1. Move more block related functions from builtin-report.c to
>>      block-info.c
>>
>>   2. Set ms (map+sym) in block hist_entry. Because this info
>>      is needed for reporting the block range (i.e. source line)
>>
>> Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
>> ---
>>   tools/perf/util/block-info.c | 317 +++++++++++++++++++++++++++++++++++
>>   tools/perf/util/block-info.h |  33 +++-
>>   tools/perf/util/hist.c       |   4 +
>>   3 files changed, 352 insertions(+), 2 deletions(-)
>>
>> diff --git a/tools/perf/util/block-info.c b/tools/perf/util/block-info.c
>> index b9954a32b8f4..1242c3a33509 100644
>> --- a/tools/perf/util/block-info.c
>> +++ b/tools/perf/util/block-info.c
>> @@ -6,6 +6,40 @@
>>   #include "sort.h"
>>   #include "annotate.h"
>>   #include "symbol.h"
>> +#include "dso.h"
>> +#include "map.h"
>> +#include "srcline.h"
>> +#include "evlist.h"
>> +
>> +static struct block_header_column{
>> +	const char *name;
>> +	int width;
>> +} block_columns[PERF_HPP_REPORT__BLOCK_MAX_INDEX] = {
>> +	[PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT] = {
>> +		.name = "Sampled Cycles%",
>> +		.width = 15,
>> +	},
>> +	[PERF_HPP_REPORT__BLOCK_LBR_CYCLES] = {
>> +		.name = "Sampled Cycles",
>> +		.width = 14,
>> +	},
>> +	[PERF_HPP_REPORT__BLOCK_CYCLES_PCT] = {
>> +		.name = "Avg Cycles%",
>> +		.width = 11,
>> +	},
>> +	[PERF_HPP_REPORT__BLOCK_AVG_CYCLES] = {
>> +		.name = "Avg Cycles",
>> +		.width = 10,
>> +	},
>> +	[PERF_HPP_REPORT__BLOCK_RANGE] = {
>> +		.name = "[Program Block Range]",
>> +		.width = 70,
>> +	},
>> +	[PERF_HPP_REPORT__BLOCK_DSO] = {
>> +		.name = "Shared Object",
>> +		.width = 20,
>> +	}
>> +};
>>   
>>   struct block_info *block_info__get(struct block_info *bi)
>>   {
>> @@ -127,3 +161,286 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
>>   
>>   	return 0;
>>   }
>> +
>> +static int 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)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
>> +			 block_fmt->header);
>> +}
>> +
>> +static int block_column_width(struct perf_hpp_fmt *fmt,
>> +			      struct perf_hpp *hpp __maybe_unused,
>> +			      struct hists *hists __maybe_unused)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +
>> +	return block_fmt->width;
>> +}
>> +
>> +static int block_total_cycles_pct_entry(struct perf_hpp_fmt *fmt,
>> +					struct perf_hpp *hpp,
>> +					struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi = he->block_info;
>> +	double ratio = 0.0;
>> +	char buf[16];
>> +
>> +	if (block_fmt->total_cycles)
>> +		ratio = (double)bi->cycles / (double)block_fmt->total_cycles;
>> +
>> +	sprintf(buf, "%.2f%%", 100.0 * ratio);
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
>> +}
>> +
>> +static int64_t block_total_cycles_pct_sort(struct perf_hpp_fmt *fmt,
>> +					   struct hist_entry *left,
>> +					   struct hist_entry *right)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi_l = left->block_info;
>> +	struct block_info *bi_r = right->block_info;
>> +	double l, r;
>> +
>> +	if (block_fmt->total_cycles) {
>> +		l = ((double)bi_l->cycles /
>> +			(double)block_fmt->total_cycles) * 100000.0;
>> +		r = ((double)bi_r->cycles /
>> +			(double)block_fmt->total_cycles) * 100000.0;
>> +		return (int64_t)l - (int64_t)r;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void cycles_string(u64 cycles, char *buf, int size)
>> +{
>> +	if (cycles >= 1000000)
>> +		scnprintf(buf, size, "%.1fM", (double)cycles / 1000000.0);
>> +	else if (cycles >= 1000)
>> +		scnprintf(buf, size, "%.1fK", (double)cycles / 1000.0);
>> +	else
>> +		scnprintf(buf, size, "%1d", cycles);
>> +}
>> +
>> +static int block_cycles_lbr_entry(struct perf_hpp_fmt *fmt,
>> +				  struct perf_hpp *hpp, struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi = he->block_info;
>> +	char cycles_buf[16];
>> +
>> +	cycles_string(bi->cycles_aggr, cycles_buf, sizeof(cycles_buf));
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
>> +			 cycles_buf);
>> +}
>> +
>> +static int block_cycles_pct_entry(struct perf_hpp_fmt *fmt,
>> +				  struct perf_hpp *hpp, struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi = he->block_info;
>> +	double ratio = 0.0;
>> +	u64 avg;
>> +	char buf[16];
>> +
>> +	if (block_fmt->block_cycles && bi->num_aggr) {
>> +		avg = bi->cycles_aggr / bi->num_aggr;
>> +		ratio = (double)avg / (double)block_fmt->block_cycles;
>> +	}
>> +
>> +	sprintf(buf, "%.2f%%", 100.0 * ratio);
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
>> +}
>> +
>> +static int block_avg_cycles_entry(struct perf_hpp_fmt *fmt,
>> +				  struct perf_hpp *hpp,
>> +				  struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi = he->block_info;
>> +	char cycles_buf[16];
>> +
>> +	cycles_string(bi->cycles_aggr / bi->num_aggr, cycles_buf,
>> +		      sizeof(cycles_buf));
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
>> +			 cycles_buf);
>> +}
>> +
>> +static int block_range_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
>> +			     struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct block_info *bi = he->block_info;
>> +	char buf[128];
>> +	char *start_line, *end_line;
>> +
>> +	symbol_conf.disable_add2line_warn = true;
>> +
>> +	start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
>> +				  he->ms.sym);
>> +
>> +	end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
>> +				he->ms.sym);
>> +
>> +	if ((start_line != SRCLINE_UNKNOWN) && (end_line != SRCLINE_UNKNOWN)) {
>> +		scnprintf(buf, sizeof(buf), "[%s -> %s]",
>> +			  start_line, end_line);
>> +	} else {
>> +		scnprintf(buf, sizeof(buf), "[%7lx -> %7lx]",
>> +			  bi->start, bi->end);
>> +	}
>> +
>> +	free_srcline(start_line);
>> +	free_srcline(end_line);
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width, buf);
>> +}
>> +
>> +static int block_dso_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
>> +			   struct hist_entry *he)
>> +{
>> +	struct block_fmt *block_fmt = container_of(fmt, struct block_fmt, fmt);
>> +	struct map *map = he->ms.map;
>> +
>> +	if (map && map->dso) {
>> +		return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
>> +				 map->dso->short_name);
>> +	}
>> +
>> +	return scnprintf(hpp->buf, hpp->size, "%*s", block_fmt->width,
>> +			 "[unknown]");
>> +}
>> +
>> +static void init_block_header(struct block_fmt *block_fmt)
>> +{
>> +	struct perf_hpp_fmt *fmt = &block_fmt->fmt;
>> +
>> +	BUG_ON(block_fmt->idx >= PERF_HPP_REPORT__BLOCK_MAX_INDEX);
>> +
>> +	block_fmt->header = block_columns[block_fmt->idx].name;
>> +	block_fmt->width = block_columns[block_fmt->idx].width;
>> +
>> +	fmt->header = block_column_header;
>> +	fmt->width = block_column_width;
>> +}
>> +
>> +static void hpp_register(struct block_fmt *block_fmt, int idx,
>> +			 struct perf_hpp_list *hpp_list)
>> +{
>> +	struct perf_hpp_fmt *fmt = &block_fmt->fmt;
>> +
>> +	block_fmt->idx = idx;
>> +	INIT_LIST_HEAD(&fmt->list);
>> +	INIT_LIST_HEAD(&fmt->sort_list);
>> +
>> +	switch (idx) {
>> +	case PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT:
>> +		fmt->entry = block_total_cycles_pct_entry;
>> +		fmt->cmp = block_info__cmp;
>> +		fmt->sort = block_total_cycles_pct_sort;
>> +		break;
>> +	case PERF_HPP_REPORT__BLOCK_LBR_CYCLES:
>> +		fmt->entry = block_cycles_lbr_entry;
>> +		break;
>> +	case PERF_HPP_REPORT__BLOCK_CYCLES_PCT:
>> +		fmt->entry = block_cycles_pct_entry;
>> +		break;
>> +	case PERF_HPP_REPORT__BLOCK_AVG_CYCLES:
>> +		fmt->entry = block_avg_cycles_entry;
>> +		break;
>> +	case PERF_HPP_REPORT__BLOCK_RANGE:
>> +		fmt->entry = block_range_entry;
>> +		break;
>> +	case PERF_HPP_REPORT__BLOCK_DSO:
>> +		fmt->entry = block_dso_entry;
>> +		break;
>> +	default:
>> +		return;
>> +	}
>> +
>> +	init_block_header(block_fmt);
>> +	perf_hpp_list__column_register(hpp_list, fmt);
>> +}
>> +
>> +static void register_block_columns(struct perf_hpp_list *hpp_list,
>> +				   struct block_fmt *block_fmts)
>> +{
>> +	for (int i = 0; i < PERF_HPP_REPORT__BLOCK_MAX_INDEX; i++)
>> +		hpp_register(&block_fmts[i], i, hpp_list);
>> +}
>> +
>> +static void init_block_hist(struct block_hist *bh, struct block_fmt *block_fmts)
>> +{
>> +	__hists__init(&bh->block_hists, &bh->block_list);
>> +	perf_hpp_list__init(&bh->block_list);
>> +	bh->block_list.nr_header_lines = 1;
>> +
>> +	register_block_columns(&bh->block_list, block_fmts);
>> +
>> +	perf_hpp_list__register_sort_field(&bh->block_list,
>> +		&block_fmts[PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT].fmt);
>> +}
>> +
>> +static inline void set_fmt(struct block_fmt *block_fmt,
>> +			   u64 total_cycles, u64 block_cycles)
>> +{
>> +	block_fmt->total_cycles = total_cycles;
>> +	block_fmt->block_cycles = block_cycles;
>> +}
>> +
>> +static void process_block_report(struct hists *hists,
>> +				 struct block_report *block_report,
>> +				 u64 total_cycles)
>> +{
>> +	struct rb_node *next = rb_first_cached(&hists->entries);
>> +	struct block_hist *bh = &block_report->hist;
>> +	struct hist_entry *he;
>> +
>> +	init_block_hist(bh, block_report->fmts);
>> +
>> +	while (next) {
>> +		he = rb_entry(next, struct hist_entry, rb_node);
>> +		block_info__process_sym(he, bh, &block_report->cycles,
>> +					total_cycles);
>> +		next = rb_next(&he->rb_node);
>> +	}
>> +
>> +	for (int i = 0; i < PERF_HPP_REPORT__BLOCK_MAX_INDEX; i++) {
>> +		block_report->fmts[i].total_cycles = total_cycles;
>> +		block_report->fmts[i].block_cycles = block_report->cycles;
>> +	}
>> +
>> +	hists__output_resort(&bh->block_hists, NULL);
>> +}
>> +
>> +struct block_report *block_info__create_report(struct evlist *evlist,
>> +					       u64 total_cycles)
>> +{
>> +	struct block_report *block_reports;
>> +	int nr_hists = evlist->core.nr_entries, i = 0;
>> +	struct evsel *pos;
>> +
>> +	block_reports = calloc(nr_hists, sizeof(struct block_report));
>> +	if (!block_reports)
>> +		return NULL;
>> +
>> +	evlist__for_each_entry(evlist, pos) {
>> +		struct hists *hists = evsel__hists(pos);
>> +
>> +		process_block_report(hists, &block_reports[i], total_cycles);
>> +		i++;
>> +	}
>> +
>> +	return block_reports;
>> +}
>> diff --git a/tools/perf/util/block-info.h b/tools/perf/util/block-info.h
>> index d55dfc2fda6f..b5266588d476 100644
>> --- a/tools/perf/util/block-info.h
>> +++ b/tools/perf/util/block-info.h
>> @@ -4,8 +4,9 @@
>>   
>>   #include <linux/types.h>
>>   #include <linux/refcount.h>
>> -#include "util/hist.h"
>> -#include "util/symbol.h"
>> +#include "hist.h"
>> +#include "symbol.h"
>> +#include "sort.h"
>>   
>>   struct block_info {
>>   	struct symbol		*sym;
>> @@ -20,6 +21,31 @@ struct block_info {
>>   	refcount_t		refcnt;
>>   };
>>   
>> +struct block_fmt {
>> +	struct perf_hpp_fmt	fmt;
>> +	int			idx;
>> +	int			width;
>> +	const char		*header;
>> +	u64			total_cycles;
>> +	u64			block_cycles;
>> +};
>> +
>> +enum {
>> +	PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT,
>> +	PERF_HPP_REPORT__BLOCK_LBR_CYCLES,
>> +	PERF_HPP_REPORT__BLOCK_CYCLES_PCT,
>> +	PERF_HPP_REPORT__BLOCK_AVG_CYCLES,
>> +	PERF_HPP_REPORT__BLOCK_RANGE,
>> +	PERF_HPP_REPORT__BLOCK_DSO,
>> +	PERF_HPP_REPORT__BLOCK_MAX_INDEX
>> +};
>> +
>> +struct block_report {
>> +	struct block_hist	hist;
>> +	u64			cycles;
>> +	struct block_fmt	fmts[PERF_HPP_REPORT__BLOCK_MAX_INDEX];
>> +};
>> +
>>   struct block_hist;
>>   
>>   struct block_info *block_info__new(void);
>> @@ -40,4 +66,7 @@ int64_t block_info__cmp(struct perf_hpp_fmt *fmt __maybe_unused,
>>   int block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
>>   			    u64 *block_cycles_aggr, u64 total_cycles);
>>   
>> +struct block_report *block_info__create_report(struct evlist *evlist,
>> +					       u64 total_cycles);
>> +
>>   #endif /* __PERF_BLOCK_H */
>> diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
>> index 0e27d6830011..7cf137b0451b 100644
>> --- a/tools/perf/util/hist.c
>> +++ b/tools/perf/util/hist.c
>> @@ -758,6 +758,10 @@ struct hist_entry *hists__add_entry_block(struct hists *hists,
>>   	struct hist_entry entry = {
>>   		.block_info = block_info,
>>   		.hists = hists,
>> +		.ms = {
>> +			.map = al->map,
>> +			.sym = al->sym,
>> +		},
>>   	}, *he = hists__findnew_entry(hists, &entry, al, false);
>>   
>>   	return he;
>> -- 
>> 2.17.1
> 

  reply	other threads:[~2019-11-07 13:05 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-07  7:47 [PATCH v7 0/7] perf report: Support sorting all blocks by cycles Jin Yao
2019-11-07  7:47 ` [PATCH v7 1/7] perf diff: Don't use hack to skip column length calculation Jin Yao
2019-11-12 11:17   ` [tip: perf/core] " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 2/7] perf util: Cleanup and refactor block info functions Jin Yao
2019-11-12 11:17   ` [tip: perf/core] perf block: " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 3/7] perf util: Count the total cycles of all samples Jin Yao
2019-11-12 11:17   ` [tip: perf/core] perf hist: " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 4/7] perf util: Support block formats with compare/sort/display Jin Yao
2019-11-07 12:45   ` Arnaldo Carvalho de Melo
2019-11-07 13:05     ` Jin, Yao [this message]
2019-11-07 13:17       ` Arnaldo Carvalho de Melo
2019-11-07 13:21         ` Jin, Yao
2019-11-12 11:17   ` [tip: perf/core] perf hist: " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 5/7] perf report: Sort by sampled cycles percent per block for stdio Jin Yao
2019-11-12 11:17   ` [tip: perf/core] " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 6/7] perf report: Support --percent-limit for --total-cycles Jin Yao
2019-11-12 11:17   ` [tip: perf/core] " tip-bot2 for Jin Yao
2019-11-07  7:47 ` [PATCH v7 7/7] perf report: Sort by sampled cycles percent per block for tui Jin Yao
2019-11-07 12:38   ` Arnaldo Carvalho de Melo
2019-11-12 11:17   ` [tip: perf/core] " tip-bot2 for Jin Yao
2019-11-07  9:28 ` [PATCH v7 0/7] perf report: Support sorting all blocks by cycles Jiri Olsa
2019-11-07 13:09   ` Jin, Yao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=37278655-c021-113b-4dcb-80af4ab638d7@linux.intel.com \
    --to=yao.jin@linux.intel.com \
    --cc=Linux-kernel@vger.kernel.org \
    --cc=ak@linux.intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=arnaldo.melo@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kan.liang@intel.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=yao.jin@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.