perf tools: Show memory region in perf-script subcommand

Show the memory region in perf-script subcommand. Memory region is found
in the mem_region field of the memory information data source. This
field was included with the introduction of support for the Off-module
Response facility (OMR) [1] in Intel's Diamond Rapids and Nova Lake
Architectures.

An example of perf-script output with the new memory region field is shown
below:

      thread 5/0 ...	|OP LOAD|LVL L3 hit|SNP HitM|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Local-shared-cache              ffffffff9f002aba
      thread 2/0 ...	|OP LOAD|LVL L3 hit|SNP None|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Local-shared-cache              ffffffff9dc54c95
      thread 8/0 ...	|OP LOAD|LVL L3 hit|SNP HitM|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Other-non-shared-cache          ffffffff9dc54db3
      thread 0/0 ...	|OP LOAD|LVL LFB/MAB hit|SNP None|TLB L1 or L2 hit|LCK No|BLK  Addr|Region N/A                       ffffffff9dc54db3
      thread 2/0 ...	|OP LOAD|LVL L0 hit|SNP None|TLB L1 or L2 hit|LCK Yes|BLK  N/A|Region N/A                            ffffffff9f002a8c
      thread 0/0 ...	|OP LOAD|LVL L3 hit|SNP HitM or Fwd|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Local-non-shared-cache   ffffffff9f002aba
      thread 0/0 ...	|OP LOAD|LVL L3 hit|SNP None|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Local-shared-cache          ffffffff9dc54ca7
     thread 30/0 ...	|OP LOAD|LVL LFB/MAB hit|SNP None|TLB L1 or L2 hit|LCK Yes|BLK  N/A|Region N/A                       ffffffff9dcc1ff2
     thread 30/0 ...	|OP LOAD|LVL RAM hit|SNP None|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Mem-0                          ffffffff9dc54c95
     thread 19/0 ...	|OP LOAD|LVL LFB/MAB hit|SNP None|TLB L1 or L2 hit|LCK No|BLK  N/A|Region N/A                        ffffffff9f002cbb
     thread 19/0 ...	|OP LOAD|LVL L3 hit|SNP HitM or Fwd|TLB L1 or L2 hit|LCK No|BLK  N/A|Region Local-non-shared-cache   ffffffff9f002aba

[1]: https://lore.kernel.org/all/20260114011750.350569-1-dapeng1.mi@linux.intel.com/

Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Assisted-by: GitHub-Copilot:claude-opus-4-8
Assisted-by: Sashiko:gemini-3.1-pro-preview
Co-developed-by: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Dapeng Mi 2026-09-23 12:09:02 -05:00 committed by Arnaldo Carvalho de Melo
parent 41544ef9c9
commit 8eca6fa643
4 changed files with 100 additions and 10 deletions

View File

@ -2153,11 +2153,12 @@ static int evlist__max_name_len(struct evlist *evlist)
return max;
}
static int data_src__fprintf(u64 data_src, FILE *fp)
static int data_src__fprintf(struct perf_session *session,
u64 data_src, FILE *fp)
{
struct mem_info *mi = mem_info__new();
char decode[100];
char out[100];
char decode[200];
char out[200];
static int maxlen;
int len;
@ -2165,10 +2166,10 @@ static int data_src__fprintf(u64 data_src, FILE *fp)
return -ENOMEM;
mem_info__data_src(mi)->val = data_src;
perf_script__meminfo_scnprintf(decode, 100, mi);
perf_script__meminfo_scnprintf(decode, 200, mi, session);
mem_info__put(mi);
len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode);
len = scnprintf(out, 200, "%16" PRIx64 " %s", data_src, decode);
if (maxlen < len)
maxlen = len;
@ -2562,7 +2563,7 @@ static void process_event(struct perf_script *script,
perf_sample__fprintf_addr(sample, thread, evsel, fp);
if (PRINT_FIELD(DATA_SRC))
data_src__fprintf(sample->data_src, fp);
data_src__fprintf(evsel__session(evsel), sample->data_src, fp);
if (PRINT_FIELD(WEIGHT))
fprintf(fp, "%16" PRIu64, sample->weight);

View File

@ -17,6 +17,7 @@
#include "symbol.h"
#include "pmu.h"
#include "pmus.h"
#include "session.h"
unsigned int perf_mem_events__loads_ldlat = 30;
@ -604,8 +605,77 @@ int perf_mem__blk_scnprintf(char *out, size_t sz, const struct mem_info *mem_inf
return l;
}
int perf_script__meminfo_scnprintf(char *out, size_t sz, const struct mem_info *mem_info)
static int perf_mem__region_scnprintf(char *out, size_t sz, const struct mem_info *mem_info)
{
size_t l = 0;
u64 mem = PERF_MEM_REGION_NA;
sz -= 1; /* -1 for null termination */
out[0] = '\0';
if (mem_info)
mem = mem_info__const_data_src(mem_info)->mem_region;
switch (mem) {
case PERF_MEM_REGION_NA:
case PERF_MEM_REGION_RSVD:
l += scnprintf(out + l, sz - l, "N/A");
break;
case PERF_MEM_REGION_L_SHARE:
l += scnprintf(out + l, sz - l, "Local-shared-cache");
break;
case PERF_MEM_REGION_L_NON_SHARE:
l += scnprintf(out + l, sz - l, "Local-non-shared-cache");
break;
case PERF_MEM_REGION_O_IO:
l += scnprintf(out + l, sz - l, "Other-IO");
break;
case PERF_MEM_REGION_O_SHARE:
l += scnprintf(out + l, sz - l, "Other-shared-cache");
break;
case PERF_MEM_REGION_O_NON_SHARE:
l += scnprintf(out + l, sz - l, "Other-non-shared-cache");
break;
case PERF_MEM_REGION_MMIO:
l += scnprintf(out + l, sz - l, "MMIO");
break;
case PERF_MEM_REGION_MEM0:
l += scnprintf(out + l, sz - l, "Mem-0");
break;
case PERF_MEM_REGION_MEM1:
l += scnprintf(out + l, sz - l, "Mem-1");
break;
case PERF_MEM_REGION_MEM2:
l += scnprintf(out + l, sz - l, "Mem-2");
break;
case PERF_MEM_REGION_MEM3:
l += scnprintf(out + l, sz - l, "Mem-3");
break;
case PERF_MEM_REGION_MEM4:
l += scnprintf(out + l, sz - l, "Mem-4");
break;
case PERF_MEM_REGION_MEM5:
l += scnprintf(out + l, sz - l, "Mem-5");
break;
case PERF_MEM_REGION_MEM6:
l += scnprintf(out + l, sz - l, "Mem-6");
break;
case PERF_MEM_REGION_MEM7:
l += scnprintf(out + l, sz - l, "Mem-7");
break;
default:
l += scnprintf(out + l, sz - l, "N/A");
break;
}
return l;
}
int perf_script__meminfo_scnprintf(char *out, size_t sz,
const struct mem_info *mem_info,
struct perf_session *session)
{
struct perf_env *env;
int i = 0;
i += scnprintf(out, sz, "|OP ");
@ -620,6 +690,21 @@ int perf_script__meminfo_scnprintf(char *out, size_t sz, const struct mem_info *
i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
i += scnprintf(out + i, sz - i, "|BLK ");
i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info);
if (session) {
/*
* In case the feature bits are not available, as in
* pipe mode, fallback to checking for the existence of
* memory ranges
*/
env = perf_session__env(session);
if ((env && session->data->is_pipe && env->nr_memory_ranges) ||
perf_header__has_feat(&session->header,
HEADER_MEMORY_RANGES)) {
i += scnprintf(out + i, sz - i, "|Region ");
i += perf_mem__region_scnprintf(out + i, sz - i,
mem_info);
}
}
return i;
}

View File

@ -24,6 +24,7 @@ enum {
struct evsel;
struct mem_info;
struct perf_pmu;
struct perf_session;
extern unsigned int perf_mem_events__loads_ldlat;
extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];
@ -47,7 +48,8 @@ int perf_mem__snp_scnprintf(char *out, size_t sz, const struct mem_info *mem_inf
int perf_mem__lck_scnprintf(char *out, size_t sz, const struct mem_info *mem_info);
int perf_mem__blk_scnprintf(char *out, size_t sz, const struct mem_info *mem_info);
int perf_script__meminfo_scnprintf(char *bf, size_t size, const struct mem_info *mem_info);
int perf_script__meminfo_scnprintf(char *bf, size_t size, const struct mem_info *mem_info,
struct perf_session *session);
struct c2c_stats {
u32 nr_entries;

View File

@ -58,6 +58,7 @@
#include "stat.h"
#include "mem-events.h"
#include "util/perf_regs.h"
#include "util/session.h"
#define _PyUnicode_FromString(arg) \
PyUnicode_FromString(arg)
@ -694,8 +695,9 @@ static void set_sample_read_in_dict(PyObject *dict_sample, struct perf_sample *s
static void set_sample_datasrc_in_dict(PyObject *dict,
struct perf_sample *sample)
{
struct perf_session *session = evsel__session(sample->evsel);
struct mem_info *mi = mem_info__new();
char decode[100];
char decode[200];
if (!mi)
Py_FatalError("couldn't create mem-info");
@ -704,7 +706,7 @@ static void set_sample_datasrc_in_dict(PyObject *dict,
PyLong_FromUnsignedLongLong(sample->data_src));
mem_info__data_src(mi)->val = sample->data_src;
perf_script__meminfo_scnprintf(decode, 100, mi);
perf_script__meminfo_scnprintf(decode, 200, mi, session);
mem_info__put(mi);
pydict_set_item_string_decref(dict, "datasrc_decode",