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

perf bpf filter: Give terms their own enum

Give the term types their own enum so that additional terms can be
added that don't correspond to a PERF_SAMPLE_xx flag. The term values
are numerically ascending rather than bit field positions, this means
they need translating to a PERF_SAMPLE_xx bit field in certain places
using a shift.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: John Fastabend <john.fastabend@gmail.com>
Cc: Changbin Du <changbin.du@huawei.com>
Cc: Yang Jihong <yangjihong1@huawei.com>
Cc: Andrii Nakryiko <andrii@kernel.org>
Cc: bpf@vger.kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240524205227.244375-2-irogers@google.com

authored by

Ian Rogers and committed by
Namhyung Kim
63b9cbd7 d163d602

+140 -68
+15 -13
tools/perf/util/bpf-filter.c
··· 17 17 18 18 #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) 19 19 20 - #define __PERF_SAMPLE_TYPE(st, opt) { st, #st, opt } 21 - #define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PERF_SAMPLE_##_st, opt) 20 + #define __PERF_SAMPLE_TYPE(tt, st, opt) { tt, #st, opt } 21 + #define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PBF_TERM_##_st, PERF_SAMPLE_##_st, opt) 22 22 23 23 static const struct perf_sample_info { 24 - u64 type; 24 + enum perf_bpf_filter_term type; 25 25 const char *name; 26 26 const char *option; 27 27 } sample_table[] = { ··· 44 44 PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"), 45 45 }; 46 46 47 - static const struct perf_sample_info *get_sample_info(u64 flags) 47 + static const struct perf_sample_info *get_sample_info(enum perf_bpf_filter_term type) 48 48 { 49 49 size_t i; 50 50 51 51 for (i = 0; i < ARRAY_SIZE(sample_table); i++) { 52 - if (sample_table[i].type == flags) 52 + if (sample_table[i].type == type) 53 53 return &sample_table[i]; 54 54 } 55 55 return NULL; ··· 59 59 { 60 60 const struct perf_sample_info *info; 61 61 62 - if (evsel->core.attr.sample_type & expr->sample_flags) 62 + if (expr->term >= PBF_TERM_SAMPLE_START && expr->term <= PBF_TERM_SAMPLE_END && 63 + (evsel->core.attr.sample_type & (1 << (expr->term - PBF_TERM_SAMPLE_START)))) 63 64 return 0; 64 65 65 66 if (expr->op == PBF_OP_GROUP_BEGIN) { ··· 73 72 return 0; 74 73 } 75 74 76 - info = get_sample_info(expr->sample_flags); 75 + info = get_sample_info(expr->term); 77 76 if (info == NULL) { 78 - pr_err("Error: %s event does not have sample flags %lx\n", 79 - evsel__name(evsel), expr->sample_flags); 77 + pr_err("Error: %s event does not have sample flags %d\n", 78 + evsel__name(evsel), expr->term); 80 79 return -1; 81 80 } 82 81 ··· 106 105 struct perf_bpf_filter_entry entry = { 107 106 .op = expr->op, 108 107 .part = expr->part, 109 - .flags = expr->sample_flags, 108 + .term = expr->term, 110 109 .value = expr->val, 111 110 }; 112 111 ··· 123 122 struct perf_bpf_filter_entry group_entry = { 124 123 .op = group->op, 125 124 .part = group->part, 126 - .flags = group->sample_flags, 125 + .term = group->term, 127 126 .value = group->val, 128 127 }; 129 128 bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY); ··· 174 173 return skel ? skel->bss->dropped : 0; 175 174 } 176 175 177 - struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, int part, 176 + struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term, 177 + int part, 178 178 enum perf_bpf_filter_op op, 179 179 unsigned long val) 180 180 { ··· 183 181 184 182 expr = malloc(sizeof(*expr)); 185 183 if (expr != NULL) { 186 - expr->sample_flags = sample_flags; 184 + expr->term = term; 187 185 expr->part = part; 188 186 expr->op = op; 189 187 expr->val = val;
+3 -2
tools/perf/util/bpf-filter.h
··· 11 11 struct list_head groups; 12 12 enum perf_bpf_filter_op op; 13 13 int part; 14 - unsigned long sample_flags; 14 + enum perf_bpf_filter_term term; 15 15 unsigned long val; 16 16 }; 17 17 18 18 struct evsel; 19 19 20 20 #ifdef HAVE_BPF_SKEL 21 - struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, int part, 21 + struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term, 22 + int part, 22 23 enum perf_bpf_filter_op op, 23 24 unsigned long val); 24 25 int perf_bpf_filter__parse(struct list_head *expr_head, const char *str);
+32 -32
tools/perf/util/bpf-filter.l
··· 9 9 #include "bpf-filter.h" 10 10 #include "bpf-filter-bison.h" 11 11 12 - static int sample(unsigned long sample_flag) 12 + static int sample(enum perf_bpf_filter_term term) 13 13 { 14 - perf_bpf_filter_lval.sample.type = sample_flag; 14 + perf_bpf_filter_lval.sample.term = term; 15 15 perf_bpf_filter_lval.sample.part = 0; 16 16 return BFT_SAMPLE; 17 17 } 18 18 19 - static int sample_part(unsigned long sample_flag, int part) 19 + static int sample_part(enum perf_bpf_filter_term term, int part) 20 20 { 21 - perf_bpf_filter_lval.sample.type = sample_flag; 21 + perf_bpf_filter_lval.sample.term = term; 22 22 perf_bpf_filter_lval.sample.part = part; 23 23 return BFT_SAMPLE; 24 24 } ··· 67 67 {num_hex} { return value(16); } 68 68 {space} { } 69 69 70 - ip { return sample(PERF_SAMPLE_IP); } 71 - id { return sample(PERF_SAMPLE_ID); } 72 - tid { return sample(PERF_SAMPLE_TID); } 73 - pid { return sample_part(PERF_SAMPLE_TID, 1); } 74 - cpu { return sample(PERF_SAMPLE_CPU); } 75 - time { return sample(PERF_SAMPLE_TIME); } 76 - addr { return sample(PERF_SAMPLE_ADDR); } 77 - period { return sample(PERF_SAMPLE_PERIOD); } 78 - txn { return sample(PERF_SAMPLE_TRANSACTION); } 79 - weight { return sample(PERF_SAMPLE_WEIGHT); } 80 - weight1 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 1); } 81 - weight2 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 2); } 82 - weight3 { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); } 83 - ins_lat { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 2); } /* alias for weight2 */ 84 - p_stage_cyc { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); } /* alias for weight3 */ 85 - retire_lat { return sample_part(PERF_SAMPLE_WEIGHT_STRUCT, 3); } /* alias for weight3 */ 86 - phys_addr { return sample(PERF_SAMPLE_PHYS_ADDR); } 87 - code_pgsz { return sample(PERF_SAMPLE_CODE_PAGE_SIZE); } 88 - data_pgsz { return sample(PERF_SAMPLE_DATA_PAGE_SIZE); } 89 - mem_op { return sample_part(PERF_SAMPLE_DATA_SRC, 1); } 90 - mem_lvlnum { return sample_part(PERF_SAMPLE_DATA_SRC, 2); } 91 - mem_lvl { return sample_part(PERF_SAMPLE_DATA_SRC, 2); } /* alias for mem_lvlnum */ 92 - mem_snoop { return sample_part(PERF_SAMPLE_DATA_SRC, 3); } /* include snoopx */ 93 - mem_remote { return sample_part(PERF_SAMPLE_DATA_SRC, 4); } 94 - mem_lock { return sample_part(PERF_SAMPLE_DATA_SRC, 5); } 95 - mem_dtlb { return sample_part(PERF_SAMPLE_DATA_SRC, 6); } 96 - mem_blk { return sample_part(PERF_SAMPLE_DATA_SRC, 7); } 97 - mem_hops { return sample_part(PERF_SAMPLE_DATA_SRC, 8); } 70 + ip { return sample(PBF_TERM_IP); } 71 + id { return sample(PBF_TERM_ID); } 72 + tid { return sample(PBF_TERM_TID); } 73 + pid { return sample_part(PBF_TERM_TID, 1); } 74 + cpu { return sample(PBF_TERM_CPU); } 75 + time { return sample(PBF_TERM_TIME); } 76 + addr { return sample(PBF_TERM_ADDR); } 77 + period { return sample(PBF_TERM_PERIOD); } 78 + txn { return sample(PBF_TERM_TRANSACTION); } 79 + weight { return sample(PBF_TERM_WEIGHT); } 80 + weight1 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 1); } 81 + weight2 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 2); } 82 + weight3 { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); } 83 + ins_lat { return sample_part(PBF_TERM_WEIGHT_STRUCT, 2); } /* alias for weight2 */ 84 + p_stage_cyc { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); } /* alias for weight3 */ 85 + retire_lat { return sample_part(PBF_TERM_WEIGHT_STRUCT, 3); } /* alias for weight3 */ 86 + phys_addr { return sample(PBF_TERM_PHYS_ADDR); } 87 + code_pgsz { return sample(PBF_TERM_CODE_PAGE_SIZE); } 88 + data_pgsz { return sample(PBF_TERM_DATA_PAGE_SIZE); } 89 + mem_op { return sample_part(PBF_TERM_DATA_SRC, 1); } 90 + mem_lvlnum { return sample_part(PBF_TERM_DATA_SRC, 2); } 91 + mem_lvl { return sample_part(PBF_TERM_DATA_SRC, 2); } /* alias for mem_lvlnum */ 92 + mem_snoop { return sample_part(PBF_TERM_DATA_SRC, 3); } /* include snoopx */ 93 + mem_remote { return sample_part(PBF_TERM_DATA_SRC, 4); } 94 + mem_lock { return sample_part(PBF_TERM_DATA_SRC, 5); } 95 + mem_dtlb { return sample_part(PBF_TERM_DATA_SRC, 6); } 96 + mem_blk { return sample_part(PBF_TERM_DATA_SRC, 7); } 97 + mem_hops { return sample_part(PBF_TERM_DATA_SRC, 8); } 98 98 99 99 "==" { return operator(PBF_OP_EQ); } 100 100 "!=" { return operator(PBF_OP_NEQ); }
+4 -3
tools/perf/util/bpf-filter.y
··· 27 27 { 28 28 unsigned long num; 29 29 struct { 30 - unsigned long type; 30 + enum perf_bpf_filter_term term; 31 31 int part; 32 32 } sample; 33 33 enum perf_bpf_filter_op op; ··· 62 62 if ($1->op == PBF_OP_GROUP_BEGIN) { 63 63 expr = $1; 64 64 } else { 65 - expr = perf_bpf_filter_expr__new(0, 0, PBF_OP_GROUP_BEGIN, 1); 65 + expr = perf_bpf_filter_expr__new(PBF_TERM_NONE, /*part=*/0, 66 + PBF_OP_GROUP_BEGIN, /*val=*/1); 66 67 list_add_tail(&$1->list, &expr->groups); 67 68 } 68 69 expr->val++; ··· 79 78 filter_expr: 80 79 BFT_SAMPLE BFT_OP BFT_NUM 81 80 { 82 - $$ = perf_bpf_filter_expr__new($1.type, $1.part, $2, $3); 81 + $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3); 83 82 } 84 83 85 84 %%
+34 -1
tools/perf/util/bpf_skel/sample-filter.h
··· 16 16 PBF_OP_GROUP_END, 17 17 }; 18 18 19 + enum perf_bpf_filter_term { 20 + /* No term is in use. */ 21 + PBF_TERM_NONE = 0, 22 + /* Terms that correspond to PERF_SAMPLE_xx values. */ 23 + PBF_TERM_SAMPLE_START = PBF_TERM_NONE + 1, 24 + PBF_TERM_IP = PBF_TERM_SAMPLE_START + 0, /* SAMPLE_IP = 1U << 0 */ 25 + PBF_TERM_TID = PBF_TERM_SAMPLE_START + 1, /* SAMPLE_TID = 1U << 1 */ 26 + PBF_TERM_TIME = PBF_TERM_SAMPLE_START + 2, /* SAMPLE_TIME = 1U << 2 */ 27 + PBF_TERM_ADDR = PBF_TERM_SAMPLE_START + 3, /* SAMPLE_ADDR = 1U << 3 */ 28 + __PBF_UNUSED_TERM4 = PBF_TERM_SAMPLE_START + 4, /* SAMPLE_READ = 1U << 4 */ 29 + __PBF_UNUSED_TERM5 = PBF_TERM_SAMPLE_START + 5, /* SAMPLE_CALLCHAIN = 1U << 5 */ 30 + PBF_TERM_ID = PBF_TERM_SAMPLE_START + 6, /* SAMPLE_ID = 1U << 6 */ 31 + PBF_TERM_CPU = PBF_TERM_SAMPLE_START + 7, /* SAMPLE_CPU = 1U << 7 */ 32 + PBF_TERM_PERIOD = PBF_TERM_SAMPLE_START + 8, /* SAMPLE_PERIOD = 1U << 8 */ 33 + __PBF_UNUSED_TERM9 = PBF_TERM_SAMPLE_START + 9, /* SAMPLE_STREAM_ID = 1U << 9 */ 34 + __PBF_UNUSED_TERM10 = PBF_TERM_SAMPLE_START + 10, /* SAMPLE_RAW = 1U << 10 */ 35 + __PBF_UNUSED_TERM11 = PBF_TERM_SAMPLE_START + 11, /* SAMPLE_BRANCH_STACK = 1U << 11 */ 36 + __PBF_UNUSED_TERM12 = PBF_TERM_SAMPLE_START + 12, /* SAMPLE_REGS_USER = 1U << 12 */ 37 + __PBF_UNUSED_TERM13 = PBF_TERM_SAMPLE_START + 13, /* SAMPLE_STACK_USER = 1U << 13 */ 38 + PBF_TERM_WEIGHT = PBF_TERM_SAMPLE_START + 14, /* SAMPLE_WEIGHT = 1U << 14 */ 39 + PBF_TERM_DATA_SRC = PBF_TERM_SAMPLE_START + 15, /* SAMPLE_DATA_SRC = 1U << 15 */ 40 + __PBF_UNUSED_TERM16 = PBF_TERM_SAMPLE_START + 16, /* SAMPLE_IDENTIFIER = 1U << 16 */ 41 + PBF_TERM_TRANSACTION = PBF_TERM_SAMPLE_START + 17, /* SAMPLE_TRANSACTION = 1U << 17 */ 42 + __PBF_UNUSED_TERM18 = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */ 43 + PBF_TERM_PHYS_ADDR = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */ 44 + __PBF_UNUSED_TERM20 = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */ 45 + __PBF_UNUSED_TERM21 = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */ 46 + PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */ 47 + PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */ 48 + PBF_TERM_WEIGHT_STRUCT = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */ 49 + PBF_TERM_SAMPLE_END = PBF_TERM_WEIGHT_STRUCT, 50 + }; 51 + 19 52 /* BPF map entry for filtering */ 20 53 struct perf_bpf_filter_entry { 21 54 enum perf_bpf_filter_op op; 22 55 __u32 part; /* sub-sample type info when it has multiple values */ 23 - __u64 flags; /* perf sample type flags */ 56 + enum perf_bpf_filter_term term; 24 57 __u64 value; 25 58 }; 26 59
+52 -17
tools/perf/util/bpf_skel/sample_filter.bpf.c
··· 48 48 { 49 49 struct perf_sample_data___new *data = (void *)kctx->data; 50 50 51 - if (!bpf_core_field_exists(data->sample_flags) || 52 - (data->sample_flags & entry->flags) == 0) 51 + if (!bpf_core_field_exists(data->sample_flags)) 53 52 return 0; 54 53 55 - switch (entry->flags) { 56 - case PERF_SAMPLE_IP: 54 + #define BUILD_CHECK_SAMPLE(x) \ 55 + _Static_assert((1 << (PBF_TERM_##x - PBF_TERM_SAMPLE_START)) == PERF_SAMPLE_##x, \ 56 + "Mismatched PBF term to sample bit " #x) 57 + BUILD_CHECK_SAMPLE(IP); 58 + BUILD_CHECK_SAMPLE(TID); 59 + BUILD_CHECK_SAMPLE(TIME); 60 + BUILD_CHECK_SAMPLE(ADDR); 61 + BUILD_CHECK_SAMPLE(ID); 62 + BUILD_CHECK_SAMPLE(CPU); 63 + BUILD_CHECK_SAMPLE(PERIOD); 64 + BUILD_CHECK_SAMPLE(WEIGHT); 65 + BUILD_CHECK_SAMPLE(DATA_SRC); 66 + BUILD_CHECK_SAMPLE(TRANSACTION); 67 + BUILD_CHECK_SAMPLE(PHYS_ADDR); 68 + BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE); 69 + BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE); 70 + BUILD_CHECK_SAMPLE(WEIGHT_STRUCT); 71 + #undef BUILD_CHECK_SAMPLE 72 + 73 + /* For sample terms check the sample bit is set. */ 74 + if (entry->term >= PBF_TERM_SAMPLE_START && entry->term <= PBF_TERM_SAMPLE_END && 75 + (data->sample_flags & (1 << (entry->term - PBF_TERM_SAMPLE_START))) == 0) 76 + return 0; 77 + 78 + switch (entry->term) { 79 + case PBF_TERM_IP: 57 80 return kctx->data->ip; 58 - case PERF_SAMPLE_ID: 81 + case PBF_TERM_ID: 59 82 return kctx->data->id; 60 - case PERF_SAMPLE_TID: 83 + case PBF_TERM_TID: 61 84 if (entry->part) 62 85 return kctx->data->tid_entry.pid; 63 86 else 64 87 return kctx->data->tid_entry.tid; 65 - case PERF_SAMPLE_CPU: 88 + case PBF_TERM_CPU: 66 89 return kctx->data->cpu_entry.cpu; 67 - case PERF_SAMPLE_TIME: 90 + case PBF_TERM_TIME: 68 91 return kctx->data->time; 69 - case PERF_SAMPLE_ADDR: 92 + case PBF_TERM_ADDR: 70 93 return kctx->data->addr; 71 - case PERF_SAMPLE_PERIOD: 94 + case PBF_TERM_PERIOD: 72 95 return kctx->data->period; 73 - case PERF_SAMPLE_TRANSACTION: 96 + case PBF_TERM_TRANSACTION: 74 97 return kctx->data->txn; 75 - case PERF_SAMPLE_WEIGHT_STRUCT: 98 + case PBF_TERM_WEIGHT_STRUCT: 76 99 if (entry->part == 1) 77 100 return kctx->data->weight.var1_dw; 78 101 if (entry->part == 2) ··· 103 80 if (entry->part == 3) 104 81 return kctx->data->weight.var3_w; 105 82 /* fall through */ 106 - case PERF_SAMPLE_WEIGHT: 83 + case PBF_TERM_WEIGHT: 107 84 return kctx->data->weight.full; 108 - case PERF_SAMPLE_PHYS_ADDR: 85 + case PBF_TERM_PHYS_ADDR: 109 86 return kctx->data->phys_addr; 110 - case PERF_SAMPLE_CODE_PAGE_SIZE: 87 + case PBF_TERM_CODE_PAGE_SIZE: 111 88 return kctx->data->code_page_size; 112 - case PERF_SAMPLE_DATA_PAGE_SIZE: 89 + case PBF_TERM_DATA_PAGE_SIZE: 113 90 return kctx->data->data_page_size; 114 - case PERF_SAMPLE_DATA_SRC: 91 + case PBF_TERM_DATA_SRC: 115 92 if (entry->part == 1) 116 93 return kctx->data->data_src.mem_op; 117 94 if (entry->part == 2) ··· 140 117 } 141 118 /* return the whole word */ 142 119 return kctx->data->data_src.val; 120 + case PBF_TERM_NONE: 121 + case __PBF_UNUSED_TERM4: 122 + case __PBF_UNUSED_TERM5: 123 + case __PBF_UNUSED_TERM9: 124 + case __PBF_UNUSED_TERM10: 125 + case __PBF_UNUSED_TERM11: 126 + case __PBF_UNUSED_TERM12: 127 + case __PBF_UNUSED_TERM13: 128 + case __PBF_UNUSED_TERM16: 129 + case __PBF_UNUSED_TERM18: 130 + case __PBF_UNUSED_TERM20: 131 + case __PBF_UNUSED_TERM21: 143 132 default: 144 133 break; 145 134 }