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

perf bpf filter: Add data_src sample data support

The data_src has many entries to express memory behaviors. Add each
term separately so that users can combine them for their purpose.

I didn't add prefix for the constants for simplicity as they are mostly
distinguishable but I had to use l1_miss and l2_hit for mem_dtlb since
mem_lvl has different values for the same names. Note that I decided
mem_lvl to be used as an alias of mem_lvlnum as it's deprecated now.
According to the comment in the UAPI header, users should use the mix of
mem_lvlnum, mem_remote and mem_snoop. Also the SNOOPX bits are
concatenated to mem_snoop for simplicity.

The following terms are used for data_src and the corresponding perf
sample data fields:

* mem_op : { load, store, pfetch, exec }
* mem_lvl: { l1, l2, l3, l4, cxl, io, any_cache, lfb, ram, pmem }
* mem_snoop: { none, hit, miss, hitm, fwd, peer }
* mem_remote: { remote }
* mem_lock: { locked }
* mem_dtlb { l1_hit, l1_miss, l2_hit, l2_miss, any_hit, any_miss, walk, fault }
* mem_blk { by_data, by_addr }
* mem_hops { hops0, hops1, hops2, hops3 }

We can now use a filter expression like below:

'mem_op == load, mem_lvl <= l2, mem_dtlb == l1_hit'
'mem_dtlb == l2_miss, mem_hops > hops1'
'mem_lvl == ram, mem_remote == 1'

Note that 'na' is shared among the terms as it has the same value except
for mem_lvl. I don't have a good idea to handle that for now.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Hao Luo <haoluo@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: James Clark <james.clark@arm.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Song Liu <song@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: bpf@vger.kernel.org
Link: https://lore.kernel.org/r/20230314234237.3008956-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
ff612055 409bcd80

+84
+61
tools/perf/util/bpf-filter.l
··· 42 42 return BFT_NUM; 43 43 } 44 44 45 + static int constant(int val) 46 + { 47 + perf_bpf_filter_lval.num = val; 48 + return BFT_NUM; 49 + } 50 + 45 51 static int error(const char *str) 46 52 { 47 53 printf("perf_bpf_filter: Unexpected filter %s: %s\n", str, perf_bpf_filter_text); ··· 86 80 phys_addr { return sample(PERF_SAMPLE_PHYS_ADDR); } 87 81 code_pgsz { return sample(PERF_SAMPLE_CODE_PAGE_SIZE); } 88 82 data_pgsz { return sample(PERF_SAMPLE_DATA_PAGE_SIZE); } 83 + mem_op { return sample_part(PERF_SAMPLE_DATA_SRC, 1); } 84 + mem_lvlnum { return sample_part(PERF_SAMPLE_DATA_SRC, 2); } 85 + mem_lvl { return sample_part(PERF_SAMPLE_DATA_SRC, 2); } /* alias for mem_lvlnum */ 86 + mem_snoop { return sample_part(PERF_SAMPLE_DATA_SRC, 3); } /* include snoopx */ 87 + mem_remote { return sample_part(PERF_SAMPLE_DATA_SRC, 4); } 88 + mem_lock { return sample_part(PERF_SAMPLE_DATA_SRC, 5); } 89 + mem_dtlb { return sample_part(PERF_SAMPLE_DATA_SRC, 6); } 90 + mem_blk { return sample_part(PERF_SAMPLE_DATA_SRC, 7); } 91 + mem_hops { return sample_part(PERF_SAMPLE_DATA_SRC, 8); } 89 92 90 93 "==" { return operator(PBF_OP_EQ); } 91 94 "!=" { return operator(PBF_OP_NEQ); } ··· 103 88 ">=" { return operator(PBF_OP_GE); } 104 89 "<=" { return operator(PBF_OP_LE); } 105 90 "&" { return operator(PBF_OP_AND); } 91 + 92 + na { return constant(PERF_MEM_OP_NA); } 93 + load { return constant(PERF_MEM_OP_LOAD); } 94 + store { return constant(PERF_MEM_OP_STORE); } 95 + pfetch { return constant(PERF_MEM_OP_PFETCH); } 96 + exec { return constant(PERF_MEM_OP_EXEC); } 97 + 98 + l1 { return constant(PERF_MEM_LVLNUM_L1); } 99 + l2 { return constant(PERF_MEM_LVLNUM_L2); } 100 + l3 { return constant(PERF_MEM_LVLNUM_L3); } 101 + l4 { return constant(PERF_MEM_LVLNUM_L4); } 102 + cxl { return constant(PERF_MEM_LVLNUM_CXL); } 103 + io { return constant(PERF_MEM_LVLNUM_IO); } 104 + any_cache { return constant(PERF_MEM_LVLNUM_ANY_CACHE); } 105 + lfb { return constant(PERF_MEM_LVLNUM_LFB); } 106 + ram { return constant(PERF_MEM_LVLNUM_RAM); } 107 + pmem { return constant(PERF_MEM_LVLNUM_PMEM); } 108 + 109 + none { return constant(PERF_MEM_SNOOP_NONE); } 110 + hit { return constant(PERF_MEM_SNOOP_HIT); } 111 + miss { return constant(PERF_MEM_SNOOP_MISS); } 112 + hitm { return constant(PERF_MEM_SNOOP_HITM); } 113 + fwd { return constant(PERF_MEM_SNOOPX_FWD); } 114 + peer { return constant(PERF_MEM_SNOOPX_PEER); } 115 + 116 + remote { return constant(PERF_MEM_REMOTE_REMOTE); } 117 + 118 + locked { return constant(PERF_MEM_LOCK_LOCKED); } 119 + 120 + l1_hit { return constant(PERF_MEM_TLB_L1 | PERF_MEM_TLB_HIT); } 121 + l1_miss { return constant(PERF_MEM_TLB_L1 | PERF_MEM_TLB_MISS); } 122 + l2_hit { return constant(PERF_MEM_TLB_L2 | PERF_MEM_TLB_HIT); } 123 + l2_miss { return constant(PERF_MEM_TLB_L2 | PERF_MEM_TLB_MISS); } 124 + any_hit { return constant(PERF_MEM_TLB_HIT); } 125 + any_miss { return constant(PERF_MEM_TLB_MISS); } 126 + walk { return constant(PERF_MEM_TLB_WK); } 127 + os { return constant(PERF_MEM_TLB_OS); } 128 + fault { return constant(PERF_MEM_TLB_OS); } /* alias for os */ 129 + 130 + by_data { return constant(PERF_MEM_BLK_DATA); } 131 + by_addr { return constant(PERF_MEM_BLK_ADDR); } 132 + 133 + hops0 { return constant(PERF_MEM_HOPS_0); } 134 + hops1 { return constant(PERF_MEM_HOPS_1); } 135 + hops2 { return constant(PERF_MEM_HOPS_2); } 136 + hops3 { return constant(PERF_MEM_HOPS_3); } 106 137 107 138 "," { return ','; } 108 139
+23
tools/perf/util/bpf_skel/sample_filter.bpf.c
··· 70 70 return kctx->data->code_page_size; 71 71 case PERF_SAMPLE_DATA_PAGE_SIZE: 72 72 return kctx->data->data_page_size; 73 + case PERF_SAMPLE_DATA_SRC: 74 + if (entry->part == 1) 75 + return kctx->data->data_src.mem_op; 76 + if (entry->part == 2) 77 + return kctx->data->data_src.mem_lvl_num; 78 + if (entry->part == 3) { 79 + __u32 snoop = kctx->data->data_src.mem_snoop; 80 + __u32 snoopx = kctx->data->data_src.mem_snoopx; 81 + 82 + return (snoopx << 5) | snoop; 83 + } 84 + if (entry->part == 4) 85 + return kctx->data->data_src.mem_remote; 86 + if (entry->part == 5) 87 + return kctx->data->data_src.mem_lock; 88 + if (entry->part == 6) 89 + return kctx->data->data_src.mem_dtlb; 90 + if (entry->part == 7) 91 + return kctx->data->data_src.mem_blk; 92 + if (entry->part == 8) 93 + return kctx->data->data_src.mem_hops; 94 + /* return the whole word */ 95 + return kctx->data->data_src.val; 73 96 default: 74 97 break; 75 98 }