perf annotate: Split branch stack cycles info from 'struct annotation'
[ Upstream commit b7f87e32590bf48eca84f729d3422be7b8dc22d3 ] The cycles info is only meaningful when sample has branch stacks. To save the memory for normal cases, move those fields to a new 'struct annotated_branch' and dynamically allocate it when needed. Also move cycles_hist from annotated_source as it's related here. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Christophe JAILLET <christophe.jaillet@wanadoo.fr> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://lore.kernel.org/r/20231103191907.54531-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Stable-dep-of: 3ef44458071a ("perf report: Fix --total-cycles --stdio output error") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
ba18185bea
commit
4ef032d899
|
@ -813,7 +813,6 @@ static __maybe_unused void annotated_source__delete(struct annotated_source *src
|
|||
if (src == NULL)
|
||||
return;
|
||||
zfree(&src->histograms);
|
||||
zfree(&src->cycles_hist);
|
||||
free(src);
|
||||
}
|
||||
|
||||
|
@ -848,18 +847,6 @@ static int annotated_source__alloc_histograms(struct annotated_source *src,
|
|||
return src->histograms ? 0 : -1;
|
||||
}
|
||||
|
||||
/* The cycles histogram is lazily allocated. */
|
||||
static int symbol__alloc_hist_cycles(struct symbol *sym)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
const size_t size = symbol__size(sym);
|
||||
|
||||
notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
|
||||
if (notes->src->cycles_hist == NULL)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void symbol__annotate_zero_histograms(struct symbol *sym)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
|
@ -868,9 +855,10 @@ void symbol__annotate_zero_histograms(struct symbol *sym)
|
|||
if (notes->src != NULL) {
|
||||
memset(notes->src->histograms, 0,
|
||||
notes->src->nr_histograms * notes->src->sizeof_sym_hist);
|
||||
if (notes->src->cycles_hist)
|
||||
memset(notes->src->cycles_hist, 0,
|
||||
symbol__size(sym) * sizeof(struct cyc_hist));
|
||||
}
|
||||
if (notes->branch && notes->branch->cycles_hist) {
|
||||
memset(notes->branch->cycles_hist, 0,
|
||||
symbol__size(sym) * sizeof(struct cyc_hist));
|
||||
}
|
||||
annotation__unlock(notes);
|
||||
}
|
||||
|
@ -961,23 +949,33 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct annotated_branch *annotation__get_branch(struct annotation *notes)
|
||||
{
|
||||
if (notes == NULL)
|
||||
return NULL;
|
||||
|
||||
if (notes->branch == NULL)
|
||||
notes->branch = zalloc(sizeof(*notes->branch));
|
||||
|
||||
return notes->branch;
|
||||
}
|
||||
|
||||
static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
|
||||
{
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
struct annotated_branch *branch;
|
||||
|
||||
if (notes->src == NULL) {
|
||||
notes->src = annotated_source__new();
|
||||
if (notes->src == NULL)
|
||||
return NULL;
|
||||
goto alloc_cycles_hist;
|
||||
branch = annotation__get_branch(notes);
|
||||
if (branch == NULL)
|
||||
return NULL;
|
||||
|
||||
if (branch->cycles_hist == NULL) {
|
||||
const size_t size = symbol__size(sym);
|
||||
|
||||
branch->cycles_hist = calloc(size, sizeof(struct cyc_hist));
|
||||
}
|
||||
|
||||
if (!notes->src->cycles_hist) {
|
||||
alloc_cycles_hist:
|
||||
symbol__alloc_hist_cycles(sym);
|
||||
}
|
||||
|
||||
return notes->src->cycles_hist;
|
||||
return branch->cycles_hist;
|
||||
}
|
||||
|
||||
struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
|
||||
|
@ -1086,6 +1084,14 @@ static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64
|
|||
return n_insn;
|
||||
}
|
||||
|
||||
static void annotated_branch__delete(struct annotated_branch *branch)
|
||||
{
|
||||
if (branch) {
|
||||
zfree(&branch->cycles_hist);
|
||||
free(branch);
|
||||
}
|
||||
}
|
||||
|
||||
static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
|
||||
{
|
||||
unsigned n_insn;
|
||||
|
@ -1094,6 +1100,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64
|
|||
|
||||
n_insn = annotation__count_insn(notes, start, end);
|
||||
if (n_insn && ch->num && ch->cycles) {
|
||||
struct annotated_branch *branch;
|
||||
float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
|
||||
|
||||
/* Hide data when there are too many overlaps. */
|
||||
|
@ -1109,10 +1116,11 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64
|
|||
}
|
||||
}
|
||||
|
||||
if (cover_insn) {
|
||||
notes->hit_cycles += ch->cycles;
|
||||
notes->hit_insn += n_insn * ch->num;
|
||||
notes->cover_insn += cover_insn;
|
||||
branch = annotation__get_branch(notes);
|
||||
if (cover_insn && branch) {
|
||||
branch->hit_cycles += ch->cycles;
|
||||
branch->hit_insn += n_insn * ch->num;
|
||||
branch->cover_insn += cover_insn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1122,19 +1130,19 @@ static int annotation__compute_ipc(struct annotation *notes, size_t size)
|
|||
int err = 0;
|
||||
s64 offset;
|
||||
|
||||
if (!notes->src || !notes->src->cycles_hist)
|
||||
if (!notes->branch || !notes->branch->cycles_hist)
|
||||
return 0;
|
||||
|
||||
notes->total_insn = annotation__count_insn(notes, 0, size - 1);
|
||||
notes->hit_cycles = 0;
|
||||
notes->hit_insn = 0;
|
||||
notes->cover_insn = 0;
|
||||
notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1);
|
||||
notes->branch->hit_cycles = 0;
|
||||
notes->branch->hit_insn = 0;
|
||||
notes->branch->cover_insn = 0;
|
||||
|
||||
annotation__lock(notes);
|
||||
for (offset = size - 1; offset >= 0; --offset) {
|
||||
struct cyc_hist *ch;
|
||||
|
||||
ch = ¬es->src->cycles_hist[offset];
|
||||
ch = ¬es->branch->cycles_hist[offset];
|
||||
if (ch && ch->cycles) {
|
||||
struct annotation_line *al;
|
||||
|
||||
|
@ -1153,13 +1161,12 @@ static int annotation__compute_ipc(struct annotation *notes, size_t size)
|
|||
al->cycles->max = ch->cycles_max;
|
||||
al->cycles->min = ch->cycles_min;
|
||||
}
|
||||
notes->have_cycles = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
while (++offset < (s64)size) {
|
||||
struct cyc_hist *ch = ¬es->src->cycles_hist[offset];
|
||||
struct cyc_hist *ch = ¬es->branch->cycles_hist[offset];
|
||||
|
||||
if (ch && ch->cycles) {
|
||||
struct annotation_line *al = notes->offsets[offset];
|
||||
|
@ -1325,6 +1332,7 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r
|
|||
void annotation__exit(struct annotation *notes)
|
||||
{
|
||||
annotated_source__delete(notes->src);
|
||||
annotated_branch__delete(notes->branch);
|
||||
}
|
||||
|
||||
static struct sharded_mutex *sharded_mutex;
|
||||
|
@ -3074,13 +3082,14 @@ call_like:
|
|||
static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
|
||||
{
|
||||
double ipc = 0.0, coverage = 0.0;
|
||||
struct annotated_branch *branch = annotation__get_branch(notes);
|
||||
|
||||
if (notes->hit_cycles)
|
||||
ipc = notes->hit_insn / ((double)notes->hit_cycles);
|
||||
if (branch && branch->hit_cycles)
|
||||
ipc = branch->hit_insn / ((double)branch->hit_cycles);
|
||||
|
||||
if (notes->total_insn) {
|
||||
coverage = notes->cover_insn * 100.0 /
|
||||
((double)notes->total_insn);
|
||||
if (branch && branch->total_insn) {
|
||||
coverage = branch->cover_insn * 100.0 /
|
||||
((double)branch->total_insn);
|
||||
}
|
||||
|
||||
scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
|
||||
|
@ -3105,7 +3114,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
|||
int printed;
|
||||
|
||||
if (first_line && (al->offset == -1 || percent_max == 0.0)) {
|
||||
if (notes->have_cycles && al->cycles) {
|
||||
if (notes->branch && al->cycles) {
|
||||
if (al->cycles->ipc == 0.0 && al->cycles->avg == 0)
|
||||
show_title = true;
|
||||
} else
|
||||
|
@ -3142,7 +3151,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
|
|||
}
|
||||
}
|
||||
|
||||
if (notes->have_cycles) {
|
||||
if (notes->branch) {
|
||||
if (al->cycles && al->cycles->ipc)
|
||||
obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc);
|
||||
else if (!show_title)
|
||||
|
|
|
@ -272,17 +272,20 @@ struct annotated_source {
|
|||
struct list_head source;
|
||||
int nr_histograms;
|
||||
size_t sizeof_sym_hist;
|
||||
struct cyc_hist *cycles_hist;
|
||||
struct sym_hist *histograms;
|
||||
};
|
||||
|
||||
struct annotated_branch {
|
||||
u64 hit_cycles;
|
||||
u64 hit_insn;
|
||||
unsigned int total_insn;
|
||||
unsigned int cover_insn;
|
||||
struct cyc_hist *cycles_hist;
|
||||
};
|
||||
|
||||
struct LOCKABLE annotation {
|
||||
u64 max_coverage;
|
||||
u64 start;
|
||||
u64 hit_cycles;
|
||||
u64 hit_insn;
|
||||
unsigned int total_insn;
|
||||
unsigned int cover_insn;
|
||||
struct annotation_options *options;
|
||||
struct annotation_line **offsets;
|
||||
int nr_events;
|
||||
|
@ -298,8 +301,8 @@ struct LOCKABLE annotation {
|
|||
u8 max_addr;
|
||||
u8 max_ins_name;
|
||||
} widths;
|
||||
bool have_cycles;
|
||||
struct annotated_source *src;
|
||||
struct annotated_branch *branch;
|
||||
};
|
||||
|
||||
static inline void annotation__init(struct annotation *notes __maybe_unused)
|
||||
|
@ -313,10 +316,10 @@ bool annotation__trylock(struct annotation *notes) EXCLUSIVE_TRYLOCK_FUNCTION(tr
|
|||
|
||||
static inline int annotation__cycles_width(struct annotation *notes)
|
||||
{
|
||||
if (notes->have_cycles && notes->options->show_minmax_cycle)
|
||||
if (notes->branch && notes->options->show_minmax_cycle)
|
||||
return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;
|
||||
|
||||
return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
|
||||
return notes->branch ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
|
||||
}
|
||||
|
||||
static inline int annotation__pcnt_width(struct annotation *notes)
|
||||
|
|
|
@ -129,9 +129,9 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh,
|
|||
al.sym = he->ms.sym;
|
||||
|
||||
notes = symbol__annotation(he->ms.sym);
|
||||
if (!notes || !notes->src || !notes->src->cycles_hist)
|
||||
if (!notes || !notes->branch || !notes->branch->cycles_hist)
|
||||
return 0;
|
||||
ch = notes->src->cycles_hist;
|
||||
ch = notes->branch->cycles_hist;
|
||||
for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
|
||||
if (ch[i].num_aggr) {
|
||||
struct block_info *bi;
|
||||
|
|
|
@ -583,21 +583,21 @@ static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf,
|
|||
{
|
||||
|
||||
struct symbol *sym = he->ms.sym;
|
||||
struct annotation *notes;
|
||||
struct annotated_branch *branch;
|
||||
double ipc = 0.0, coverage = 0.0;
|
||||
char tmp[64];
|
||||
|
||||
if (!sym)
|
||||
return repsep_snprintf(bf, size, "%-*s", width, "-");
|
||||
|
||||
notes = symbol__annotation(sym);
|
||||
branch = symbol__annotation(sym)->branch;
|
||||
|
||||
if (notes->hit_cycles)
|
||||
ipc = notes->hit_insn / ((double)notes->hit_cycles);
|
||||
if (branch && branch->hit_cycles)
|
||||
ipc = branch->hit_insn / ((double)branch->hit_cycles);
|
||||
|
||||
if (notes->total_insn) {
|
||||
coverage = notes->cover_insn * 100.0 /
|
||||
((double)notes->total_insn);
|
||||
if (branch && branch->total_insn) {
|
||||
coverage = branch->cover_insn * 100.0 /
|
||||
((double)branch->total_insn);
|
||||
}
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
|
||||
|
|
Loading…
Reference in New Issue