Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf hist: Correct hist_entry->mem_info refcounts

The 'struct mem_info' is created by iter_prepare_mem_entry() at the
beginning and destroyed by iter_finish_mem_entry() at the end.

So if it's used in a new hist_entry, it should be cloned.

Simplify (hopefully) the logic by adding some helper functions and by
not holding the refcount in the temporary entry.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20240731235505.710436-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
96465e01 7c5dd51b

+42 -7
+7 -7
tools/perf/util/hist.c
··· 476 476 he->branch_info->to.ms.map = map__get(he->branch_info->to.ms.map); 477 477 } 478 478 479 + if (he->mem_info) { 480 + he->mem_info = mem_info__clone(template->mem_info); 481 + if (he->mem_info == NULL) 482 + goto err_infos; 483 + } 484 + 479 485 if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) 480 486 callchain_init(he->callchain); 481 487 ··· 626 620 if (symbol_conf.cumulate_callchain) 627 621 he_stat__add_period(he->stat_acc, period); 628 622 629 - /* 630 - * This mem info was allocated from sample__resolve_mem 631 - * and will not be used anymore. 632 - */ 633 - mem_info__zput(entry->mem_info); 634 - 635 623 block_info__delete(entry->block_info); 636 624 637 625 kvm_info__zput(entry->kvm_info); ··· 739 739 .filtered = symbol__parent_filter(sym_parent) | al->filtered, 740 740 .hists = hists, 741 741 .branch_info = bi, 742 - .mem_info = mem_info__get(mi), 742 + .mem_info = mi, 743 743 .kvm_info = ki, 744 744 .block_info = block_info, 745 745 .transaction = sample->transaction,
+18
tools/perf/util/map_symbol.c
··· 13 13 { 14 14 map_symbol__exit(&ams->ms); 15 15 } 16 + 17 + void map_symbol__copy(struct map_symbol *dst, struct map_symbol *src) 18 + { 19 + dst->maps = maps__get(src->maps); 20 + dst->map = map__get(src->map); 21 + dst->sym = src->sym; 22 + } 23 + 24 + void addr_map_symbol__copy(struct addr_map_symbol *dst, struct addr_map_symbol *src) 25 + { 26 + map_symbol__copy(&dst->ms, &src->ms); 27 + 28 + dst->addr = src->addr; 29 + dst->al_addr = src->al_addr; 30 + dst->al_level = src->al_level; 31 + dst->phys_addr = src->phys_addr; 32 + dst->data_page_size = src->data_page_size; 33 + }
+3
tools/perf/util/map_symbol.h
··· 26 26 void map_symbol__exit(struct map_symbol *ms); 27 27 void addr_map_symbol__exit(struct addr_map_symbol *ams); 28 28 29 + void map_symbol__copy(struct map_symbol *dst, struct map_symbol *src); 30 + void addr_map_symbol__copy(struct addr_map_symbol *dst, struct addr_map_symbol *src); 31 + 29 32 #endif // __PERF_MAP_SYMBOL
+13
tools/perf/util/mem-info.c
··· 33 33 34 34 return result; 35 35 } 36 + 37 + struct mem_info *mem_info__clone(struct mem_info *mi) 38 + { 39 + struct mem_info *result = mem_info__new(); 40 + 41 + if (result) { 42 + addr_map_symbol__copy(mem_info__iaddr(result), mem_info__iaddr(mi)); 43 + addr_map_symbol__copy(mem_info__daddr(result), mem_info__daddr(mi)); 44 + mem_info__data_src(result)->val = mem_info__data_src(mi)->val; 45 + } 46 + 47 + return result; 48 + }
+1
tools/perf/util/mem-info.h
··· 15 15 }; 16 16 17 17 struct mem_info *mem_info__new(void); 18 + struct mem_info *mem_info__clone(struct mem_info *mi); 18 19 struct mem_info *mem_info__get(struct mem_info *mi); 19 20 void mem_info__put(struct mem_info *mi); 20 21