From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 83ADC16DEBB; Fri, 21 Jun 2024 22:23:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008639; cv=none; b=X0nJXCRGsaXfY2GvWnz5wLWlc35tuCIUqV6Mdo2wmkVVFnZGUCfkzAZRgHer173ZgrxhvjBo9bLSzCeR6n2cGruI8gvh6sNx7pwshTCqWYUy2TCp9GODjgHkftfbqwCokO+eO0l/z+BOqpBbTjBmSfS0TYFs9U+296FGElI5MAc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008639; c=relaxed/simple; bh=zHc83XrbJTNe36n7sL4yUh7EnP4zcww8T8v44+CNjPg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ioa1a+7cfyWgc7ayh7sNHmi6WOu3gwK8BG13hqIHG1X2+gfkgQIw6TmIm1HMoQ13TF9zDeZNlOb9vjSwe+b39Tm8jprhAsrN6ZKZpUVUFVJRLd5rEJ/3ryRD3g567Tsuxx5CtGu5ea8zZa6kREb7LSiTA4zVFHZ/9UdmjBEKb4c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=npLgbE8J; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="npLgbE8J" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AC5ABC4AF0C; Fri, 21 Jun 2024 22:23:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008639; bh=zHc83XrbJTNe36n7sL4yUh7EnP4zcww8T8v44+CNjPg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=npLgbE8JUMm5uphArcqmOuAaG6566W/93P3wPAxwqze5cxlIIoBiHR4J4Y8+/m0yE IiKirw8srkGf4rBRjGWvkv0edm7xhZroyJwnkdooQLQHKP0MI35gmByGLH6+pS/T+z DgMZYxHR7WHN/QppVoRTpOFjwIhpKJM2G7daaxAEXBNdUsaNwDJ97ulDOSRyFRm4+2 aH2jDupGKIxrghqQgIbPzVOkcxvyjm3IVPDjO2mDU0ib/Z1C89bMVIAc7UcIQYwIUI FX/iC995e3AMBHJD3I/4jj2nxOnsDIboUeO2asjPBmP6fND5z+eg+Cb6Mbv+0UxdWo KpjHwME4TsV6w== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 1/8] perf bpf-filter: Make filters map a single entry hashmap Date: Fri, 21 Jun 2024 15:23:50 -0700 Message-ID: <20240621222357.717374-2-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" And the value is now an array. This is to support multiple filter entries in the map later. No functional changes intended. Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-filter.c | 81 ++++++++++++++------ tools/perf/util/bpf_skel/sample-filter.h | 1 + tools/perf/util/bpf_skel/sample_filter.bpf.c | 39 +++++----- 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 04f98b6bb291..2510832d83f9 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -93,71 +93,102 @@ static int check_sample_flags(struct evsel *evsel, str= uct perf_bpf_filter_expr * =20 int perf_bpf_filter__prepare(struct evsel *evsel) { - int i, x, y, fd; + int i, x, y, fd, ret; struct sample_filter_bpf *skel; struct bpf_program *prog; struct bpf_link *link; struct perf_bpf_filter_expr *expr; + struct perf_bpf_filter_entry *entry; + + entry =3D calloc(MAX_FILTERS, sizeof(*entry)); + if (entry =3D=3D NULL) + return -1; =20 skel =3D sample_filter_bpf__open_and_load(); if (!skel) { pr_err("Failed to load perf sample-filter BPF skeleton\n"); - return -1; + ret =3D -EPERM; + goto err; } =20 i =3D 0; fd =3D bpf_map__fd(skel->maps.filters); list_for_each_entry(expr, &evsel->bpf_filters, list) { - struct perf_bpf_filter_entry entry =3D { - .op =3D expr->op, - .part =3D expr->part, - .term =3D expr->term, - .value =3D expr->val, - }; + if (check_sample_flags(evsel, expr) < 0) { + ret =3D -EINVAL; + goto err; + } =20 - if (check_sample_flags(evsel, expr) < 0) - return -1; + if (i =3D=3D MAX_FILTERS) { + ret =3D -E2BIG; + goto err; + } =20 - bpf_map_update_elem(fd, &i, &entry, BPF_ANY); + entry[i].op =3D expr->op; + entry[i].part =3D expr->part; + entry[i].term =3D expr->term; + entry[i].value =3D expr->val; i++; =20 if (expr->op =3D=3D PBF_OP_GROUP_BEGIN) { struct perf_bpf_filter_expr *group; =20 list_for_each_entry(group, &expr->groups, list) { - struct perf_bpf_filter_entry group_entry =3D { - .op =3D group->op, - .part =3D group->part, - .term =3D group->term, - .value =3D group->val, - }; - bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY); + if (i =3D=3D MAX_FILTERS) { + ret =3D -E2BIG; + goto err; + } + + entry[i].op =3D group->op; + entry[i].part =3D group->part; + entry[i].term =3D group->term; + entry[i].value =3D group->val; i++; } =20 - memset(&entry, 0, sizeof(entry)); - entry.op =3D PBF_OP_GROUP_END; - bpf_map_update_elem(fd, &i, &entry, BPF_ANY); + if (i =3D=3D MAX_FILTERS) { + ret =3D -E2BIG; + goto err; + } + + entry[i].op =3D PBF_OP_GROUP_END; i++; } } =20 - if (i > MAX_FILTERS) { - pr_err("Too many filters: %d (max =3D %d)\n", i, MAX_FILTERS); - return -1; + if (i < MAX_FILTERS) { + /* to terminate the loop early */ + entry[i].op =3D PBF_OP_DONE; + i++; + } + + /* The filters map has only one entry for now */ + i =3D 0; + if (bpf_map_update_elem(fd, &i, entry, BPF_ANY) < 0) { + ret =3D -errno; + pr_err("Failed to update the filter map\n"); + goto err; } + prog =3D skel->progs.perf_sample_filter; for (x =3D 0; x < xyarray__max_x(evsel->core.fd); x++) { for (y =3D 0; y < xyarray__max_y(evsel->core.fd); y++) { link =3D bpf_program__attach_perf_event(prog, FD(evsel, x, y)); if (IS_ERR(link)) { pr_err("Failed to attach perf sample-filter program\n"); - return PTR_ERR(link); + ret =3D PTR_ERR(link); + goto err; } } } + free(entry); evsel->bpf_skel =3D skel; return 0; + +err: + free(entry); + sample_filter_bpf__destroy(skel); + return ret; } =20 int perf_bpf_filter__destroy(struct evsel *evsel) diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf= _skel/sample-filter.h index 350efa121026..bb6a1b91f1df 100644 --- a/tools/perf/util/bpf_skel/sample-filter.h +++ b/tools/perf/util/bpf_skel/sample-filter.h @@ -14,6 +14,7 @@ enum perf_bpf_filter_op { PBF_OP_AND, PBF_OP_GROUP_BEGIN, PBF_OP_GROUP_END, + PBF_OP_DONE, }; =20 enum perf_bpf_filter_term { diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util= /bpf_skel/sample_filter.bpf.c index f59985101973..0d56e52b922c 100644 --- a/tools/perf/util/bpf_skel/sample_filter.bpf.c +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c @@ -9,10 +9,10 @@ =20 /* BPF map that will be filled by user space */ struct filters { - __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(type, BPF_MAP_TYPE_HASH); __type(key, int); - __type(value, struct perf_bpf_filter_entry); - __uint(max_entries, MAX_FILTERS); + __type(value, struct perf_bpf_filter_entry[MAX_FILTERS]); + __uint(max_entries, 1); } filters SEC(".maps"); =20 int dropped; @@ -179,39 +179,39 @@ int perf_sample_filter(void *ctx) __u64 sample_data; int in_group =3D 0; int group_result =3D 0; - int i; + int i, k; =20 kctx =3D bpf_cast_to_kern_ctx(ctx); =20 - for (i =3D 0; i < MAX_FILTERS; i++) { - int key =3D i; /* needed for verifier :( */ + k =3D 0; + entry =3D bpf_map_lookup_elem(&filters, &k); + if (entry =3D=3D NULL) + goto drop; =20 - entry =3D bpf_map_lookup_elem(&filters, &key); - if (entry =3D=3D NULL) - break; - sample_data =3D perf_get_sample(kctx, entry); + for (i =3D 0; i < MAX_FILTERS; i++) { + sample_data =3D perf_get_sample(kctx, &entry[i]); =20 - switch (entry->op) { + switch (entry[i].op) { case PBF_OP_EQ: - CHECK_RESULT(sample_data, =3D=3D, entry->value) + CHECK_RESULT(sample_data, =3D=3D, entry[i].value) break; case PBF_OP_NEQ: - CHECK_RESULT(sample_data, !=3D, entry->value) + CHECK_RESULT(sample_data, !=3D, entry[i].value) break; case PBF_OP_GT: - CHECK_RESULT(sample_data, >, entry->value) + CHECK_RESULT(sample_data, >, entry[i].value) break; case PBF_OP_GE: - CHECK_RESULT(sample_data, >=3D, entry->value) + CHECK_RESULT(sample_data, >=3D, entry[i].value) break; case PBF_OP_LT: - CHECK_RESULT(sample_data, <, entry->value) + CHECK_RESULT(sample_data, <, entry[i].value) break; case PBF_OP_LE: - CHECK_RESULT(sample_data, <=3D, entry->value) + CHECK_RESULT(sample_data, <=3D, entry[i].value) break; case PBF_OP_AND: - CHECK_RESULT(sample_data, &, entry->value) + CHECK_RESULT(sample_data, &, entry[i].value) break; case PBF_OP_GROUP_BEGIN: in_group =3D 1; @@ -222,6 +222,9 @@ int perf_sample_filter(void *ctx) goto drop; in_group =3D 0; break; + case PBF_OP_DONE: + /* no failures so far, accept it */ + return 1; } } /* generate sample data */ --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9EBD816DEC7; Fri, 21 Jun 2024 22:23:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008639; cv=none; b=TF6XBltDuQvIj8+0GZI3dAfes0TK3qsSIJa+H+bdvfMxG8FwApHpa5DiV7yBJIV58TYU4p5Q+7nkyxe42idcq9p3Drdu7Lf16PjroukYraUq+FBJQAJ7N6SasPyfaey9CLliXDvSh0Hia11oF4RP631LQBhIPXiuKOJORcauEs8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008639; c=relaxed/simple; bh=bK4z5lAwoZAj2M39ibIP4DJKoadAB9ceXALPRrPLH64=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lO0KCnZKpfVKiExNysbVPle88YDriWF0dxTlGTDkEdZWMF84d4mZ4D36i/5531dk+GirySqpvTqz0IfLjBWjjeIzndMfxzxXkCxN8E2ommJ32mlEwLGNcnunx3DafKPS9whwQAOsfFkoICvstIWdBGcIsImJ6JB5IWsR07HYxMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Jvbfy8oc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Jvbfy8oc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2B6A3C4AF07; Fri, 21 Jun 2024 22:23:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008639; bh=bK4z5lAwoZAj2M39ibIP4DJKoadAB9ceXALPRrPLH64=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jvbfy8ocjyjK7dXgG4u0cQTF+9dDNFAvioa2jNwjEu/ycLpxwxeT3don0RyyphcaH McW5eiGqMuob/GhzfGJhSiQdJVbXdWzXHO0J1JuZfsP95F17RMfZhcqyGsPRaoR1Dx 9pkXrkQJTDwBUZjCXDyRoVdgLDF3pFBf+MSb0fKAsp/jJGMjwIicLnKpsuAjuCmWLS 6h8iiTEPsbW4+/AWuHuB+wKHRlnjF2rjIMpPlUkZqKgVtXQxmbvQYhibcXjfpwJve0 ixxvM26+HwlimQOUm666JuR3B6UkGyoNYCUzqEKBWrizgmL9DhNPfMDwZeyGTAu1JT WVQNsO5NyxDyA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 2/8] perf bpf-filter: Pass 'target' to perf_bpf_filter__prepare() Date: Fri, 21 Jun 2024 15:23:51 -0700 Message-ID: <20240621222357.717374-3-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This is needed to prepare target-specific actions in the later patch. We want to reuse the pinned BPF program and map for regular users to profile their own processes. Signed-off-by: Namhyung Kim --- tools/perf/builtin-record.c | 2 +- tools/perf/builtin-stat.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 2 +- tools/perf/util/bpf-filter.c | 2 +- tools/perf/util/bpf-filter.h | 6 ++++-- tools/perf/util/evlist.c | 5 +++-- tools/perf/util/evlist.h | 4 +++- tools/perf/util/python.c | 3 ++- 9 files changed, 17 insertions(+), 11 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 019305b94e5f..e855a7688008 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1389,7 +1389,7 @@ static int record__open(struct record *rec) "even with a suitable vmlinux or kallsyms file.\n\n"); } =20 - if (evlist__apply_filters(evlist, &pos)) { + if (evlist__apply_filters(evlist, &pos, &opts->target)) { pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", pos->filter ?: "BPF", evsel__name(pos), errno, str_error_r(errno, msg, sizeof(msg))); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 661832756a24..1f92445f7480 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -833,7 +833,7 @@ static int __run_perf_stat(int argc, const char **argv,= int run_idx) return -1; } =20 - if (evlist__apply_filters(evsel_list, &counter)) { + if (evlist__apply_filters(evsel_list, &counter, &target)) { pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", counter->filter, evsel__name(counter), errno, str_error_r(errno, msg, sizeof(msg))); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e8cbbf10d361..d1a06a88d693 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1055,7 +1055,7 @@ static int perf_top__start_counters(struct perf_top *= top) } } =20 - if (evlist__apply_filters(evlist, &counter)) { + if (evlist__apply_filters(evlist, &counter, &opts->target)) { pr_err("failed to set filter \"%s\" on event %s with %d (%s)\n", counter->filter ?: "BPF", evsel__name(counter), errno, str_error_r(errno, msg, sizeof(msg))); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index c42bc608954e..0f93ba83717d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -3959,7 +3959,7 @@ static int trace__run(struct trace *trace, int argc, = const char **argv) err =3D trace__expand_filters(trace, &evsel); if (err) goto out_delete_evlist; - err =3D evlist__apply_filters(evlist, &evsel); + err =3D evlist__apply_filters(evlist, &evsel, &trace->opts.target); if (err < 0) goto out_error_apply_filters; =20 diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 2510832d83f9..0b2eca56aa10 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -91,7 +91,7 @@ static int check_sample_flags(struct evsel *evsel, struct= perf_bpf_filter_expr * return -1; } =20 -int perf_bpf_filter__prepare(struct evsel *evsel) +int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target __= maybe_unused) { int i, x, y, fd, ret; struct sample_filter_bpf *skel; diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h index cd6764442c16..605a3d0226e0 100644 --- a/tools/perf/util/bpf-filter.h +++ b/tools/perf/util/bpf-filter.h @@ -16,6 +16,7 @@ struct perf_bpf_filter_expr { }; =20 struct evsel; +struct target; =20 #ifdef HAVE_BPF_SKEL struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filte= r_term term, @@ -23,7 +24,7 @@ struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(en= um perf_bpf_filter_term enum perf_bpf_filter_op op, unsigned long val); int perf_bpf_filter__parse(struct list_head *expr_head, const char *str); -int perf_bpf_filter__prepare(struct evsel *evsel); +int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target); int perf_bpf_filter__destroy(struct evsel *evsel); u64 perf_bpf_filter__lost_count(struct evsel *evsel); =20 @@ -34,7 +35,8 @@ static inline int perf_bpf_filter__parse(struct list_head= *expr_head __maybe_unu { return -EOPNOTSUPP; } -static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unu= sed) +static inline int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unu= sed, + struct target *target __maybe_unused) { return -EOPNOTSUPP; } diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 3a719edafc7a..1417f9a23083 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1086,7 +1086,8 @@ int evlist__create_maps(struct evlist *evlist, struct= target *target) return -1; } =20 -int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel) +int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel, + struct target *target) { struct evsel *evsel; int err =3D 0; @@ -1108,7 +1109,7 @@ int evlist__apply_filters(struct evlist *evlist, stru= ct evsel **err_evsel) * non-tracepoint events can have BPF filters. */ if (!list_empty(&evsel->bpf_filters)) { - err =3D perf_bpf_filter__prepare(evsel); + err =3D perf_bpf_filter__prepare(evsel, target); if (err) { *err_evsel =3D evsel; break; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index cb91dc9117a2..cccc34da5a02 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -20,6 +20,7 @@ struct pollfd; struct thread_map; struct perf_cpu_map; struct record_opts; +struct target; =20 /* * State machine of bkw_mmap_state: @@ -212,7 +213,8 @@ void evlist__enable_non_dummy(struct evlist *evlist); void evlist__set_selected(struct evlist *evlist, struct evsel *evsel); =20 int evlist__create_maps(struct evlist *evlist, struct target *target); -int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel); +int evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel, + struct target *target); =20 u64 __evlist__combined_sample_type(struct evlist *evlist); u64 evlist__combined_sample_type(struct evlist *evlist); diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 88f98f2772fb..5775c5c1f617 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -178,7 +178,8 @@ int bpf_counter__disable(struct evsel *evsel __maybe_un= used) =20 // not to drag util/bpf-filter.c #ifdef HAVE_BPF_SKEL -int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused) +int perf_bpf_filter__prepare(struct evsel *evsel __maybe_unused, + struct target *target __maybe_unused) { return 0; } --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 828C216EC18; Fri, 21 Jun 2024 22:24:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008640; cv=none; b=dmWzqZfYDXsQx9oWJ+smZmK1iNNtGXqPyXSir/FRpjmYm2PseV6ALicEhmai7Gtq3mCSmlnkpkGYG5j/Hq0kMLOj/aTSgLn0n0/fgLG3d6f73K2O+S0iEVxELtL38/RRGesyo1VWYe17nUeokbWMdj7QzzktX7BuxOEhHgosjb8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008640; c=relaxed/simple; bh=W5GZEcIk9twAOrRsPhPKS2FUMDyJH0v8fpPh0A03qEk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nObo4rmCtp7oM5mI3WgqP3fDxYBFZxgBT8jqMuC6XI3U78ddty0lPkMdtZkflRoQkIeqhE2TPoa+4d4VnphOoIwGWl4glFdO8+q6QZIcWJvbIwuodEgHL4QBruetZ3rM3+wlQfR5yOIe+8JRPkJvYx0TS4WQgh/5R2PYbNcf9mw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pdvMT9Xs; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pdvMT9Xs" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A1E18C4AF12; Fri, 21 Jun 2024 22:23:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008640; bh=W5GZEcIk9twAOrRsPhPKS2FUMDyJH0v8fpPh0A03qEk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pdvMT9XsB/8qClLenFuK8U2NqL4qKJlpMKh56rQgp1nuugQ4PyvmIh3ISOMwQ+udC E1cFLiRYSiJ+0p6Ttsk5LAIdPTweHOE/w07FHknLbPeQgSx/jsCF0CWmrdO9E5IXiV 9mAM2kUBf5/VtJ8je2QV8/LzHU2jJ8+NgEO9zOU7jOcGDxBFgBbbtVECiiyO6ttG+T ToaiBDUBgzExx1Tq7L0NvoddUH2UeNmSOIr7Z8v6YYcK7GnT7tA2nCC6vXkBbZpIX0 bFNUnibpDXLfhbbIP7PGGYsOHyIqanIOKdYKgM98y2YaOGt45Xhki/XQkssGen4kWE Y3TLPboyStMLg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 3/8] perf bpf-filter: Split per-task filter use case Date: Fri, 21 Jun 2024 15:23:52 -0700 Message-ID: <20240621222357.717374-4-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If the target is a list of tasks, it can use a shared hash map for filter expressions. The key of the filter map is an integer index like in an array. A separate pid_hash map is added to get the index for the filter map using the tgid. For system-wide mode including per-cpu or per-user targets are handled by the single entry map like before. Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-filter.c | 186 +++++++++++++++---- tools/perf/util/bpf_skel/sample-filter.h | 1 + tools/perf/util/bpf_skel/sample_filter.bpf.c | 21 +++ 3 files changed, 168 insertions(+), 40 deletions(-) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 0b2eca56aa10..5ec0e0955ec4 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -3,10 +3,13 @@ =20 #include #include +#include #include +#include =20 #include "util/debug.h" #include "util/evsel.h" +#include "util/target.h" =20 #include "util/bpf-filter.h" #include @@ -91,38 +94,17 @@ static int check_sample_flags(struct evsel *evsel, stru= ct perf_bpf_filter_expr * return -1; } =20 -int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target __= maybe_unused) +static int get_filter_entries(struct evsel *evsel, struct perf_bpf_filter_= entry *entry) { - int i, x, y, fd, ret; - struct sample_filter_bpf *skel; - struct bpf_program *prog; - struct bpf_link *link; + int i =3D 0; struct perf_bpf_filter_expr *expr; - struct perf_bpf_filter_entry *entry; - - entry =3D calloc(MAX_FILTERS, sizeof(*entry)); - if (entry =3D=3D NULL) - return -1; - - skel =3D sample_filter_bpf__open_and_load(); - if (!skel) { - pr_err("Failed to load perf sample-filter BPF skeleton\n"); - ret =3D -EPERM; - goto err; - } =20 - i =3D 0; - fd =3D bpf_map__fd(skel->maps.filters); list_for_each_entry(expr, &evsel->bpf_filters, list) { - if (check_sample_flags(evsel, expr) < 0) { - ret =3D -EINVAL; - goto err; - } + if (check_sample_flags(evsel, expr) < 0) + return -EINVAL; =20 - if (i =3D=3D MAX_FILTERS) { - ret =3D -E2BIG; - goto err; - } + if (i =3D=3D MAX_FILTERS) + return -E2BIG; =20 entry[i].op =3D expr->op; entry[i].part =3D expr->part; @@ -134,10 +116,8 @@ int perf_bpf_filter__prepare(struct evsel *evsel, stru= ct target *target __maybe_ struct perf_bpf_filter_expr *group; =20 list_for_each_entry(group, &expr->groups, list) { - if (i =3D=3D MAX_FILTERS) { - ret =3D -E2BIG; - goto err; - } + if (i =3D=3D MAX_FILTERS) + return -E2BIG; =20 entry[i].op =3D group->op; entry[i].part =3D group->part; @@ -146,10 +126,8 @@ int perf_bpf_filter__prepare(struct evsel *evsel, stru= ct target *target __maybe_ i++; } =20 - if (i =3D=3D MAX_FILTERS) { - ret =3D -E2BIG; - goto err; - } + if (i =3D=3D MAX_FILTERS) + return -E2BIG; =20 entry[i].op =3D PBF_OP_GROUP_END; i++; @@ -161,15 +139,143 @@ int perf_bpf_filter__prepare(struct evsel *evsel, st= ruct target *target __maybe_ entry[i].op =3D PBF_OP_DONE; i++; } + return 0; +} + +static int convert_to_tgid(int tid) +{ + char path[128]; + char *buf, *p, *q; + int tgid; + size_t len; + + scnprintf(path, sizeof(path), "%d/status", tid); + if (procfs__read_str(path, &buf, &len) < 0) + return -1; =20 - /* The filters map has only one entry for now */ - i =3D 0; - if (bpf_map_update_elem(fd, &i, entry, BPF_ANY) < 0) { - ret =3D -errno; - pr_err("Failed to update the filter map\n"); + p =3D strstr(buf, "Tgid:"); + if (p =3D=3D NULL) { + free(buf); + return -1; + } + + tgid =3D strtol(p + 6, &q, 0); + free(buf); + if (*q !=3D '\n') + return -1; + + return tgid; +} + +static int update_pid_hash(struct sample_filter_bpf *skel, struct evsel *e= vsel, + struct perf_bpf_filter_entry *entry) +{ + int filter_idx; + int nr, last; + int fd =3D bpf_map__fd(skel->maps.filters); + struct perf_thread_map *threads; + + /* Find the first available entry in the filters map */ + for (filter_idx =3D 0; filter_idx < MAX_FILTERS; filter_idx++) { + if (bpf_map_update_elem(fd, &filter_idx, entry, BPF_NOEXIST) =3D=3D 0) + break; + } + + if (filter_idx =3D=3D MAX_FILTERS) { + pr_err("Too many users for the filter map\n"); + return -EBUSY; + } + + threads =3D perf_evsel__threads(&evsel->core); + if (threads =3D=3D NULL) { + pr_err("Cannot get the thread list of the event\n"); + return -EINVAL; + } + + /* save the index to a hash map */ + fd =3D bpf_map__fd(skel->maps.pid_hash); + + last =3D -1; + nr =3D perf_thread_map__nr(threads); + for (int i =3D 0; i < nr; i++) { + int pid =3D perf_thread_map__pid(threads, i); + int tgid; + + /* it actually needs tgid, let's get tgid from /proc. */ + tgid =3D convert_to_tgid(pid); + if (tgid < 0) { + /* the thread may be dead, ignore. */ + continue; + } + + if (tgid =3D=3D last) + continue; + last =3D tgid; + + if (bpf_map_update_elem(fd, &tgid, &filter_idx, BPF_ANY) < 0) { + pr_err("Failed to update the pid hash\n"); + return -errno; + } + pr_debug("pid hash: %d -> %d\n", tgid, filter_idx); + } + return 0; +} + +int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target) +{ + int i, x, y, fd, ret; + struct sample_filter_bpf *skel =3D NULL; + struct bpf_program *prog; + struct bpf_link *link; + struct perf_bpf_filter_entry *entry; + bool needs_pid_hash =3D !target__has_cpu(target) && !target->uid_str; + + entry =3D calloc(MAX_FILTERS, sizeof(*entry)); + if (entry =3D=3D NULL) + return -1; + + ret =3D get_filter_entries(evsel, entry); + if (ret < 0) { + pr_err("Failed to process filter entries\n"); + goto err; + } + + skel =3D sample_filter_bpf__open(); + if (!skel) { + pr_err("Failed to open perf sample-filter BPF skeleton\n"); + ret =3D -EPERM; goto err; } =20 + if (needs_pid_hash) { + bpf_map__set_max_entries(skel->maps.filters, MAX_FILTERS); + bpf_map__set_max_entries(skel->maps.pid_hash, MAX_PIDS); + skel->rodata->use_pid_hash =3D 1; + } + + if (sample_filter_bpf__load(skel) < 0) { + pr_err("Failed to load perf sample-filter BPF skeleton\n"); + ret =3D -EPERM; + goto err; + } + + if (needs_pid_hash) { + /* The filters map is shared among other processes */ + ret =3D update_pid_hash(skel, evsel, entry); + if (ret < 0) + goto err; + } else { + i =3D 0; + fd =3D bpf_map__fd(skel->maps.filters); + + /* The filters map has only one entry in this case */ + if (bpf_map_update_elem(fd, &i, entry, BPF_ANY) < 0) { + ret =3D -errno; + pr_err("Failed to update the filter map\n"); + goto err; + } + } + prog =3D skel->progs.perf_sample_filter; for (x =3D 0; x < xyarray__max_x(evsel->core.fd); x++) { for (y =3D 0; y < xyarray__max_y(evsel->core.fd); y++) { diff --git a/tools/perf/util/bpf_skel/sample-filter.h b/tools/perf/util/bpf= _skel/sample-filter.h index bb6a1b91f1df..e666bfd5fbdd 100644 --- a/tools/perf/util/bpf_skel/sample-filter.h +++ b/tools/perf/util/bpf_skel/sample-filter.h @@ -2,6 +2,7 @@ #define PERF_UTIL_BPF_SKEL_SAMPLE_FILTER_H =20 #define MAX_FILTERS 64 +#define MAX_PIDS (16 * 1024) =20 /* supported filter operations */ enum perf_bpf_filter_op { diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util= /bpf_skel/sample_filter.bpf.c index 0d56e52b922c..c5273f06fa45 100644 --- a/tools/perf/util/bpf_skel/sample_filter.bpf.c +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c @@ -15,7 +15,16 @@ struct filters { __uint(max_entries, 1); } filters SEC(".maps"); =20 +/* tgid to filter index */ +struct pid_hash { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); +} pid_hash SEC(".maps"); + int dropped; +volatile const int use_pid_hash; =20 void *bpf_cast_to_kern_ctx(void *) __ksym; =20 @@ -184,6 +193,18 @@ int perf_sample_filter(void *ctx) kctx =3D bpf_cast_to_kern_ctx(ctx); =20 k =3D 0; + + if (use_pid_hash) { + int tgid =3D bpf_get_current_pid_tgid() >> 32; + int *idx; + + idx =3D bpf_map_lookup_elem(&pid_hash, &tgid); + if (idx) + k =3D *idx; + else + goto drop; + } + entry =3D bpf_map_lookup_elem(&filters, &k); if (entry =3D=3D NULL) goto drop; --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA26716F0E1; Fri, 21 Jun 2024 22:24:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008640; cv=none; b=eFffkbLUVR84OrNmDygjKZ2vvAkEoJ8W2M2OMMr0nZ4ZATM8MJO+l/Xd7Q/2HqMx+IST51m8SaF0UdCwHrQOy20Q5nHfZ3UeVwEIq5R+0CXtcoFvIVvO0tlC9ISR3qqRF2dBWlD0KVnMur88GQugDCrzlRUDT6oM29tkD9KkUiI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008640; c=relaxed/simple; bh=yA6a1kZaqADIwlQBycW+e66P07E/ZjEUB39NlBGm9g0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=IvWVlpOqUaOwRYgRc7EmV9JacUQsC35MumsGA2BwO+jQFoK92HS104jVKpH7VOMSzxpEgIa2Fq8Oddu95lEzmBbJo2KcQqFoGQMZd9D2ycUn8btwmBZ4pvA+NaJMxBuPW0ZRQFtpKBkeNidUf6co6So2PcSJLN7NLxgB2mlt0kg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m/NSWuwK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="m/NSWuwK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2617FC4AF1B; Fri, 21 Jun 2024 22:24:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008640; bh=yA6a1kZaqADIwlQBycW+e66P07E/ZjEUB39NlBGm9g0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=m/NSWuwKz+4xIRUZOXDZEyx17QI6/MjPRo++OeWRiOMzT2H3PHCrcaes0LDnVGaaZ iL/UsCPFx74nCwgJaYTolT0Xvi6YafLboTMOpUlR9q9yJ3tbYSkmsD7UTtzFWs02X0 I7v/6r2v2HpYZ8bF3A3EMWXw5b6+1vnK5gH1rIFxP3VyZl9d0SH9mVH466IjzuE9fO /0NzfSHLhjCwSc2d65Uhnp4tM6jzV1fXSpvt+JksaMeVmol0NZgxNyNwEq5daZL4Nu +PZtvgPYOsoVmGcUau4neClr9t6bnsEyiMWbnjIeuJvbg+JAHo4MUqDw47cCBOw9zm TXJEcz4qY+Vpw== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 4/8] perf bpf-filter: Support pin/unpin BPF object Date: Fri, 21 Jun 2024 15:23:53 -0700 Message-ID: <20240621222357.717374-5-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" And use the pinned objects for unprivileged users to profile their own tasks. The BPF objects need to be pinned in the BPF-fs by root first and it'll be handled in the later patch. Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-filter.c | 230 +++++++++++++++++++++++++++++------ tools/perf/util/bpf-filter.h | 13 ++ 2 files changed, 209 insertions(+), 34 deletions(-) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 5ec0e0955ec4..37ed6c48debf 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include +#include +#include +#include =20 #include #include @@ -23,6 +26,9 @@ #define __PERF_SAMPLE_TYPE(tt, st, opt) { tt, #st, opt } #define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PBF_TERM_##_st, PERF= _SAMPLE_##_st, opt) =20 +/* Index in the pinned 'filters' map. Should be released after use. */ +static int pinned_filter_idx =3D -1; + static const struct perf_sample_info { enum perf_bpf_filter_term type; const char *name; @@ -47,6 +53,8 @@ static const struct perf_sample_info { PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"), }; =20 +static int get_pinned_fd(const char *name); + static const struct perf_sample_info *get_sample_info(enum perf_bpf_filter= _term type) { size_t i; @@ -167,19 +175,26 @@ static int convert_to_tgid(int tid) return tgid; } =20 -static int update_pid_hash(struct sample_filter_bpf *skel, struct evsel *e= vsel, - struct perf_bpf_filter_entry *entry) +static int update_pid_hash(struct evsel *evsel, struct perf_bpf_filter_ent= ry *entry) { int filter_idx; - int nr, last; - int fd =3D bpf_map__fd(skel->maps.filters); + int fd, nr, last; struct perf_thread_map *threads; =20 + fd =3D get_pinned_fd("filters"); + if (fd < 0) { + pr_debug("cannot get fd for 'filters' map\n"); + return fd; + } + /* Find the first available entry in the filters map */ for (filter_idx =3D 0; filter_idx < MAX_FILTERS; filter_idx++) { - if (bpf_map_update_elem(fd, &filter_idx, entry, BPF_NOEXIST) =3D=3D 0) + if (bpf_map_update_elem(fd, &filter_idx, entry, BPF_NOEXIST) =3D=3D 0) { + pinned_filter_idx =3D filter_idx; break; + } } + close(fd); =20 if (filter_idx =3D=3D MAX_FILTERS) { pr_err("Too many users for the filter map\n"); @@ -193,7 +208,9 @@ static int update_pid_hash(struct sample_filter_bpf *sk= el, struct evsel *evsel, } =20 /* save the index to a hash map */ - fd =3D bpf_map__fd(skel->maps.pid_hash); + fd =3D get_pinned_fd("pid_hash"); + if (fd < 0) + return fd; =20 last =3D -1; nr =3D perf_thread_map__nr(threads); @@ -214,10 +231,12 @@ static int update_pid_hash(struct sample_filter_bpf *= skel, struct evsel *evsel, =20 if (bpf_map_update_elem(fd, &tgid, &filter_idx, BPF_ANY) < 0) { pr_err("Failed to update the pid hash\n"); - return -errno; + close(fd); + return -1; } pr_debug("pid hash: %d -> %d\n", tgid, filter_idx); } + close(fd); return 0; } =20 @@ -240,40 +259,48 @@ int perf_bpf_filter__prepare(struct evsel *evsel, str= uct target *target) goto err; } =20 - skel =3D sample_filter_bpf__open(); - if (!skel) { - pr_err("Failed to open perf sample-filter BPF skeleton\n"); - ret =3D -EPERM; - goto err; - } + if (needs_pid_hash && geteuid() !=3D 0) { + /* The filters map is shared among other processes */ + ret =3D update_pid_hash(evsel, entry); + if (ret < 0) + goto err; =20 - if (needs_pid_hash) { - bpf_map__set_max_entries(skel->maps.filters, MAX_FILTERS); - bpf_map__set_max_entries(skel->maps.pid_hash, MAX_PIDS); - skel->rodata->use_pid_hash =3D 1; + fd =3D get_pinned_fd("perf_sample_filter"); + if (fd < 0) { + ret =3D fd; + goto err; + } + + for (x =3D 0; x < xyarray__max_x(evsel->core.fd); x++) { + for (y =3D 0; y < xyarray__max_y(evsel->core.fd); y++) { + ret =3D ioctl(FD(evsel, x, y), PERF_EVENT_IOC_SET_BPF, fd); + if (ret < 0) { + pr_err("Failed to attach perf sample-filter\n"); + goto err; + } + } + } + + close(fd); + free(entry); + return 0; } =20 - if (sample_filter_bpf__load(skel) < 0) { + skel =3D sample_filter_bpf__open_and_load(); + if (!skel) { + ret =3D -errno; pr_err("Failed to load perf sample-filter BPF skeleton\n"); - ret =3D -EPERM; goto err; } =20 - if (needs_pid_hash) { - /* The filters map is shared among other processes */ - ret =3D update_pid_hash(skel, evsel, entry); - if (ret < 0) - goto err; - } else { - i =3D 0; - fd =3D bpf_map__fd(skel->maps.filters); - - /* The filters map has only one entry in this case */ - if (bpf_map_update_elem(fd, &i, entry, BPF_ANY) < 0) { - ret =3D -errno; - pr_err("Failed to update the filter map\n"); - goto err; - } + i =3D 0; + fd =3D bpf_map__fd(skel->maps.filters); + + /* The filters map has only one entry in this case */ + if (bpf_map_update_elem(fd, &i, entry, BPF_ANY) < 0) { + ret =3D -errno; + pr_err("Failed to update the filter map\n"); + goto err; } =20 prog =3D skel->progs.perf_sample_filter; @@ -306,6 +333,15 @@ int perf_bpf_filter__destroy(struct evsel *evsel) free(expr); } sample_filter_bpf__destroy(evsel->bpf_skel); + + if (pinned_filter_idx >=3D 0) { + int fd =3D get_pinned_fd("filters"); + + bpf_map_delete_elem(fd, &pinned_filter_idx); + pinned_filter_idx =3D -1; + close(fd); + } + return 0; } =20 @@ -349,3 +385,129 @@ int perf_bpf_filter__parse(struct list_head *expr_hea= d, const char *str) =20 return ret; } + +int perf_bpf_filter__pin(void) +{ + struct sample_filter_bpf *skel; + char *path =3D NULL; + int dir_fd, ret =3D -1; + + skel =3D sample_filter_bpf__open(); + if (!skel) { + ret =3D -errno; + pr_err("Failed to open perf sample-filter BPF skeleton\n"); + goto err; + } + + /* pinned program will use pid-hash */ + bpf_map__set_max_entries(skel->maps.filters, MAX_FILTERS); + bpf_map__set_max_entries(skel->maps.pid_hash, MAX_PIDS); + skel->rodata->use_pid_hash =3D 1; + + if (sample_filter_bpf__load(skel) < 0) { + ret =3D -errno; + pr_err("Failed to load perf sample-filter BPF skeleton\n"); + goto err; + } + + if (asprintf(&path, "%s/fs/bpf/%s", sysfs__mountpoint(), + PERF_BPF_FILTER_PIN_PATH) < 0) { + ret =3D -errno; + pr_err("Failed to allocate pathname in the BPF-fs\n"); + goto err; + } + + ret =3D bpf_object__pin(skel->obj, path); + if (ret < 0) { + pr_err("Failed to pin BPF filter objects\n"); + goto err; + } + + /* setup access permissions for the pinned objects */ + dir_fd =3D open(path, O_PATH); + if (dir_fd < 0) { + bpf_object__unpin(skel->obj, path); + ret =3D dir_fd; + goto err; + } + + /* BPF-fs root has the sticky bit */ + if (fchmodat(dir_fd, "..", 01755, 0) < 0) { + pr_debug("chmod for BPF-fs failed\n"); + ret =3D -errno; + goto err_close; + } + + /* perf_filter directory */ + if (fchmodat(dir_fd, ".", 0755, 0) < 0) { + pr_debug("chmod for perf_filter directory failed?\n"); + ret =3D -errno; + goto err_close; + } + + /* programs need write permission for some reason */ + if (fchmodat(dir_fd, "perf_sample_filter", 0777, 0) < 0) { + pr_debug("chmod for perf_sample_filter failed\n"); + ret =3D -errno; + } + /* maps */ + if (fchmodat(dir_fd, "filters", 0666, 0) < 0) { + pr_debug("chmod for filters failed\n"); + ret =3D -errno; + } + if (fchmodat(dir_fd, "pid_hash", 0666, 0) < 0) { + pr_debug("chmod for pid_hash failed\n"); + ret =3D -errno; + } + +err_close: + close(dir_fd); + +err: + free(path); + sample_filter_bpf__destroy(skel); + return ret; +} + +int perf_bpf_filter__unpin(void) +{ + struct sample_filter_bpf *skel; + char *path =3D NULL; + int ret =3D -1; + + skel =3D sample_filter_bpf__open_and_load(); + if (!skel) { + ret =3D -errno; + pr_err("Failed to open perf sample-filter BPF skeleton\n"); + goto err; + } + + if (asprintf(&path, "%s/fs/bpf/%s", sysfs__mountpoint(), + PERF_BPF_FILTER_PIN_PATH) < 0) { + ret =3D -errno; + pr_err("Failed to allocate pathname in the BPF-fs\n"); + goto err; + } + + ret =3D bpf_object__unpin(skel->obj, path); + +err: + free(path); + sample_filter_bpf__destroy(skel); + return ret; +} + +static int get_pinned_fd(const char *name) +{ + char *path =3D NULL; + int fd; + + if (asprintf(&path, "%s/fs/bpf/%s/%s", sysfs__mountpoint(), + PERF_BPF_FILTER_PIN_PATH, name) < 0) + return -1; + + fd =3D bpf_obj_get(path); + + free(path); + return fd; +} diff --git a/tools/perf/util/bpf-filter.h b/tools/perf/util/bpf-filter.h index 605a3d0226e0..916ed7770b73 100644 --- a/tools/perf/util/bpf-filter.h +++ b/tools/perf/util/bpf-filter.h @@ -18,6 +18,9 @@ struct perf_bpf_filter_expr { struct evsel; struct target; =20 +/* path in BPF-fs for the pinned program and maps */ +#define PERF_BPF_FILTER_PIN_PATH "perf_filter" + #ifdef HAVE_BPF_SKEL struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filte= r_term term, int part, @@ -27,6 +30,8 @@ int perf_bpf_filter__parse(struct list_head *expr_head, c= onst char *str); int perf_bpf_filter__prepare(struct evsel *evsel, struct target *target); int perf_bpf_filter__destroy(struct evsel *evsel); u64 perf_bpf_filter__lost_count(struct evsel *evsel); +int perf_bpf_filter__pin(void); +int perf_bpf_filter__unpin(void); =20 #else /* !HAVE_BPF_SKEL */ =20 @@ -48,5 +53,13 @@ static inline u64 perf_bpf_filter__lost_count(struct evs= el *evsel __maybe_unused { return 0; } +static inline int perf_bpf_filter__pin(void) +{ + return -EOPNOTSUPP; +} +static inline int perf_bpf_filter__unpin(void) +{ + return -EOPNOTSUPP; +} #endif /* HAVE_BPF_SKEL*/ #endif /* PERF_UTIL_BPF_FILTER_H */ --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7126816F273; Fri, 21 Jun 2024 22:24:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008641; cv=none; b=mEpC5CVtA18vTLcMKbloC6odDnl3Y/E5gJAEdnpGSJh35Bd2eQOMFiC+DT2dSVjng0Kr1gKbrXrt84zwwXUaWtLSSx3gMBMvHGGUh++TDon6niPDdqAowC8ptJ1fTbjVhZvEsp2p6KJ+teZ4UJYgU3PsCndfa702W1sJusfpBF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008641; c=relaxed/simple; bh=egp9ozSEksd36GD3FzpFfqRLU8xFzWxjV3v6ui5H4bw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=POr2ZeM3pLemsIW5MToQpcXSzwUfLti/r2/1KL71rF9ToDVmR672/RhEknJtC8MCXe7R+SO+bJudIIlAOWR2bwmuH2Ht2t7pnxm9Kd9HuI/V0Wco+Z8oqwHdc3Jps6DlXDWgkMHzSvQaBGmz7j5UM+v3PvODfOXUGjvRwCm0zHU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=McwWk0xM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="McwWk0xM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 97B1CC4AF07; Fri, 21 Jun 2024 22:24:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008640; bh=egp9ozSEksd36GD3FzpFfqRLU8xFzWxjV3v6ui5H4bw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=McwWk0xM5Glzt4DYz1iz26ZASeu7Kmt3Br7c9y4Gf0gYfzj4x30Io/28MNymdYQJH /qUguYSZtes0KFt0yoAC/Vsyh2ssxHInNAXTChAT2LdfMooMiY87CLug/i5eTleIeW kUbvKWF6G2YqIcm9QK+emQXb/Y8nviJ1wHq0q0wQFdIaLF4615MoqQ6bUtfjfUp/nb IUDFsZOblQjfOfY8+m7IAXoFQOzkSmDf/4nO4mymhVpA0hZHvDATG6yCv63BPXR1sB sxl+r1kpR+SyVojLPVsQoeYYPZcWVojdadzvI/alDPJsTLLmjWfWtKMrpQp1IxZ2Ht 2SzxAUFniSGrg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 5/8] perf bpf-filter: Support separate lost counts for each filter Date: Fri, 21 Jun 2024 15:23:54 -0700 Message-ID: <20240621222357.717374-6-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" As the BPF filter is shared between other processes, it should have its own counter for each invocation. Add a new array map (lost_count) to save the count using the same index as the filter. It should clear the count before running the filter. Signed-off-by: Namhyung Kim --- tools/perf/util/bpf-filter.c | 37 ++++++++++++++++++-- tools/perf/util/bpf_skel/sample_filter.bpf.c | 15 ++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/bpf-filter.c b/tools/perf/util/bpf-filter.c index 37ed6c48debf..c5eb0b7eec19 100644 --- a/tools/perf/util/bpf-filter.c +++ b/tools/perf/util/bpf-filter.c @@ -260,11 +260,23 @@ int perf_bpf_filter__prepare(struct evsel *evsel, str= uct target *target) } =20 if (needs_pid_hash && geteuid() !=3D 0) { + int zero =3D 0; + /* The filters map is shared among other processes */ ret =3D update_pid_hash(evsel, entry); if (ret < 0) goto err; =20 + fd =3D get_pinned_fd("dropped"); + if (fd < 0) { + ret =3D fd; + goto err; + } + + /* Reset the lost count */ + bpf_map_update_elem(fd, &pinned_filter_idx, &zero, BPF_ANY); + close(fd); + fd =3D get_pinned_fd("perf_sample_filter"); if (fd < 0) { ret =3D fd; @@ -347,9 +359,25 @@ int perf_bpf_filter__destroy(struct evsel *evsel) =20 u64 perf_bpf_filter__lost_count(struct evsel *evsel) { - struct sample_filter_bpf *skel =3D evsel->bpf_skel; + int count =3D 0; + + if (list_empty(&evsel->bpf_filters)) + return 0; + + if (pinned_filter_idx >=3D 0) { + int fd =3D get_pinned_fd("dropped"); + + bpf_map_lookup_elem(fd, &pinned_filter_idx, &count); + close(fd); + } else if (evsel->bpf_skel) { + struct sample_filter_bpf *skel =3D evsel->bpf_skel; + int fd =3D bpf_map__fd(skel->maps.dropped); + int idx =3D 0; =20 - return skel ? skel->bss->dropped : 0; + bpf_map_lookup_elem(fd, &idx, &count); + } + + return count; } =20 struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filte= r_term term, @@ -402,6 +430,7 @@ int perf_bpf_filter__pin(void) /* pinned program will use pid-hash */ bpf_map__set_max_entries(skel->maps.filters, MAX_FILTERS); bpf_map__set_max_entries(skel->maps.pid_hash, MAX_PIDS); + bpf_map__set_max_entries(skel->maps.dropped, MAX_FILTERS); skel->rodata->use_pid_hash =3D 1; =20 if (sample_filter_bpf__load(skel) < 0) { @@ -459,6 +488,10 @@ int perf_bpf_filter__pin(void) pr_debug("chmod for pid_hash failed\n"); ret =3D -errno; } + if (fchmodat(dir_fd, "dropped", 0666, 0) < 0) { + pr_debug("chmod for dropped failed\n"); + ret =3D -errno; + } =20 err_close: close(dir_fd); diff --git a/tools/perf/util/bpf_skel/sample_filter.bpf.c b/tools/perf/util= /bpf_skel/sample_filter.bpf.c index c5273f06fa45..4c75354b84fd 100644 --- a/tools/perf/util/bpf_skel/sample_filter.bpf.c +++ b/tools/perf/util/bpf_skel/sample_filter.bpf.c @@ -23,7 +23,14 @@ struct pid_hash { __uint(max_entries, 1); } pid_hash SEC(".maps"); =20 -int dropped; +/* tgid to filter index */ +struct lost_count { + __uint(type, BPF_MAP_TYPE_ARRAY); + __type(key, int); + __type(value, int); + __uint(max_entries, 1); +} dropped SEC(".maps"); + volatile const int use_pid_hash; =20 void *bpf_cast_to_kern_ctx(void *) __ksym; @@ -189,6 +196,7 @@ int perf_sample_filter(void *ctx) int in_group =3D 0; int group_result =3D 0; int i, k; + int *losts; =20 kctx =3D bpf_cast_to_kern_ctx(ctx); =20 @@ -252,7 +260,10 @@ int perf_sample_filter(void *ctx) return 1; =20 drop: - __sync_fetch_and_add(&dropped, 1); + losts =3D bpf_map_lookup_elem(&dropped, &k); + if (losts !=3D NULL) + __sync_fetch_and_add(losts, 1); + return 0; } =20 --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8863716F27B; Fri, 21 Jun 2024 22:24:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008641; cv=none; b=hKDtAtcqi9GEgvz76VYGTjqanvGGmFZzJ6X2n5qWoPNS2afEildwtvCM0GnGNF2C6xFnvWTMFOTCG7x550dwRPTfmH79rSFtBxKGRY2ilTDW3zt2VrcHVRAejWn5An7yRHiWbDZawm7xzZDvarHDWYCkZhZb11GvA/jA0QTic/s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008641; c=relaxed/simple; bh=r+axlpKvx5bW+LBnT30m1FMMrTx8JrNdVUOP6zjsi2E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q9hE+cF12DaptFZn0zXxmMql/fZ9m7/xnkd32XtOiU4d4iAstpcTXCq+7GlgX4ut5Pky4H1ROFLqUpNOCog3ZIJ0CXlj3zhi/9pH1IVHkb3lsIhqikuOeqWdeTDnahA7IsVVKtZgBGk8YYzd7feZsY4OOBKjCzz/LfF0eXlAoHc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UQr0grK1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UQr0grK1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1A1CBC4AF10; Fri, 21 Jun 2024 22:24:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008641; bh=r+axlpKvx5bW+LBnT30m1FMMrTx8JrNdVUOP6zjsi2E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UQr0grK1/vwcCmn6T4XIRH9Z0b4uviW4UgKm9JIEe8L5rGrFF7lwHbDsRudXycTZ7 ImYOOws+5XD8PGIc1lH8pItRADPD2VBgIc1z/yotrzGP4X6YZTjofFY89XcFwJzJO7 tsZxOh7Ax/GjtQ/lZiE6i+utd+gMPELFgyUlwh89j/wCkYgCqa0lpwDaef7QBu4lgW gR1SqRw2C8+HNRf9cUjMO8jujLJwdyWA2AU/yKTaPZCS4FEEqdCeXNgurDbwhaVns9 LHOLyFHFjDQSCuD/swXCcf7zp7yBdmwmuU8UyiL3zmcrsB6N3OQQw8po9G2B5MmSNQ PiivpnSeg/jSg== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 6/8] perf record: Fix a potential error handling issue Date: Fri, 21 Jun 2024 15:23:55 -0700 Message-ID: <20240621222357.717374-7-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The evlist is allocated at the beginning of cmd_record(). Also free-ing thread masks should be paired with record__init_thread_masks() which is called right before __cmd_record(). Let's change the order of these functions to release the resources correctly in case of errors. This is maybe fine as the process exits, but it might be a problem if it manages some system-wide resources that live longer than the process. Signed-off-by: Namhyung Kim --- tools/perf/builtin-record.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index e855a7688008..a473000f3599 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -4242,13 +4242,13 @@ int cmd_record(int argc, const char **argv) =20 err =3D __cmd_record(&record, argc, argv); out: - evlist__delete(rec->evlist); + record__free_thread_masks(rec, rec->nr_threads); + rec->nr_threads =3D 0; symbol__exit(); auxtrace_record__free(rec->itr); out_opts: - record__free_thread_masks(rec, rec->nr_threads); - rec->nr_threads =3D 0; evlist__close_control(rec->opts.ctl_fd, rec->opts.ctl_fd_ack, &rec->opts.= ctl_fd_close); + evlist__delete(rec->evlist); return err; } =20 --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 69E6A16F8ED; Fri, 21 Jun 2024 22:24:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008642; cv=none; b=IVNm0jEdz1Bst4KoRFsoowMHmqrAbKTk5cDiAzfBM9VGzEVD6kz6wszLrbUbQ1UYl0BiiV/hM0EmNp4C3KcUIhDqzgZKPHW6QBeSvaHV8woAj3Y6NgfHCKe26GLQIjTlVzc7KTRksCngMko28WZIZKX2JIpHbkMOWFFHGTowpKA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008642; c=relaxed/simple; bh=XXty6hGBDPkOM763yRelUV/ggPiZMfvcd7jwZYXzhas=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KntXKLImKDYTYMDj55YMeBE+LFbmOkb91X6B3Kn1fO3R29iNsefnJ9FdoAU5bT3enWaoFNxy5pHbrD/tJ3t7PKeuvI2nJ6Tc4qGif/WYjvwNnNvE+Crs6Xgq3TFUlYZOBUa3l0Yn4RfVCOEZYrcHvcAGKn+zUojav3SQKwmBG/Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mcFLeM4t; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mcFLeM4t" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8EA47C4AF0A; Fri, 21 Jun 2024 22:24:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008641; bh=XXty6hGBDPkOM763yRelUV/ggPiZMfvcd7jwZYXzhas=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mcFLeM4tjaAb+kjL8LDNZP8gQZrog+qTSG501UVW9bdzx/BZLb+3bAgGbUftMMPpP G3KBO4R+hM1i0fXmQgCm/rz5K3kXgDgKooCdWCOOgk3xWuwdhjj5DQbdsl2JHth9zo DIhPahqem2Ap5V2u/REFvR/AknY2v44Wj9ZiorJoAbGfuZE69cWRDzBdstF9/pd8qo dKZk0Mdyiclgou0KeIcnTmX0Xd4FORU68ugB6ybs6fyQ1a5pBF8JVBimL7qsxifRIw n+8haWjfGY94nV+ruSMZM/bpqB9hlTeQ1hIH79phLoLrweUdqub8VjrzpBaFNAKTEv wv4/HQF4nNw3w== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 7/8] perf record: Add --setup-filter option Date: Fri, 21 Jun 2024 15:23:56 -0700 Message-ID: <20240621222357.717374-8-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" To allow BPF filters for unprivileged users it needs to pin the BPF objects to BPF-fs first. Let's add a new option to pin and unpin the objects easily. I'm not sure 'perf record' is a right place to do this but I don't have a better idea right now. $ sudo perf record --setup-filter pin The above command would pin BPF program and maps for the filter when the system has BPF-fs (usually at /sys/fs/bpf/). To unpin the objects, users can run the following command (as root). $ sudo perf record --setup-filter unpin Signed-off-by: Namhyung Kim --- tools/perf/Documentation/perf-record.txt | 5 +++++ tools/perf/builtin-record.c | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Document= ation/perf-record.txt index d6532ed97c02..41e36b4dc765 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -828,6 +828,11 @@ filtered through the mask provided by -C option. only, as of now. So the applications built without the frame pointer might see bogus addresses. =20 +--setup-filter=3D:: + Prepare BPF filter to be used by regular users. The action should be + either "pin" or "unpin". The filter can be used after it's pinned. + + include::intel-hybrid.txt[] =20 SEE ALSO diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a473000f3599..e88dedc0391b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -171,6 +171,7 @@ struct record { bool timestamp_filename; bool timestamp_boundary; bool off_cpu; + const char *filter_action; struct switch_output switch_output; unsigned long long samples; unsigned long output_max_size; /* =3D 0: unlimited */ @@ -3557,6 +3558,8 @@ static struct option __record_options[] =3D { "write collected trace data into several data files using parallel = threads", record__parse_threads), OPT_BOOLEAN(0, "off-cpu", &record.off_cpu, "Enable off-cpu analysis"), + OPT_STRING(0, "setup-filter", &record.filter_action, "pin|unpin", + "BPF filter action"), OPT_END() }; =20 @@ -4086,6 +4089,18 @@ int cmd_record(int argc, const char **argv) pr_warning("WARNING: --timestamp-filename option is not available in par= allel streaming mode.\n"); } =20 + if (rec->filter_action) { + if (!strcmp(rec->filter_action, "pin")) + err =3D perf_bpf_filter__pin(); + else if (!strcmp(rec->filter_action, "unpin")) + err =3D perf_bpf_filter__unpin(); + else { + pr_warning("Unknown BPF filter action: %s\n", rec->filter_action); + err =3D -EINVAL; + } + goto out_opts; + } + /* * Allow aliases to facilitate the lookup of symbols for address * filters. Refer to auxtrace_parse_filters(). --=20 2.45.2.741.gdbec12cfda-goog From nobody Fri Dec 19 15:48:32 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C596816F907; Fri, 21 Jun 2024 22:24:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008642; cv=none; b=T6mdvpaJCh9YjKWvjy5KgXTSOg7m3Df4sN7mnoAB3TGxbeutrtMjpJ5amylgVZbkTYFNA1ad4HJ9/drvKWLut6R36CXxP46fHvSLRXc6yvwinCBe+gIUqS7WRVPlyXVvoe0cV8V1ZU8sXoKEf+4mn0vH/jxhF4BHnCQYilqyjk4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719008642; c=relaxed/simple; bh=atSs/tRSRRAIPe/BSsP+YIRgCS9mtgue7bFyinAh7kw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=uDtf53IPoFl2aGIvjLoTW+CpKceB4afAkKucs5WZctRolzHacSSSI8+QO5PcVdzdlAcqs+kPTeQg2theBIyzRo41oDxvjZwnHFQegmeew7MDrIpVDWuzlBtTyFrtm0l0caS/ipledFi2VXtzph2Wbx+n+A5iTE3s7PHz4e2WPkM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Oi/ROPRI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Oi/ROPRI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1209CC4AF0C; Fri, 21 Jun 2024 22:24:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1719008642; bh=atSs/tRSRRAIPe/BSsP+YIRgCS9mtgue7bFyinAh7kw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Oi/ROPRIQ6aaqy3ukSpzi+iy26Z3fMt4gV5N+sh2qtcqGMg+iXME3OE4221mSkFD1 Vi5DF5vnX0XfIhZPzQWazmN4/Cj3rABdaax6dM5ON0CvQWSWgXMRVgtFjq1lJApuQJ gzb3RNiEK+7T+63SWdhrAQoVCoOgBYnHQFlMgTDLOKgCm+s+1MBLRqO+KmJdzjYt5P mrHYLM7fMZe4OcPuQ8DZKDGDUqyLZ6P/4Fno+TgQ4s+rJo+IVlphLDKFkrEZ5qWExz d9JMF+yBLcgfieuTcB6Qr1Dsye4nYkRpuGoq78NyxRvR+UO+Cej9LhiRBT6ZvxB2mu U3JOyN9y1kXyA== From: Namhyung Kim To: Arnaldo Carvalho de Melo , Ian Rogers , Kan Liang Cc: Jiri Olsa , Adrian Hunter , Peter Zijlstra , Ingo Molnar , LKML , linux-perf-users@vger.kernel.org Subject: [PATCH 8/8] perf test: Update sample filtering test Date: Fri, 21 Jun 2024 15:23:57 -0700 Message-ID: <20240621222357.717374-9-namhyung@kernel.org> X-Mailer: git-send-email 2.45.2.741.gdbec12cfda-goog In-Reply-To: <20240621222357.717374-1-namhyung@kernel.org> References: <20240621222357.717374-1-namhyung@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Now it can run the BPF filtering test with normal user if the BPF objects are pinned by 'sudo perf record --setup-filter pin'. Let's update the test case to verify the behavior. It'll skip the test if the filter check is failed from a normal user, but it shows a message how to set up the filters. First, run the test as a normal user and it fails. $ perf test -vv filtering 95: perf record sample filtering (by BPF) tests: --- start --- test child forked, pid 425677 Checking BPF-filter privilege try 'sudo perf record --setup-filter pin' first. <<<--- here bpf-filter test [Skipped permission] ---- end(-2) ---- 95: perf record sample filtering (by BPF) tests : Sk= ip According to the message, run the perf record command to pin the BPF objects. $ sudo perf record --setup-filter pin And re-run the test as a normal user. $ perf test -vv filtering 95: perf record sample filtering (by BPF) tests: --- start --- test child forked, pid 424486 Checking BPF-filter privilege Basic bpf-filter test Basic bpf-filter test [Success] Failing bpf-filter test Error: task-clock event does not have PERF_SAMPLE_CPU Failing bpf-filter test [Success] Group bpf-filter test Error: task-clock event does not have PERF_SAMPLE_CPU Error: task-clock event does not have PERF_SAMPLE_CODE_PAGE_SIZE Group bpf-filter test [Success] ---- end(0) ---- 95: perf record sample filtering (by BPF) tests : Ok Signed-off-by: Namhyung Kim --- tools/perf/tests/shell/record_bpf_filter.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tools/perf/tests/shell/record_bpf_filter.sh b/tools/perf/tests= /shell/record_bpf_filter.sh index 31c593966e8c..c5882d620db7 100755 --- a/tools/perf/tests/shell/record_bpf_filter.sh +++ b/tools/perf/tests/shell/record_bpf_filter.sh @@ -22,15 +22,16 @@ trap trap_cleanup EXIT TERM INT test_bpf_filter_priv() { echo "Checking BPF-filter privilege" =20 - if [ "$(id -u)" !=3D 0 ] - then - echo "bpf-filter test [Skipped permission]" - err=3D2 - return - fi if ! perf record -e task-clock --filter 'period > 1' \ -o /dev/null --quiet true 2>&1 then + if [ "$(id -u)" !=3D 0 ] + then + echo "try 'sudo perf record --setup-filter pin' first." + echo "bpf-filter test [Skipped permission]" + err=3D2 + return + fi echo "bpf-filter test [Skipped missing BPF support]" err=3D2 return --=20 2.45.2.741.gdbec12cfda-goog