perf hist: Add struct he_mem_stat

The 'struct he_mem_stat' is to save detailed information about memory
instruction.  It'll be used to show breakdown of various data from
PERF_SAMPLE_DATA_SRC.  Note that this structure is generic and the
contents will be different depending on actual data it'll use later.

The information about the actual data will be saved in 'struct hists'
and its length is in nr_mem_stats.  This commit just adds ground works
and does nothing since hists->nr_mem_stats is 0 for now.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.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: Leo Yan <leo.yan@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Link: https://lore.kernel.org/r/20250430205548.789750-5-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Namhyung Kim 2025-04-30 13:55:41 -07:00 committed by Arnaldo Carvalho de Melo
parent 29e6392ec3
commit 930d4c45c6
2 changed files with 83 additions and 0 deletions

View File

@ -336,6 +336,67 @@ static void he_stat__decay(struct he_stat *he_stat)
he_stat->latency = (he_stat->latency * 7) / 8;
}
static int hists__update_mem_stat(struct hists *hists, struct hist_entry *he,
struct mem_info *mi, u64 period)
{
if (hists->nr_mem_stats == 0)
return 0;
if (he->mem_stat == NULL) {
he->mem_stat = calloc(hists->nr_mem_stats, sizeof(*he->mem_stat));
if (he->mem_stat == NULL)
return -1;
}
for (int i = 0; i < hists->nr_mem_stats; i++) {
int idx = 0; /* TODO: get correct index from mem info */
(void)mi;
he->mem_stat[i].entries[idx] += period;
}
return 0;
}
static void hists__add_mem_stat(struct hists *hists, struct hist_entry *dst,
struct hist_entry *src)
{
if (hists->nr_mem_stats == 0)
return;
for (int i = 0; i < hists->nr_mem_stats; i++) {
for (int k = 0; k < MEM_STAT_LEN; k++)
dst->mem_stat[i].entries[k] += src->mem_stat[i].entries[k];
}
}
static int hists__clone_mem_stat(struct hists *hists, struct hist_entry *dst,
struct hist_entry *src)
{
if (hists->nr_mem_stats == 0)
return 0;
dst->mem_stat = calloc(hists->nr_mem_stats, sizeof(*dst->mem_stat));
if (dst->mem_stat == NULL)
return -1;
for (int i = 0; i < hists->nr_mem_stats; i++) {
for (int k = 0; k < MEM_STAT_LEN; k++)
dst->mem_stat[i].entries[k] = src->mem_stat[i].entries[k];
}
return 0;
}
static void hists__decay_mem_stat(struct hists *hists, struct hist_entry *he)
{
if (hists->nr_mem_stats == 0)
return;
for (int i = 0; i < hists->nr_mem_stats; i++) {
for (int k = 0; k < MEM_STAT_LEN; k++)
he->mem_stat[i].entries[k] = (he->mem_stat[i].entries[k] * 7) / 8;
}
}
static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@ -350,6 +411,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
if (symbol_conf.cumulate_callchain)
he_stat__decay(he->stat_acc);
decay_callchain(he->callchain);
hists__decay_mem_stat(hists, he);
if (!he->depth) {
u64 period_diff = prev_period - he->stat.period;
@ -693,6 +755,10 @@ static struct hist_entry *hists__findnew_entry(struct hists *hists,
he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
if (symbol_conf.cumulate_callchain)
he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
if (hists__update_mem_stat(hists, he, entry->mem_info, period) < 0) {
hist_entry__delete(he);
return NULL;
}
return he;
}
@ -1423,6 +1489,7 @@ void hist_entry__delete(struct hist_entry *he)
free_callchain(he->callchain);
zfree(&he->trace_output);
zfree(&he->raw_data);
zfree(&he->mem_stat);
ops->free(he);
}
@ -1572,6 +1639,7 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
cmp = hist_entry__collapse_hierarchy(hpp_list, iter, he);
if (!cmp) {
he_stat__add_stat(&iter->stat, &he->stat);
hists__add_mem_stat(hists, iter, he);
return iter;
}
@ -1613,6 +1681,11 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
new->srcfile = NULL;
}
if (hists__clone_mem_stat(hists, new, he) < 0) {
hist_entry__delete(new);
return NULL;
}
rb_link_node(&new->rb_node_in, parent, p);
rb_insert_color_cached(&new->rb_node_in, root, leftmost);
return new;
@ -1695,6 +1768,7 @@ static int hists__collapse_insert_entry(struct hists *hists,
he_stat__add_stat(&iter->stat, &he->stat);
if (symbol_conf.cumulate_callchain)
he_stat__add_stat(iter->stat_acc, he->stat_acc);
hists__add_mem_stat(hists, iter, he);
if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) {
struct callchain_cursor *cursor = get_tls_callchain_cursor();

View File

@ -100,6 +100,13 @@ enum hist_column {
struct thread;
struct dso;
#define MEM_STAT_LEN 8
struct he_mem_stat {
/* meaning of entries depends on enum mem_stat_type */
u64 entries[MEM_STAT_LEN];
};
struct hists {
struct rb_root_cached entries_in_array[2];
struct rb_root_cached *entries_in;
@ -125,6 +132,7 @@ struct hists {
struct perf_hpp_list *hpp_list;
struct list_head hpp_formats;
int nr_hpp_node;
int nr_mem_stats;
};
#define hists__has(__h, __f) (__h)->hpp_list->__f
@ -232,6 +240,7 @@ struct hist_entry {
} pairs;
struct he_stat stat;
struct he_stat *stat_acc;
struct he_mem_stat *mem_stat;
struct map_symbol ms;
struct thread *thread;
struct comm *comm;