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

Configure Feed

Select the types of activity you want to include in your feed.

perf bpf-filter: Support filtering on cgroups

The new cgroup filter can take either of '==' or '!=' operator and a
pathname for the target cgroup.

$ perf record -a --all-cgroups -e cycles --filter 'cgroup == /abc/def' -- sleep 1

Users should have --all-cgroups option in the command line to enable
cgroup filtering. Technically it doesn't need to have the option as
it can get the current task's cgroup info directly from BPF. But I want
to follow the convention for the other sample info.

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: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20240826221045.1202305-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
91e88437 591156f2

+55 -9
+1
tools/perf/util/bpf-filter.c
··· 100 100 PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"), 101 101 PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"), 102 102 PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"), 103 + PERF_SAMPLE_TYPE(CGROUP, "--all-cgroups"), 103 104 }; 104 105 105 106 static int get_pinned_fd(const char *name);
+23 -5
tools/perf/util/bpf-filter.l
··· 9 9 #include "bpf-filter.h" 10 10 #include "bpf-filter-bison.h" 11 11 12 + extern int perf_bpf_filter_needs_path; 13 + 12 14 static int sample(enum perf_bpf_filter_term term) 13 15 { 16 + perf_bpf_filter_needs_path = 0; 14 17 perf_bpf_filter_lval.sample.term = term; 15 18 perf_bpf_filter_lval.sample.part = 0; 16 19 return BFT_SAMPLE; ··· 21 18 22 19 static int sample_part(enum perf_bpf_filter_term term, int part) 23 20 { 21 + perf_bpf_filter_needs_path = 0; 24 22 perf_bpf_filter_lval.sample.term = term; 25 23 perf_bpf_filter_lval.sample.part = part; 26 24 return BFT_SAMPLE; 25 + } 26 + 27 + static int sample_path(enum perf_bpf_filter_term term) 28 + { 29 + perf_bpf_filter_needs_path = 1; 30 + perf_bpf_filter_lval.sample.term = term; 31 + perf_bpf_filter_lval.sample.part = 0; 32 + return BFT_SAMPLE_PATH; 27 33 } 28 34 29 35 static int operator(enum perf_bpf_filter_op op) ··· 60 48 return BFT_NUM; 61 49 } 62 50 63 - static int error(const char *str) 51 + static int path_or_error(void) 64 52 { 65 - printf("perf_bpf_filter: Unexpected filter %s: %s\n", str, perf_bpf_filter_text); 66 - return BFT_ERROR; 53 + if (!perf_bpf_filter_needs_path) { 54 + printf("perf_bpf_filter: Error: Unexpected item: %s\n", 55 + perf_bpf_filter_text); 56 + return BFT_ERROR; 57 + } 58 + perf_bpf_filter_lval.path = perf_bpf_filter_text; 59 + return BFT_PATH; 67 60 } 68 61 69 62 %} ··· 76 59 num_dec [0-9]+ 77 60 num_hex 0[Xx][0-9a-fA-F]+ 78 61 space [ \t]+ 62 + path [^ \t\n]+ 79 63 ident [_a-zA-Z][_a-zA-Z0-9]+ 80 64 81 65 %% ··· 115 97 mem_hops { return sample_part(PBF_TERM_DATA_SRC, 8); } 116 98 uid { return sample(PBF_TERM_UID); } 117 99 gid { return sample(PBF_TERM_GID); } 100 + cgroup { return sample_path(PBF_TERM_CGROUP); } 118 101 119 102 "==" { return operator(PBF_OP_EQ); } 120 103 "!=" { return operator(PBF_OP_NEQ); } ··· 174 155 "," { return ','; } 175 156 "||" { return BFT_LOGICAL_OR; } 176 157 177 - {ident} { return error("ident"); } 178 - . { return error("input"); } 158 + {path} { return path_or_error(); } 179 159 180 160 %%
+26 -2
tools/perf/util/bpf-filter.y
··· 12 12 #include <linux/compiler.h> 13 13 #include <linux/list.h> 14 14 #include "bpf-filter.h" 15 + #include "cgroup.h" 15 16 16 17 int perf_bpf_filter_lex(void); 18 + 19 + /* To indicate if the current term needs a pathname or not */ 20 + int perf_bpf_filter_needs_path; 17 21 18 22 static void perf_bpf_filter_error(struct list_head *expr __maybe_unused, 19 23 char const *msg) ··· 30 26 %union 31 27 { 32 28 unsigned long num; 29 + char *path; 33 30 struct { 34 31 enum perf_bpf_filter_term term; 35 32 int part; ··· 39 34 struct perf_bpf_filter_expr *expr; 40 35 } 41 36 42 - %token BFT_SAMPLE BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR 37 + %token BFT_SAMPLE BFT_SAMPLE_PATH BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR BFT_PATH 43 38 %type <expr> filter_term filter_expr 44 39 %destructor { free ($$); } <expr> 45 - %type <sample> BFT_SAMPLE 40 + %type <sample> BFT_SAMPLE BFT_SAMPLE_PATH 46 41 %type <op> BFT_OP 47 42 %type <num> BFT_NUM 43 + %type <path> BFT_PATH 48 44 49 45 %% 50 46 ··· 86 80 BFT_SAMPLE BFT_OP BFT_NUM 87 81 { 88 82 $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3); 83 + } 84 + | 85 + BFT_SAMPLE_PATH BFT_OP BFT_PATH 86 + { 87 + struct cgroup *cgrp; 88 + unsigned long cgroup_id = 0; 89 + 90 + if ($2 != PBF_OP_EQ && $2 != PBF_OP_NEQ) { 91 + printf("perf_bpf_filter: cgroup accepts '==' or '!=' only\n"); 92 + YYERROR; 93 + } 94 + 95 + cgrp = cgroup__new($3, /*do_open=*/false); 96 + if (cgrp && read_cgroup_id(cgrp) == 0) 97 + cgroup_id = cgrp->id; 98 + 99 + $$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, cgroup_id); 100 + cgroup__put(cgrp); 89 101 } 90 102 91 103 %%
+1 -1
tools/perf/util/bpf_skel/sample-filter.h
··· 45 45 __PBF_UNUSED_TERM18 = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */ 46 46 PBF_TERM_PHYS_ADDR = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */ 47 47 __PBF_UNUSED_TERM20 = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */ 48 - __PBF_UNUSED_TERM21 = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */ 48 + PBF_TERM_CGROUP = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */ 49 49 PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */ 50 50 PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */ 51 51 PBF_TERM_WEIGHT_STRUCT = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */
+3 -1
tools/perf/util/bpf_skel/sample_filter.bpf.c
··· 93 93 BUILD_CHECK_SAMPLE(DATA_SRC); 94 94 BUILD_CHECK_SAMPLE(TRANSACTION); 95 95 BUILD_CHECK_SAMPLE(PHYS_ADDR); 96 + BUILD_CHECK_SAMPLE(CGROUP); 96 97 BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE); 97 98 BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE); 98 99 BUILD_CHECK_SAMPLE(WEIGHT_STRUCT); ··· 136 135 return kctx->data->weight.full; 137 136 case PBF_TERM_PHYS_ADDR: 138 137 return kctx->data->phys_addr; 138 + case PBF_TERM_CGROUP: 139 + return kctx->data->cgroup; 139 140 case PBF_TERM_CODE_PAGE_SIZE: 140 141 return kctx->data->code_page_size; 141 142 case PBF_TERM_DATA_PAGE_SIZE: ··· 186 183 case __PBF_UNUSED_TERM16: 187 184 case __PBF_UNUSED_TERM18: 188 185 case __PBF_UNUSED_TERM20: 189 - case __PBF_UNUSED_TERM21: 190 186 default: 191 187 break; 192 188 }
+1
tools/perf/util/bpf_skel/vmlinux/vmlinux.h
··· 171 171 u32 cpu; 172 172 } cpu_entry; 173 173 u64 phys_addr; 174 + u64 cgroup; 174 175 u64 data_page_size; 175 176 u64 code_page_size; 176 177 } __attribute__((__aligned__(64))) __attribute__((preserve_access_index));