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>
This commit is contained in:
parent
591156f25f
commit
91e88437d5
@ -100,6 +100,7 @@ static const struct perf_sample_info {
|
|||||||
PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"),
|
PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"),
|
||||||
PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"),
|
PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"),
|
||||||
PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
|
PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
|
||||||
|
PERF_SAMPLE_TYPE(CGROUP, "--all-cgroups"),
|
||||||
};
|
};
|
||||||
|
|
||||||
static int get_pinned_fd(const char *name);
|
static int get_pinned_fd(const char *name);
|
||||||
|
@ -9,8 +9,11 @@
|
|||||||
#include "bpf-filter.h"
|
#include "bpf-filter.h"
|
||||||
#include "bpf-filter-bison.h"
|
#include "bpf-filter-bison.h"
|
||||||
|
|
||||||
|
extern int perf_bpf_filter_needs_path;
|
||||||
|
|
||||||
static int sample(enum perf_bpf_filter_term term)
|
static int sample(enum perf_bpf_filter_term term)
|
||||||
{
|
{
|
||||||
|
perf_bpf_filter_needs_path = 0;
|
||||||
perf_bpf_filter_lval.sample.term = term;
|
perf_bpf_filter_lval.sample.term = term;
|
||||||
perf_bpf_filter_lval.sample.part = 0;
|
perf_bpf_filter_lval.sample.part = 0;
|
||||||
return BFT_SAMPLE;
|
return BFT_SAMPLE;
|
||||||
@ -18,11 +21,20 @@ static int sample(enum perf_bpf_filter_term term)
|
|||||||
|
|
||||||
static int sample_part(enum perf_bpf_filter_term term, int part)
|
static int sample_part(enum perf_bpf_filter_term term, int part)
|
||||||
{
|
{
|
||||||
|
perf_bpf_filter_needs_path = 0;
|
||||||
perf_bpf_filter_lval.sample.term = term;
|
perf_bpf_filter_lval.sample.term = term;
|
||||||
perf_bpf_filter_lval.sample.part = part;
|
perf_bpf_filter_lval.sample.part = part;
|
||||||
return BFT_SAMPLE;
|
return BFT_SAMPLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sample_path(enum perf_bpf_filter_term term)
|
||||||
|
{
|
||||||
|
perf_bpf_filter_needs_path = 1;
|
||||||
|
perf_bpf_filter_lval.sample.term = term;
|
||||||
|
perf_bpf_filter_lval.sample.part = 0;
|
||||||
|
return BFT_SAMPLE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
static int operator(enum perf_bpf_filter_op op)
|
static int operator(enum perf_bpf_filter_op op)
|
||||||
{
|
{
|
||||||
perf_bpf_filter_lval.op = op;
|
perf_bpf_filter_lval.op = op;
|
||||||
@ -48,10 +60,15 @@ static int constant(int val)
|
|||||||
return BFT_NUM;
|
return BFT_NUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int error(const char *str)
|
static int path_or_error(void)
|
||||||
{
|
{
|
||||||
printf("perf_bpf_filter: Unexpected filter %s: %s\n", str, perf_bpf_filter_text);
|
if (!perf_bpf_filter_needs_path) {
|
||||||
return BFT_ERROR;
|
printf("perf_bpf_filter: Error: Unexpected item: %s\n",
|
||||||
|
perf_bpf_filter_text);
|
||||||
|
return BFT_ERROR;
|
||||||
|
}
|
||||||
|
perf_bpf_filter_lval.path = perf_bpf_filter_text;
|
||||||
|
return BFT_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
@ -59,6 +76,7 @@ static int error(const char *str)
|
|||||||
num_dec [0-9]+
|
num_dec [0-9]+
|
||||||
num_hex 0[Xx][0-9a-fA-F]+
|
num_hex 0[Xx][0-9a-fA-F]+
|
||||||
space [ \t]+
|
space [ \t]+
|
||||||
|
path [^ \t\n]+
|
||||||
ident [_a-zA-Z][_a-zA-Z0-9]+
|
ident [_a-zA-Z][_a-zA-Z0-9]+
|
||||||
|
|
||||||
%%
|
%%
|
||||||
@ -97,6 +115,7 @@ mem_blk { return sample_part(PBF_TERM_DATA_SRC, 7); }
|
|||||||
mem_hops { return sample_part(PBF_TERM_DATA_SRC, 8); }
|
mem_hops { return sample_part(PBF_TERM_DATA_SRC, 8); }
|
||||||
uid { return sample(PBF_TERM_UID); }
|
uid { return sample(PBF_TERM_UID); }
|
||||||
gid { return sample(PBF_TERM_GID); }
|
gid { return sample(PBF_TERM_GID); }
|
||||||
|
cgroup { return sample_path(PBF_TERM_CGROUP); }
|
||||||
|
|
||||||
"==" { return operator(PBF_OP_EQ); }
|
"==" { return operator(PBF_OP_EQ); }
|
||||||
"!=" { return operator(PBF_OP_NEQ); }
|
"!=" { return operator(PBF_OP_NEQ); }
|
||||||
@ -155,7 +174,6 @@ hops3 { return constant(PERF_MEM_HOPS_3); }
|
|||||||
"," { return ','; }
|
"," { return ','; }
|
||||||
"||" { return BFT_LOGICAL_OR; }
|
"||" { return BFT_LOGICAL_OR; }
|
||||||
|
|
||||||
{ident} { return error("ident"); }
|
{path} { return path_or_error(); }
|
||||||
. { return error("input"); }
|
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -12,9 +12,13 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include "bpf-filter.h"
|
#include "bpf-filter.h"
|
||||||
|
#include "cgroup.h"
|
||||||
|
|
||||||
int perf_bpf_filter_lex(void);
|
int perf_bpf_filter_lex(void);
|
||||||
|
|
||||||
|
/* To indicate if the current term needs a pathname or not */
|
||||||
|
int perf_bpf_filter_needs_path;
|
||||||
|
|
||||||
static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
|
static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
|
||||||
char const *msg)
|
char const *msg)
|
||||||
{
|
{
|
||||||
@ -26,6 +30,7 @@ static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
|
|||||||
%union
|
%union
|
||||||
{
|
{
|
||||||
unsigned long num;
|
unsigned long num;
|
||||||
|
char *path;
|
||||||
struct {
|
struct {
|
||||||
enum perf_bpf_filter_term term;
|
enum perf_bpf_filter_term term;
|
||||||
int part;
|
int part;
|
||||||
@ -34,12 +39,13 @@ static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
|
|||||||
struct perf_bpf_filter_expr *expr;
|
struct perf_bpf_filter_expr *expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
%token BFT_SAMPLE BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR
|
%token BFT_SAMPLE BFT_SAMPLE_PATH BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR BFT_PATH
|
||||||
%type <expr> filter_term filter_expr
|
%type <expr> filter_term filter_expr
|
||||||
%destructor { free ($$); } <expr>
|
%destructor { free ($$); } <expr>
|
||||||
%type <sample> BFT_SAMPLE
|
%type <sample> BFT_SAMPLE BFT_SAMPLE_PATH
|
||||||
%type <op> BFT_OP
|
%type <op> BFT_OP
|
||||||
%type <num> BFT_NUM
|
%type <num> BFT_NUM
|
||||||
|
%type <path> BFT_PATH
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@ -81,5 +87,23 @@ BFT_SAMPLE BFT_OP BFT_NUM
|
|||||||
{
|
{
|
||||||
$$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3);
|
$$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
BFT_SAMPLE_PATH BFT_OP BFT_PATH
|
||||||
|
{
|
||||||
|
struct cgroup *cgrp;
|
||||||
|
unsigned long cgroup_id = 0;
|
||||||
|
|
||||||
|
if ($2 != PBF_OP_EQ && $2 != PBF_OP_NEQ) {
|
||||||
|
printf("perf_bpf_filter: cgroup accepts '==' or '!=' only\n");
|
||||||
|
YYERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
cgrp = cgroup__new($3, /*do_open=*/false);
|
||||||
|
if (cgrp && read_cgroup_id(cgrp) == 0)
|
||||||
|
cgroup_id = cgrp->id;
|
||||||
|
|
||||||
|
$$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, cgroup_id);
|
||||||
|
cgroup__put(cgrp);
|
||||||
|
}
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -45,7 +45,7 @@ enum perf_bpf_filter_term {
|
|||||||
__PBF_UNUSED_TERM18 = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */
|
__PBF_UNUSED_TERM18 = PBF_TERM_SAMPLE_START + 18, /* SAMPLE_REGS_INTR = 1U << 18 */
|
||||||
PBF_TERM_PHYS_ADDR = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */
|
PBF_TERM_PHYS_ADDR = PBF_TERM_SAMPLE_START + 19, /* SAMPLE_PHYS_ADDR = 1U << 19 */
|
||||||
__PBF_UNUSED_TERM20 = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */
|
__PBF_UNUSED_TERM20 = PBF_TERM_SAMPLE_START + 20, /* SAMPLE_AUX = 1U << 20 */
|
||||||
__PBF_UNUSED_TERM21 = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */
|
PBF_TERM_CGROUP = PBF_TERM_SAMPLE_START + 21, /* SAMPLE_CGROUP = 1U << 21 */
|
||||||
PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */
|
PBF_TERM_DATA_PAGE_SIZE = PBF_TERM_SAMPLE_START + 22, /* SAMPLE_DATA_PAGE_SIZE = 1U << 22 */
|
||||||
PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */
|
PBF_TERM_CODE_PAGE_SIZE = PBF_TERM_SAMPLE_START + 23, /* SAMPLE_CODE_PAGE_SIZE = 1U << 23 */
|
||||||
PBF_TERM_WEIGHT_STRUCT = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */
|
PBF_TERM_WEIGHT_STRUCT = PBF_TERM_SAMPLE_START + 24, /* SAMPLE_WEIGHT_STRUCT = 1U << 24 */
|
||||||
|
@ -93,6 +93,7 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
|
|||||||
BUILD_CHECK_SAMPLE(DATA_SRC);
|
BUILD_CHECK_SAMPLE(DATA_SRC);
|
||||||
BUILD_CHECK_SAMPLE(TRANSACTION);
|
BUILD_CHECK_SAMPLE(TRANSACTION);
|
||||||
BUILD_CHECK_SAMPLE(PHYS_ADDR);
|
BUILD_CHECK_SAMPLE(PHYS_ADDR);
|
||||||
|
BUILD_CHECK_SAMPLE(CGROUP);
|
||||||
BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE);
|
BUILD_CHECK_SAMPLE(DATA_PAGE_SIZE);
|
||||||
BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE);
|
BUILD_CHECK_SAMPLE(CODE_PAGE_SIZE);
|
||||||
BUILD_CHECK_SAMPLE(WEIGHT_STRUCT);
|
BUILD_CHECK_SAMPLE(WEIGHT_STRUCT);
|
||||||
@ -135,6 +136,8 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
|
|||||||
return kctx->data->weight.full;
|
return kctx->data->weight.full;
|
||||||
case PBF_TERM_PHYS_ADDR:
|
case PBF_TERM_PHYS_ADDR:
|
||||||
return kctx->data->phys_addr;
|
return kctx->data->phys_addr;
|
||||||
|
case PBF_TERM_CGROUP:
|
||||||
|
return kctx->data->cgroup;
|
||||||
case PBF_TERM_CODE_PAGE_SIZE:
|
case PBF_TERM_CODE_PAGE_SIZE:
|
||||||
return kctx->data->code_page_size;
|
return kctx->data->code_page_size;
|
||||||
case PBF_TERM_DATA_PAGE_SIZE:
|
case PBF_TERM_DATA_PAGE_SIZE:
|
||||||
@ -183,7 +186,6 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
|
|||||||
case __PBF_UNUSED_TERM16:
|
case __PBF_UNUSED_TERM16:
|
||||||
case __PBF_UNUSED_TERM18:
|
case __PBF_UNUSED_TERM18:
|
||||||
case __PBF_UNUSED_TERM20:
|
case __PBF_UNUSED_TERM20:
|
||||||
case __PBF_UNUSED_TERM21:
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,7 @@ struct perf_sample_data {
|
|||||||
u32 cpu;
|
u32 cpu;
|
||||||
} cpu_entry;
|
} cpu_entry;
|
||||||
u64 phys_addr;
|
u64 phys_addr;
|
||||||
|
u64 cgroup;
|
||||||
u64 data_page_size;
|
u64 data_page_size;
|
||||||
u64 code_page_size;
|
u64 code_page_size;
|
||||||
} __attribute__((__aligned__(64))) __attribute__((preserve_access_index));
|
} __attribute__((__aligned__(64))) __attribute__((preserve_access_index));
|
||||||
|
Loading…
Reference in New Issue
Block a user