* [PATCH v4 0/8] perf trace: Augment enum arguments with BTF
@ 2024-07-05 9:42 Howard Chu
2024-07-05 9:42 ` [PATCH v5 1/8] perf trace: Fix iteration of syscall ids in syscalltbl->entries Howard Chu
` (7 more replies)
0 siblings, 8 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel
Changes in v5:
- Use hardcoded landlock structs and macros for landlock.c workload to
make this build in older systems.
Changes in v4:
- Fix landlock workload's build error.
Changes in v3:
- Add trace__btf_scnprintf() helper function
- Remove is_enum memeber in struct syscall_arg_fmt, replace it with
btf_is_enum()
- Add syscall_arg_fmt__cache_btf_enum() to cache btf_type only
- Resolve NO_LIBBPF=1 build error
- Skip BTF augmentation test if landlock_add_rule syscall and LIBBPF are not
available
- Rename landlock.c workload, add a comment to landlock.c workload
- Change the way of skipping 'enum ' prefix
- Add type_name member to struct syscall_arg
Changes in v2:
- Add trace_btf_enum regression test, and landlock workload
v1:
In this patch, BTF is used to turn enum value to the corresponding
enum variable name. There is only one system call that uses enum value
as its argument, that is `landlock_add_rule()`.
Enum arguments of non-syscall tracepoints can also be augmented, for
instance timer:hrtimer_start and timer:hrtimer_init's 'mode' argument.
Arnaldo Carvalho de Melo (2):
perf trace: Introduce trace__btf_scnprintf()
perf trace: Remove arg_fmt->is_enum, we can get that from the BTF type
Howard Chu (6):
perf trace: Fix iteration of syscall ids in syscalltbl->entries
perf trace: BTF-based enum pretty printing for syscall args
perf trace: Augment non-syscall tracepoints with enum arguments with
BTF
perf trace: Filter enum arguments with enum names
perf test: Add landlock workload
perf test trace_btf_enum: Add regression test for the BTF augmentation
of enums in 'perf trace'
tools/perf/builtin-trace.c | 229 ++++++++++++++++++++---
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/shell/trace_btf_enum.sh | 61 ++++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 +
tools/perf/tests/workloads/landlock.c | 66 +++++++
tools/perf/trace/beauty/beauty.h | 1 +
tools/perf/util/syscalltbl.c | 7 +
tools/perf/util/syscalltbl.h | 1 +
9 files changed, 345 insertions(+), 24 deletions(-)
create mode 100755 tools/perf/tests/shell/trace_btf_enum.sh
create mode 100644 tools/perf/tests/workloads/landlock.c
--
2.45.2
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v5 1/8] perf trace: Fix iteration of syscall ids in syscalltbl->entries
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args Howard Chu
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
This is a bug found when implementing pretty-printing for the
landlock_add_rule system call, I decided to send this patch separately
because this is a serious bug that should be fixed fast.
I wrote a test program to do landlock_add_rule syscall in a loop,
yet perf trace -e landlock_add_rule freezes, giving no output.
This bug is introduced by the false understanding of the variable "key"
below:
```
for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
struct syscall *sc = trace__syscall_info(trace, NULL, key);
...
}
```
The code above seems right at the beginning, but when looking at
syscalltbl.c, I found these lines:
```
for (i = 0; i <= syscalltbl_native_max_id; ++i)
if (syscalltbl_native[i])
++nr_entries;
entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries);
...
for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) {
if (syscalltbl_native[i]) {
entries[j].name = syscalltbl_native[i];
entries[j].id = i;
++j;
}
}
```
meaning the key is merely an index to traverse the syscall table,
instead of the actual syscall id for this particular syscall.
So if one uses key to do trace__syscall_info(trace, NULL, key), because
key only goes up to trace->sctbl->syscalls.nr_entries, for example, on
my X86_64 machine, this number is 373, it will end up neglecting all
the rest of the syscall, in my case, everything after `rseq`, because
the traversal will stop at 373, and `rseq` is the last syscall whose id
is lower than 373
in tools/perf/arch/x86/include/generated/asm/syscalls_64.c:
```
...
[334] = "rseq",
[424] = "pidfd_send_signal",
...
```
The reason why the key is scrambled but perf trace works well is that
key is used in trace__syscall_info(trace, NULL, key) to do
trace->syscalls.table[id], this makes sure that the struct syscall returned
actually has an id the same value as key, making the later bpf_prog
matching all correct.
After fixing this bug, I can do perf trace on 38 more syscalls, and
because more syscalls are visible, we get 8 more syscalls that can be
augmented.
before:
perf $ perf trace -vv --max-events=1 |& grep Reusing
Reusing "open" BPF sys_enter augmenter for "stat"
Reusing "open" BPF sys_enter augmenter for "lstat"
Reusing "open" BPF sys_enter augmenter for "access"
Reusing "connect" BPF sys_enter augmenter for "accept"
Reusing "sendto" BPF sys_enter augmenter for "recvfrom"
Reusing "connect" BPF sys_enter augmenter for "bind"
Reusing "connect" BPF sys_enter augmenter for "getsockname"
Reusing "connect" BPF sys_enter augmenter for "getpeername"
Reusing "open" BPF sys_enter augmenter for "execve"
Reusing "open" BPF sys_enter augmenter for "truncate"
Reusing "open" BPF sys_enter augmenter for "chdir"
Reusing "open" BPF sys_enter augmenter for "mkdir"
Reusing "open" BPF sys_enter augmenter for "rmdir"
Reusing "open" BPF sys_enter augmenter for "creat"
Reusing "open" BPF sys_enter augmenter for "link"
Reusing "open" BPF sys_enter augmenter for "unlink"
Reusing "open" BPF sys_enter augmenter for "symlink"
Reusing "open" BPF sys_enter augmenter for "readlink"
Reusing "open" BPF sys_enter augmenter for "chmod"
Reusing "open" BPF sys_enter augmenter for "chown"
Reusing "open" BPF sys_enter augmenter for "lchown"
Reusing "open" BPF sys_enter augmenter for "mknod"
Reusing "open" BPF sys_enter augmenter for "statfs"
Reusing "open" BPF sys_enter augmenter for "pivot_root"
Reusing "open" BPF sys_enter augmenter for "chroot"
Reusing "open" BPF sys_enter augmenter for "acct"
Reusing "open" BPF sys_enter augmenter for "swapon"
Reusing "open" BPF sys_enter augmenter for "swapoff"
Reusing "open" BPF sys_enter augmenter for "delete_module"
Reusing "open" BPF sys_enter augmenter for "setxattr"
Reusing "open" BPF sys_enter augmenter for "lsetxattr"
Reusing "openat" BPF sys_enter augmenter for "fsetxattr"
Reusing "open" BPF sys_enter augmenter for "getxattr"
Reusing "open" BPF sys_enter augmenter for "lgetxattr"
Reusing "openat" BPF sys_enter augmenter for "fgetxattr"
Reusing "open" BPF sys_enter augmenter for "listxattr"
Reusing "open" BPF sys_enter augmenter for "llistxattr"
Reusing "open" BPF sys_enter augmenter for "removexattr"
Reusing "open" BPF sys_enter augmenter for "lremovexattr"
Reusing "fsetxattr" BPF sys_enter augmenter for "fremovexattr"
Reusing "open" BPF sys_enter augmenter for "mq_open"
Reusing "open" BPF sys_enter augmenter for "mq_unlink"
Reusing "fsetxattr" BPF sys_enter augmenter for "add_key"
Reusing "fremovexattr" BPF sys_enter augmenter for "request_key"
Reusing "fremovexattr" BPF sys_enter augmenter for "inotify_add_watch"
Reusing "fremovexattr" BPF sys_enter augmenter for "mkdirat"
Reusing "fremovexattr" BPF sys_enter augmenter for "mknodat"
Reusing "fremovexattr" BPF sys_enter augmenter for "fchownat"
Reusing "fremovexattr" BPF sys_enter augmenter for "futimesat"
Reusing "fremovexattr" BPF sys_enter augmenter for "newfstatat"
Reusing "fremovexattr" BPF sys_enter augmenter for "unlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "linkat"
Reusing "open" BPF sys_enter augmenter for "symlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "readlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "fchmodat"
Reusing "fremovexattr" BPF sys_enter augmenter for "faccessat"
Reusing "fremovexattr" BPF sys_enter augmenter for "utimensat"
Reusing "connect" BPF sys_enter augmenter for "accept4"
Reusing "fremovexattr" BPF sys_enter augmenter for "name_to_handle_at"
Reusing "fremovexattr" BPF sys_enter augmenter for "renameat2"
Reusing "open" BPF sys_enter augmenter for "memfd_create"
Reusing "fremovexattr" BPF sys_enter augmenter for "execveat"
Reusing "fremovexattr" BPF sys_enter augmenter for "statx"
after
perf $ perf trace -vv --max-events=1 |& grep Reusing
Reusing "open" BPF sys_enter augmenter for "stat"
Reusing "open" BPF sys_enter augmenter for "lstat"
Reusing "open" BPF sys_enter augmenter for "access"
Reusing "connect" BPF sys_enter augmenter for "accept"
Reusing "sendto" BPF sys_enter augmenter for "recvfrom"
Reusing "connect" BPF sys_enter augmenter for "bind"
Reusing "connect" BPF sys_enter augmenter for "getsockname"
Reusing "connect" BPF sys_enter augmenter for "getpeername"
Reusing "open" BPF sys_enter augmenter for "execve"
Reusing "open" BPF sys_enter augmenter for "truncate"
Reusing "open" BPF sys_enter augmenter for "chdir"
Reusing "open" BPF sys_enter augmenter for "mkdir"
Reusing "open" BPF sys_enter augmenter for "rmdir"
Reusing "open" BPF sys_enter augmenter for "creat"
Reusing "open" BPF sys_enter augmenter for "link"
Reusing "open" BPF sys_enter augmenter for "unlink"
Reusing "open" BPF sys_enter augmenter for "symlink"
Reusing "open" BPF sys_enter augmenter for "readlink"
Reusing "open" BPF sys_enter augmenter for "chmod"
Reusing "open" BPF sys_enter augmenter for "chown"
Reusing "open" BPF sys_enter augmenter for "lchown"
Reusing "open" BPF sys_enter augmenter for "mknod"
Reusing "open" BPF sys_enter augmenter for "statfs"
Reusing "open" BPF sys_enter augmenter for "pivot_root"
Reusing "open" BPF sys_enter augmenter for "chroot"
Reusing "open" BPF sys_enter augmenter for "acct"
Reusing "open" BPF sys_enter augmenter for "swapon"
Reusing "open" BPF sys_enter augmenter for "swapoff"
Reusing "open" BPF sys_enter augmenter for "delete_module"
Reusing "open" BPF sys_enter augmenter for "setxattr"
Reusing "open" BPF sys_enter augmenter for "lsetxattr"
Reusing "openat" BPF sys_enter augmenter for "fsetxattr"
Reusing "open" BPF sys_enter augmenter for "getxattr"
Reusing "open" BPF sys_enter augmenter for "lgetxattr"
Reusing "openat" BPF sys_enter augmenter for "fgetxattr"
Reusing "open" BPF sys_enter augmenter for "listxattr"
Reusing "open" BPF sys_enter augmenter for "llistxattr"
Reusing "open" BPF sys_enter augmenter for "removexattr"
Reusing "open" BPF sys_enter augmenter for "lremovexattr"
Reusing "fsetxattr" BPF sys_enter augmenter for "fremovexattr"
Reusing "open" BPF sys_enter augmenter for "mq_open"
Reusing "open" BPF sys_enter augmenter for "mq_unlink"
Reusing "fsetxattr" BPF sys_enter augmenter for "add_key"
Reusing "fremovexattr" BPF sys_enter augmenter for "request_key"
Reusing "fremovexattr" BPF sys_enter augmenter for "inotify_add_watch"
Reusing "fremovexattr" BPF sys_enter augmenter for "mkdirat"
Reusing "fremovexattr" BPF sys_enter augmenter for "mknodat"
Reusing "fremovexattr" BPF sys_enter augmenter for "fchownat"
Reusing "fremovexattr" BPF sys_enter augmenter for "futimesat"
Reusing "fremovexattr" BPF sys_enter augmenter for "newfstatat"
Reusing "fremovexattr" BPF sys_enter augmenter for "unlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "linkat"
Reusing "open" BPF sys_enter augmenter for "symlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "readlinkat"
Reusing "fremovexattr" BPF sys_enter augmenter for "fchmodat"
Reusing "fremovexattr" BPF sys_enter augmenter for "faccessat"
Reusing "fremovexattr" BPF sys_enter augmenter for "utimensat"
Reusing "connect" BPF sys_enter augmenter for "accept4"
Reusing "fremovexattr" BPF sys_enter augmenter for "name_to_handle_at"
Reusing "fremovexattr" BPF sys_enter augmenter for "renameat2"
Reusing "open" BPF sys_enter augmenter for "memfd_create"
Reusing "fremovexattr" BPF sys_enter augmenter for "execveat"
Reusing "fremovexattr" BPF sys_enter augmenter for "statx"
TL;DR:
These are the new syscalls that can be augmented
Reusing "openat" BPF sys_enter augmenter for "open_tree"
Reusing "openat" BPF sys_enter augmenter for "openat2"
Reusing "openat" BPF sys_enter augmenter for "mount_setattr"
Reusing "openat" BPF sys_enter augmenter for "move_mount"
Reusing "open" BPF sys_enter augmenter for "fsopen"
Reusing "openat" BPF sys_enter augmenter for "fspick"
Reusing "openat" BPF sys_enter augmenter for "faccessat2"
Reusing "openat" BPF sys_enter augmenter for "fchmodat2"
as for the perf trace output:
before
perf $ perf trace -e faccessat2 --max-events=1
[no output]
after
perf $ ./perf trace -e faccessat2 --max-events=1
0.000 ( 0.037 ms): waybar/958 faccessat2(dfd: 40, filename: "uevent") = 0
P.S. The reason why this bug was not found in the past five years is
probably because it only happens to the newer syscalls whose id is
greater, for instance, faccessat2 of id 439, which not a lot of people
care about when using perf trace.
Commiter notes:
That and the fact that the BPF code was hidden before having to use -e,
that got changed kinda recently when we switched to using BPF skels for
augmenting syscalls in 'perf trace':
⬢[acme@toolbox perf-tools-next]$ git log --oneline tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
a9f4c6c999008c92 perf trace: Collect sys_nanosleep first argument
29d16de26df17e94 perf augmented_raw_syscalls.bpf: Move 'struct timespec64' to vmlinux.h
5069211e2f0b47e7 perf trace: Use the right bpf_probe_read(_str) variant for reading user data
33b725ce7b988756 perf trace: Avoid compile error wrt redefining bool
7d9642311b6d9d31 perf bpf augmented_raw_syscalls: Add an assert to make sure sizeof(augmented_arg->value) is a power of two.
262b54b6c9396823 perf bpf augmented_raw_syscalls: Add an assert to make sure sizeof(saddr) is a power of two.
1836480429d173c0 perf bpf_skel augmented_raw_syscalls: Cap the socklen parameter using &= sizeof(saddr)
cd2cece61ac5f900 perf trace: Tidy comments related to BPF + syscall augmentation
5e6da6be3082f77b perf trace: Migrate BPF augmentation to use a skeleton
⬢[acme@toolbox perf-tools-next]$
⬢[acme@toolbox perf-tools-next]$ git show --oneline --pretty=reference 5e6da6be3082f77b | head -1
5e6da6be3082f77b (perf trace: Migrate BPF augmentation to use a skeleton, 2023-08-10)
⬢[acme@toolbox perf-tools-next]$
I.e. from August, 2023.
One had as well to ask for BUILD_BPF_SKEL=1, which now is default if all
it needs is available on the system.
I simplified the code to not expose the 'struct syscall' outside of
tools/perf/util/syscalltbl.c, instead providing a function to go from
the index to the syscall id:
int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx);
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/lkml/ZmhlAxbVcAKoPTg8@x1
Link: https://lore.kernel.org/r/20240624181345.124764-2-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 14 +++++++-------
tools/perf/util/syscalltbl.c | 7 +++++++
tools/perf/util/syscalltbl.h | 1 +
3 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index a547ccfa92c9..8449f2beb54d 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -3354,8 +3354,6 @@ static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id)
static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *sc)
{
struct tep_format_field *field, *candidate_field;
- int id;
-
/*
* We're only interested in syscalls that have a pointer:
*/
@@ -3367,7 +3365,8 @@ static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace
return NULL;
try_to_find_pair:
- for (id = 0; id < trace->sctbl->syscalls.nr_entries; ++id) {
+ for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) {
+ int id = syscalltbl__id_at_idx(trace->sctbl, i);
struct syscall *pair = trace__syscall_info(trace, NULL, id);
struct bpf_program *pair_prog;
bool is_candidate = false;
@@ -3456,10 +3455,10 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace)
{
int map_enter_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_enter);
int map_exit_fd = bpf_map__fd(trace->skel->maps.syscalls_sys_exit);
- int err = 0, key;
+ int err = 0;
- for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
- int prog_fd;
+ for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) {
+ int prog_fd, key = syscalltbl__id_at_idx(trace->sctbl, i);
if (!trace__syscall_enabled(trace, key))
continue;
@@ -3505,7 +3504,8 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace)
* first and second arg (this one on the raw_syscalls:sys_exit prog
* array tail call, then that one will be used.
*/
- for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
+ for (int i = 0; i < trace->sctbl->syscalls.nr_entries; ++i) {
+ int key = syscalltbl__id_at_idx(trace->sctbl, i);
struct syscall *sc = trace__syscall_info(trace, NULL, key);
struct bpf_program *pair_prog;
int prog_fd;
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c
index 63be7b58761d..0dd26b991b3f 100644
--- a/tools/perf/util/syscalltbl.c
+++ b/tools/perf/util/syscalltbl.c
@@ -123,6 +123,13 @@ int syscalltbl__id(struct syscalltbl *tbl, const char *name)
return sc ? sc->id : -1;
}
+int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx)
+{
+ struct syscall *syscalls = tbl->syscalls.entries;
+
+ return idx < tbl->syscalls.nr_entries ? syscalls[idx].id : -1;
+}
+
int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx)
{
int i;
diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h
index a41d2ca9e4ae..2b53b7ed25a6 100644
--- a/tools/perf/util/syscalltbl.h
+++ b/tools/perf/util/syscalltbl.h
@@ -16,6 +16,7 @@ void syscalltbl__delete(struct syscalltbl *tbl);
const char *syscalltbl__name(const struct syscalltbl *tbl, int id);
int syscalltbl__id(struct syscalltbl *tbl, const char *name);
+int syscalltbl__id_at_idx(struct syscalltbl *tbl, int idx);
int syscalltbl__strglobmatch_first(struct syscalltbl *tbl, const char *syscall_glob, int *idx);
int syscalltbl__strglobmatch_next(struct syscalltbl *tbl, const char *syscall_glob, int *idx);
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
2024-07-05 9:42 ` [PATCH v5 1/8] perf trace: Fix iteration of syscall ids in syscalltbl->entries Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-10 17:54 ` Ian Rogers
2024-07-05 9:42 ` [PATCH v5 3/8] perf trace: Augment non-syscall tracepoints with enum arguments with BTF Howard Chu
` (5 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo,
Alexander Shishkin, Günther Noack, Ingo Molnar, Mark Rutland,
Mickaël Salaün, Peter Zijlstra
In this patch, BTF is used to turn enum value to the corresponding
name. There is only one system call that uses enum value as its
argument, that is `landlock_add_rule()`.
The vmlinux btf is loaded lazily, when user decided to trace the
`landlock_add_rule` syscall. But if one decide to run `perf trace`
without any arguments, the behaviour is to trace `landlock_add_rule`,
so vmlinux btf will be loaded by default.
The laziest behaviour is to load vmlinux btf when a
`landlock_add_rule` syscall hits. But I think you could lose some
samples when loading vmlinux btf at run time, for it can delay the
handling of other samples. I might need your precious opinions on
this...
before:
```
perf $ ./perf trace -e landlock_add_rule
0.000 ( 0.008 ms): ldlck-test/438194 landlock_add_rule(rule_type: 2) = -1 EBADFD (File descriptor in bad state)
0.010 ( 0.001 ms): ldlck-test/438194 landlock_add_rule(rule_type: 1) = -1 EBADFD (File descriptor in bad state)
```
after:
```
perf $ ./perf trace -e landlock_add_rule
0.000 ( 0.029 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_NET_PORT) = -1 EBADFD (File descriptor in bad state)
0.036 ( 0.004 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_PATH_BENEATH) = -1 EBADFD (File descriptor in bad state)
```
Committer notes:
Made it build with NO_LIBBPF=1, simplified btf_enum_fprintf(), see [1]
for the discussion.
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Günther Noack <gnoack@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mickaël Salaün <mic@digikod.net>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/lkml/20240613022757.3589783-1-howardchu95@gmail.com
Link: https://lore.kernel.org/lkml/ZnXAhFflUl_LV1QY@x1 # [1]
Link: https://lore.kernel.org/r/20240624181345.124764-3-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 110 +++++++++++++++++++++++++++++++++++--
1 file changed, 106 insertions(+), 4 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 8449f2beb54d..1391564911d9 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -19,6 +19,7 @@
#ifdef HAVE_LIBBPF_SUPPORT
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
+#include <bpf/btf.h>
#ifdef HAVE_BPF_SKEL
#include "bpf_skel/augmented_raw_syscalls.skel.h"
#endif
@@ -110,6 +111,10 @@ struct syscall_arg_fmt {
const char *name;
u16 nr_entries; // for arrays
bool show_zero;
+ bool is_enum;
+#ifdef HAVE_LIBBPF_SUPPORT
+ const struct btf_type *type;
+#endif
};
struct syscall_fmt {
@@ -139,6 +144,9 @@ struct trace {
} syscalls;
#ifdef HAVE_BPF_SKEL
struct augmented_raw_syscalls_bpf *skel;
+#endif
+#ifdef HAVE_LIBBPF_SUPPORT
+ struct btf *btf;
#endif
struct record_opts opts;
struct evlist *evlist;
@@ -204,6 +212,20 @@ struct trace {
} oe;
};
+static void trace__load_vmlinux_btf(struct trace *trace __maybe_unused)
+{
+#ifdef HAVE_LIBBPF_SUPPORT
+ if (trace->btf != NULL)
+ return;
+
+ trace->btf = btf__load_vmlinux_btf();
+ if (verbose > 0) {
+ fprintf(trace->output, trace->btf ? "vmlinux BTF loaded\n" :
+ "Failed to load vmlinux BTF\n");
+ }
+#endif
+}
+
struct tp_field {
int offset;
union {
@@ -887,6 +909,64 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
+#ifdef HAVE_LIBBPF_SUPPORT
+static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
+{
+ int id;
+
+ // Already cached?
+ if (arg_fmt->type != NULL)
+ return 0;
+
+ type = strstr(type, "enum ");
+ if (type == NULL)
+ return -1;
+
+ type += 5; // skip "enum " to get the enumeration name
+
+ id = btf__find_by_name(btf, type);
+ if (id < 0)
+ return -1;
+
+ arg_fmt->type = btf__type_by_id(btf, id);
+ return arg_fmt->type == NULL ? -1 : 0;
+}
+
+static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
+{
+ struct btf_enum *be = btf_enum(type);
+ const int nr_entries = btf_vlen(type);
+
+ for (int i = 0; i < nr_entries; ++i, ++be) {
+ if (be->val == val) {
+ return scnprintf(bf, size, "%s",
+ btf__name_by_offset(btf, be->name_off));
+ }
+ }
+
+ return 0;
+}
+
+static size_t trace__btf_enum_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
+ size_t size, int val, char *type)
+{
+ if (trace->btf == NULL)
+ return 0;
+
+ if (syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type) < 0)
+ return 0;
+
+ return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
+}
+#else // HAVE_LIBBPF_SUPPORT
+static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg_fmt *arg_fmt __maybe_unused,
+ char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
+ char *type __maybe_unused)
+{
+ return 0;
+}
+#endif // HAVE_LIBBPF_SUPPORT
+
#define STRARRAY(name, array) \
{ .scnprintf = SCA_STRARRAY, \
.strtoul = STUL_STRARRAY, \
@@ -1238,6 +1318,7 @@ struct syscall {
bool is_exit;
bool is_open;
bool nonexistent;
+ bool use_btf;
struct tep_format_field *args;
const char *name;
const struct syscall_fmt *fmt;
@@ -1744,7 +1825,8 @@ static const struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *n
}
static struct tep_format_field *
-syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field)
+syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field,
+ bool *use_btf)
{
struct tep_format_field *last_field = NULL;
int len;
@@ -1756,6 +1838,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
continue;
len = strlen(field->name);
+ arg->is_enum = false;
if (strcmp(field->type, "const char *") == 0 &&
((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
@@ -1782,6 +1865,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
* 7 unsigned long
*/
arg->scnprintf = SCA_FD;
+ } else if (strstr(field->type, "enum") && use_btf != NULL) {
+ *use_btf = arg->is_enum = true;
} else {
const struct syscall_arg_fmt *fmt =
syscall_arg_fmt__find_by_name(field->name);
@@ -1798,7 +1883,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
static int syscall__set_arg_fmts(struct syscall *sc)
{
- struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args);
+ struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args,
+ &sc->use_btf);
if (last_field)
sc->args_size = last_field->offset + last_field->size;
@@ -1811,6 +1897,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
char tp_name[128];
struct syscall *sc;
const char *name = syscalltbl__name(trace->sctbl, id);
+ int err;
#ifdef HAVE_SYSCALL_TABLE_SUPPORT
if (trace->syscalls.table == NULL) {
@@ -1883,7 +1970,13 @@ static int trace__read_syscall_info(struct trace *trace, int id)
sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
- return syscall__set_arg_fmts(sc);
+ err = syscall__set_arg_fmts(sc);
+
+ /* after calling syscall__set_arg_fmts() we'll know whether use_btf is true */
+ if (sc->use_btf)
+ trace__load_vmlinux_btf(trace);
+
+ return err;
}
static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
@@ -1891,7 +1984,7 @@ static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
if (fmt != NULL) {
- syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
+ syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields, NULL);
return 0;
}
@@ -2103,6 +2196,15 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
if (trace->show_arg_names)
printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
+ if (sc->arg_fmt[arg.idx].is_enum) {
+ size_t p = trace__btf_enum_scnprintf(trace, &sc->arg_fmt[arg.idx], bf + printed,
+ size - printed, val, field->type);
+ if (p) {
+ printed += p;
+ continue;
+ }
+ }
+
printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
bf + printed, size - printed, &arg, val);
}
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 3/8] perf trace: Augment non-syscall tracepoints with enum arguments with BTF
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
2024-07-05 9:42 ` [PATCH v5 1/8] perf trace: Fix iteration of syscall ids in syscalltbl->entries Howard Chu
2024-07-05 9:42 ` [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 4/8] perf trace: Filter enum arguments with enum names Howard Chu
` (4 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Alexander Shishkin, Ingo Molnar,
Mark Rutland, Peter Zijlstra, Arnaldo Carvalho de Melo
Before:
perf $ ./perf trace -e timer:hrtimer_start --max-events=1
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff974466c25f18, function: 0xffffffff89da5be0, expires: 377432432256753, softexpires: 377432432256753, mode: 10)
After:
perf $ ./perf trace -e timer:hrtimer_start --max-events=1
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 4382442895089, softexpires: 4382442895089, mode: HRTIMER_MODE_ABS_PINNED_HARD)
in which HRTIMER_MODE_ABS_PINNED_HARD is:
perf $ pahole hrtimer_mode
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0,
HRTIMER_MODE_REL = 1,
HRTIMER_MODE_PINNED = 2,
HRTIMER_MODE_SOFT = 4,
HRTIMER_MODE_HARD = 8,
HRTIMER_MODE_ABS_PINNED = 2,
HRTIMER_MODE_REL_PINNED = 3,
HRTIMER_MODE_ABS_SOFT = 4,
HRTIMER_MODE_REL_SOFT = 5,
HRTIMER_MODE_ABS_PINNED_SOFT = 6,
HRTIMER_MODE_REL_PINNED_SOFT = 7,
HRTIMER_MODE_ABS_HARD = 8,
HRTIMER_MODE_REL_HARD = 9,
HRTIMER_MODE_ABS_PINNED_HARD = 10,
HRTIMER_MODE_REL_PINNED_HARD = 11,
};
Can also be tested by
./perf trace -e pagemap:mm_lru_insertion,timer:hrtimer_start,timer:hrtimer_init,skb:kfree_skb --max-events=10
(Chose these 4 events because they happen quite frequently.)
However some enum arguments may not be contained in vmlinux BTF. To see
what enum arguments are supported, use:
vmlinux_dir $ bpftool btf dump file /sys/kernel/btf/vmlinux > vmlinux
vmlinux_dir $ while read l; do grep "ENUM '$l'" vmlinux; done < <(grep field:enum /sys/kernel/tracing/events/*/*/format | awk '{print $3}' | sort | uniq) | awk '{print $3}' | sed "s/'\(.*\)'/\1/g"
dev_pm_qos_req_type
error_detector
hrtimer_mode
i2c_slave_event
ieee80211_bss_type
lru_list
migrate_mode
nl80211_auth_type
nl80211_band
nl80211_iftype
numa_vmaskip_reason
pm_qos_req_action
pwm_polarity
skb_drop_reason
thermal_trip_type
xen_lazy_mode
xen_mc_extend_args
xen_mc_flush_reason
zone_type
And what tracepoints have these enum types as their arguments:
vmlinux_dir $ while read l; do grep "ENUM '$l'" vmlinux; done < <(grep field:enum /sys/kernel/tracing/events/*/*/format | awk '{print $3}' | sort | uniq) | awk '{print $3}' | sed "s/'\(.*\)'/\1/g" > good_enums
vmlinux_dir $ cat good_enums
dev_pm_qos_req_type
error_detector
hrtimer_mode
i2c_slave_event
ieee80211_bss_type
lru_list
migrate_mode
nl80211_auth_type
nl80211_band
nl80211_iftype
numa_vmaskip_reason
pm_qos_req_action
pwm_polarity
skb_drop_reason
thermal_trip_type
xen_lazy_mode
xen_mc_extend_args
xen_mc_flush_reason
zone_type
vmlinux_dir $ grep -f good_enums -l /sys/kernel/tracing/events/*/*/format
/sys/kernel/tracing/events/cfg80211/cfg80211_chandef_dfs_required/format
/sys/kernel/tracing/events/cfg80211/cfg80211_ch_switch_notify/format
/sys/kernel/tracing/events/cfg80211/cfg80211_ch_switch_started_notify/format
/sys/kernel/tracing/events/cfg80211/cfg80211_get_bss/format
/sys/kernel/tracing/events/cfg80211/cfg80211_ibss_joined/format
/sys/kernel/tracing/events/cfg80211/cfg80211_inform_bss_frame/format
/sys/kernel/tracing/events/cfg80211/cfg80211_radar_event/format
/sys/kernel/tracing/events/cfg80211/cfg80211_ready_on_channel_expired/format
/sys/kernel/tracing/events/cfg80211/cfg80211_ready_on_channel/format
/sys/kernel/tracing/events/cfg80211/cfg80211_reg_can_beacon/format
/sys/kernel/tracing/events/cfg80211/cfg80211_return_bss/format
/sys/kernel/tracing/events/cfg80211/cfg80211_tx_mgmt_expired/format
/sys/kernel/tracing/events/cfg80211/rdev_add_virtual_intf/format
/sys/kernel/tracing/events/cfg80211/rdev_auth/format
/sys/kernel/tracing/events/cfg80211/rdev_change_virtual_intf/format
/sys/kernel/tracing/events/cfg80211/rdev_channel_switch/format
/sys/kernel/tracing/events/cfg80211/rdev_connect/format
/sys/kernel/tracing/events/cfg80211/rdev_inform_bss/format
/sys/kernel/tracing/events/cfg80211/rdev_libertas_set_mesh_channel/format
/sys/kernel/tracing/events/cfg80211/rdev_mgmt_tx/format
/sys/kernel/tracing/events/cfg80211/rdev_remain_on_channel/format
/sys/kernel/tracing/events/cfg80211/rdev_return_chandef/format
/sys/kernel/tracing/events/cfg80211/rdev_return_int_survey_info/format
/sys/kernel/tracing/events/cfg80211/rdev_set_ap_chanwidth/format
/sys/kernel/tracing/events/cfg80211/rdev_set_monitor_channel/format
/sys/kernel/tracing/events/cfg80211/rdev_set_radar_background/format
/sys/kernel/tracing/events/cfg80211/rdev_start_ap/format
/sys/kernel/tracing/events/cfg80211/rdev_start_radar_detection/format
/sys/kernel/tracing/events/cfg80211/rdev_tdls_channel_switch/format
/sys/kernel/tracing/events/compaction/mm_compaction_defer_compaction/format
/sys/kernel/tracing/events/compaction/mm_compaction_deferred/format
/sys/kernel/tracing/events/compaction/mm_compaction_defer_reset/format
/sys/kernel/tracing/events/compaction/mm_compaction_finished/format
/sys/kernel/tracing/events/compaction/mm_compaction_kcompactd_wake/format
/sys/kernel/tracing/events/compaction/mm_compaction_suitable/format
/sys/kernel/tracing/events/compaction/mm_compaction_wakeup_kcompactd/format
/sys/kernel/tracing/events/error_report/error_report_end/format
/sys/kernel/tracing/events/i2c_slave/i2c_slave/format
/sys/kernel/tracing/events/migrate/mm_migrate_pages/format
/sys/kernel/tracing/events/migrate/mm_migrate_pages_start/format
/sys/kernel/tracing/events/pagemap/mm_lru_insertion/format
/sys/kernel/tracing/events/power/dev_pm_qos_add_request/format
/sys/kernel/tracing/events/power/dev_pm_qos_remove_request/format
/sys/kernel/tracing/events/power/dev_pm_qos_update_request/format
/sys/kernel/tracing/events/power/pm_qos_update_flags/format
/sys/kernel/tracing/events/power/pm_qos_update_target/format
/sys/kernel/tracing/events/pwm/pwm_apply/format
/sys/kernel/tracing/events/pwm/pwm_get/format
/sys/kernel/tracing/events/sched/sched_skip_vma_numa/format
/sys/kernel/tracing/events/skb/kfree_skb/format
/sys/kernel/tracing/events/thermal/thermal_zone_trip/format
/sys/kernel/tracing/events/timer/hrtimer_init/format
/sys/kernel/tracing/events/timer/hrtimer_start/format
/sys/kernel/tracing/events/xen/xen_mc_batch/format
/sys/kernel/tracing/events/xen/xen_mc_extend_args/format
/sys/kernel/tracing/events/xen/xen_mc_flush_reason/format
/sys/kernel/tracing/events/xen/xen_mc_issue/format
Committer testing:
root@x1:~# perf trace -e timer:hrtimer_start --max-events=2
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff225050, function: 0xffffffff9e22ddd0, expires: 241152380000000, softexpires: 241152380000000, mode: HRTIMER_MODE_ABS)
0.028 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff225050, function: 0xffffffff9e22ddd0, expires: 241153654000000, softexpires: 241153654000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
root@x1:~#
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Reviewed-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/lkml/20240615032743.112750-1-howardchu95@gmail.com
Link: https://lore.kernel.org/r/20240624181345.124764-4-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 1391564911d9..5618feb7d01a 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1979,12 +1979,12 @@ static int trace__read_syscall_info(struct trace *trace, int id)
return err;
}
-static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
+static int evsel__init_tp_arg_scnprintf(struct evsel *evsel, bool *use_btf)
{
struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
if (fmt != NULL) {
- syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields, NULL);
+ syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields, use_btf);
return 0;
}
@@ -2188,7 +2188,8 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
* property isn't set.
*/
if (val == 0 && !trace->show_zeros &&
- !(sc->arg_fmt && sc->arg_fmt[arg.idx].show_zero))
+ !(sc->arg_fmt && sc->arg_fmt[arg.idx].show_zero) &&
+ !(sc->arg_fmt && sc->arg_fmt[arg.idx].is_enum))
continue;
printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
@@ -2893,7 +2894,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
val = syscall_arg_fmt__mask_val(arg, &syscall_arg, val);
/* Suppress this argument if its value is zero and show_zero property isn't set. */
- if (val == 0 && !trace->show_zeros && !arg->show_zero)
+ if (val == 0 && !trace->show_zeros && !arg->show_zero && !arg->is_enum)
continue;
printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
@@ -2901,6 +2902,15 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
if (trace->show_arg_names)
printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
+ if (arg->is_enum) {
+ size_t p = trace__btf_enum_scnprintf(trace, arg, bf + printed,
+ size - printed, val, field->type);
+ if (p) {
+ printed += p;
+ continue;
+ }
+ }
+
printed += syscall_arg_fmt__scnprintf_val(arg, bf + printed, size - printed, &syscall_arg, val);
}
@@ -4553,7 +4563,7 @@ static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
}
}
-static int evlist__set_syscall_tp_fields(struct evlist *evlist)
+static int evlist__set_syscall_tp_fields(struct evlist *evlist, bool *use_btf)
{
struct evsel *evsel;
@@ -4562,7 +4572,7 @@ static int evlist__set_syscall_tp_fields(struct evlist *evlist)
continue;
if (strcmp(evsel->tp_format->system, "syscalls")) {
- evsel__init_tp_arg_scnprintf(evsel);
+ evsel__init_tp_arg_scnprintf(evsel, use_btf);
continue;
}
@@ -5040,11 +5050,16 @@ int cmd_trace(int argc, const char **argv)
}
if (trace.evlist->core.nr_entries > 0) {
+ bool use_btf = false;
+
evlist__set_default_evsel_handler(trace.evlist, trace__event_handler);
- if (evlist__set_syscall_tp_fields(trace.evlist)) {
+ if (evlist__set_syscall_tp_fields(trace.evlist, &use_btf)) {
perror("failed to set syscalls:* tracepoint fields");
goto out;
}
+
+ if (use_btf)
+ trace__load_vmlinux_btf(&trace);
}
if (trace.sort_events) {
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 4/8] perf trace: Filter enum arguments with enum names
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
` (2 preceding siblings ...)
2024-07-05 9:42 ` [PATCH v5 3/8] perf trace: Augment non-syscall tracepoints with enum arguments with BTF Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-10 17:48 ` Ian Rogers
2024-07-05 9:42 ` [PATCH v5 5/8] perf test: Add landlock workload Howard Chu
` (3 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo,
Alexander Shishkin, Ingo Molnar, Mark Rutland, Peter Zijlstra
Before:
perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
No resolver (strtoul) for "mode" in "timer:hrtimer_start", can't set filter "(mode!=HRTIMER_MODE_ABS_PINNED_HARD) && (common_pid != 281988)"
After:
perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12351248764875, softexpires: 12351248764875, mode: HRTIMER_MODE_ABS)
&& and ||:
perf $ ./perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_ABS' --max-events=1
0.000 Hyprland/534 timer:hrtimer_start(hrtimer: 0xffff9497801a84d0, function: 0xffffffffc04cdbe0, expires: 12639434638458, softexpires: 12639433638458, mode: HRTIMER_MODE_REL)
perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_REL || mode == HRTIMER_MODE_PINNED' --max-events=1
0.000 ldlck-test/60639 timer:hrtimer_start(hrtimer: 0xffffb16404ee7bf8, function: 0xffffffffa7790420, expires: 12772614418016, softexpires: 12772614368016, mode: HRTIMER_MODE_REL)
Switching it up, using both enum name and integer value(--filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0'):
perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0' --max-events=3
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12601748739825, softexpires: 12601748739825, mode: HRTIMER_MODE_ABS_PINNED_HARD)
0.036 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12518758748124, softexpires: 12518758748124, mode: HRTIMER_MODE_ABS_PINNED_HARD)
0.172 tmux: server/41881 timer:hrtimer_start(hrtimer: 0xffffb164081e7838, function: 0xffffffffa7790420, expires: 12518768255836, softexpires: 12518768205836, mode: HRTIMER_MODE_ABS)
P.S.
perf $ pahole hrtimer_mode
enum hrtimer_mode {
HRTIMER_MODE_ABS = 0,
HRTIMER_MODE_REL = 1,
HRTIMER_MODE_PINNED = 2,
HRTIMER_MODE_SOFT = 4,
HRTIMER_MODE_HARD = 8,
HRTIMER_MODE_ABS_PINNED = 2,
HRTIMER_MODE_REL_PINNED = 3,
HRTIMER_MODE_ABS_SOFT = 4,
HRTIMER_MODE_REL_SOFT = 5,
HRTIMER_MODE_ABS_PINNED_SOFT = 6,
HRTIMER_MODE_REL_PINNED_SOFT = 7,
HRTIMER_MODE_ABS_HARD = 8,
HRTIMER_MODE_REL_HARD = 9,
HRTIMER_MODE_ABS_PINNED_HARD = 10,
HRTIMER_MODE_REL_PINNED_HARD = 11,
};
Committer testing:
root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS' --max-events=2
0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff2a5050, function: 0xffffffff9e22ddd0, expires: 241502326000000, softexpires: 241502326000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
18446744073709.488 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff425050, function: 0xffffffff9e22ddd0, expires: 241501814000000, softexpires: 241501814000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD' --max-events=2
0.000 podman/510644 timer:hrtimer_start(hrtimer: 0xffffa2024f5f7dd0, function: 0xffffffff9e2170c0, expires: 241530497418194, softexpires: 241530497368194, mode: HRTIMER_MODE_REL)
40.251 gnome-shell/2484 timer:hrtimer_start(hrtimer: 0xffff8d48bda17650, function: 0xffffffffc0661550, expires: 241550528619247, softexpires: 241550527619247, mode: HRTIMER_MODE_REL)
root@x1:~# perf trace -v -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_REL' --max-events=2
Using CPUID GenuineIntel-6-BA-3
vmlinux BTF loaded
<SNIP>
0
0xa
0x1
New filter for timer:hrtimer_start: (mode != 0 && mode != 0xa && mode != 0x1) && (common_pid != 524049 && common_pid != 4041)
mmap size 528384B
^Croot@x1:~#
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/lkml/ZnCcliuecJABD5FN@x1
Link: https://lore.kernel.org/r/20240624181345.124764-5-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 62 ++++++++++++++++++++++++++++++++++----
1 file changed, 56 insertions(+), 6 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 5618feb7d01a..e664001d5ed7 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -932,6 +932,37 @@ static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, stru
return arg_fmt->type == NULL ? -1 : 0;
}
+static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
+{
+ const struct btf_type *bt;
+ char *type = arg->parm;
+ struct btf_enum *be;
+ struct btf *btf;
+
+ trace__load_vmlinux_btf(arg->trace);
+
+ btf = arg->trace->btf;
+ if (btf == NULL)
+ return false;
+
+ if (syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type) < 0)
+ return false;
+
+ bt = arg->fmt->type;
+ be = btf_enum(bt);
+ for (int i = 0; i < btf_vlen(bt); ++i, ++be) {
+ const char *name = btf__name_by_offset(btf, be->name_off);
+ int max_len = max(size, strlen(name));
+
+ if (strncmp(name, bf, max_len) == 0) {
+ *val = be->val;
+ return true;
+ }
+ }
+
+ return false;
+}
+
static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
{
struct btf_enum *be = btf_enum(type);
@@ -965,8 +996,16 @@ static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, stru
{
return 0;
}
+
+static bool syscall_arg__strtoul_btf_enum(char *bf __maybe_unused, size_t size __maybe_unused,
+ struct syscall_arg *arg __maybe_unused, u64 *val __maybe_unused)
+{
+ return false;
+}
#endif // HAVE_LIBBPF_SUPPORT
+#define STUL_BTF_ENUM syscall_arg__strtoul_btf_enum
+
#define STRARRAY(name, array) \
{ .scnprintf = SCA_STRARRAY, \
.strtoul = STUL_STRARRAY, \
@@ -1867,6 +1906,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
arg->scnprintf = SCA_FD;
} else if (strstr(field->type, "enum") && use_btf != NULL) {
*use_btf = arg->is_enum = true;
+ arg->strtoul = STUL_BTF_ENUM;
} else {
const struct syscall_arg_fmt *fmt =
syscall_arg_fmt__find_by_name(field->name);
@@ -3792,7 +3832,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
return __trace__deliver_event(trace, event->event);
}
-static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg)
+static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg,
+ char **type)
{
struct tep_format_field *field;
struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
@@ -3801,13 +3842,15 @@ static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel
return NULL;
for (field = evsel->tp_format->format.fields; field; field = field->next, ++fmt)
- if (strcmp(field->name, arg) == 0)
+ if (strcmp(field->name, arg) == 0) {
+ *type = field->type;
return fmt;
+ }
return NULL;
}
-static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel *evsel)
+static int trace__expand_filter(struct trace *trace, struct evsel *evsel)
{
char *tok, *left = evsel->filter, *new_filter = evsel->filter;
@@ -3840,14 +3883,14 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
struct syscall_arg_fmt *fmt;
int left_size = tok - left,
right_size = right_end - right;
- char arg[128];
+ char arg[128], *type;
while (isspace(left[left_size - 1]))
--left_size;
scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
- fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg);
+ fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg, &type);
if (fmt == NULL) {
pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
arg, evsel->name, evsel->filter);
@@ -3860,9 +3903,16 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
if (fmt->strtoul) {
u64 val;
struct syscall_arg syscall_arg = {
- .parm = fmt->parm,
+ .trace = trace,
+ .fmt = fmt,
};
+ if (fmt->is_enum) {
+ syscall_arg.parm = type;
+ } else {
+ syscall_arg.parm = fmt->parm;
+ }
+
if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
char *n, expansion[19];
int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 5/8] perf test: Add landlock workload
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
` (3 preceding siblings ...)
2024-07-05 9:42 ` [PATCH v5 4/8] perf trace: Filter enum arguments with enum names Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace' Howard Chu
` (2 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
We'll use it to add a regression test for the BTF augmentation of enum
arguments for tracepoints in 'perf trace':
root@x1:~# perf trace -e landlock_add_rule perf test -w landlock
0.000 ( 0.009 ms): perf/747160 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd8e258594, flags: 45) = -1 EINVAL (Invalid argument)
0.011 ( 0.002 ms): perf/747160 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd8e2585a0, flags: 45) = -1 EINVAL (Invalid argument)
root@x1:~#
Committer notes:
It was agreed on the discussion (see Link below) to shorten then name of
the workload from 'landlock_add_rule' to 'landlock', and I moved it to a
separate patch.
Also, to address a build failure from Namhyung, I stopped loading
linux/landlock.h and instead added the used defines, enums and types to
make this build in older systems. All we want is to emit the syscall and
intercept it.
We also need to add a "CFLAGS_landlock.o = -Wno-attributes" line
to cope with those landlock struct packed structs when building on
32-bit architectures.
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/lkml/CAH0uvohaypdTV6Z7O5QSK+va_qnhZ6BP6oSJ89s1c1E0CjgxDA@mail.gmail.com
Link: https://lore.kernel.org/r/20240624181345.124764-1-howardchu95@gmail.com
Link: https://lore.kernel.org/r/20240624181345.124764-6-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 +
tools/perf/tests/workloads/landlock.c | 66 +++++++++++++++++++++++++++
4 files changed, 70 insertions(+)
create mode 100644 tools/perf/tests/workloads/landlock.c
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index c3d84b67ca8e..470a9709427d 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -152,6 +152,7 @@ static struct test_workload *workloads[] = {
&workload__sqrtloop,
&workload__brstack,
&workload__datasym,
+ &workload__landlock,
};
static int num_subtests(const struct test_suite *t)
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 3aa7701ee0e9..6ea2be86b7bf 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -205,6 +205,7 @@ DECLARE_WORKLOAD(leafloop);
DECLARE_WORKLOAD(sqrtloop);
DECLARE_WORKLOAD(brstack);
DECLARE_WORKLOAD(datasym);
+DECLARE_WORKLOAD(landlock);
extern const char *dso_to_test;
extern const char *test_objdump_path;
diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build
index 48bf0d3b0f3d..3fe97e68d105 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -6,8 +6,10 @@ perf-test-y += leafloop.o
perf-test-y += sqrtloop.o
perf-test-y += brstack.o
perf-test-y += datasym.o
+perf-test-y += landlock.o
CFLAGS_sqrtloop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_leafloop.o = -g -O0 -fno-inline -fno-omit-frame-pointer -U_FORTIFY_SOURCE
CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_datasym.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
+CFLAGS_landlock.o = -Wno-attributes
diff --git a/tools/perf/tests/workloads/landlock.c b/tools/perf/tests/workloads/landlock.c
new file mode 100644
index 000000000000..0c2bcdaf2263
--- /dev/null
+++ b/tools/perf/tests/workloads/landlock.c
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <unistd.h>
+#include "../tests.h"
+
+/* This workload was initially added to test enum augmentation with BTF in perf
+ * trace because its the only syscall that has an enum argument. Since it is
+ * a recent addition to the Linux kernel (at the time of the introduction of this
+ * 'perf test' workload) we just add the required types and defines here instead
+ * of including linux/landlock, that isn't available in older systems.
+ *
+ * We are not interested in the the result of the syscall, just in intercepting
+ * its arguments.
+ */
+
+#ifndef __NR_landlock_add_rule
+#define __NR_landlock_add_rule 445
+#endif
+
+#ifndef LANDLOCK_ACCESS_FS_READ_FILE
+#define LANDLOCK_ACCESS_FS_READ_FILE (1ULL << 2)
+
+#define LANDLOCK_RULE_PATH_BENEATH 1
+
+struct landlock_path_beneath_attr {
+ __u64 allowed_access;
+ __s32 parent_fd;
+} __attribute__((packed));
+#endif
+
+#ifndef LANDLOCK_ACCESS_NET_CONNECT_TCP
+#define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1)
+
+#define LANDLOCK_RULE_NET_PORT 2
+
+struct landlock_net_port_attr {
+ __u64 allowed_access;
+ __u64 port;
+};
+#endif
+
+static int landlock(int argc __maybe_unused, const char **argv __maybe_unused)
+{
+ int fd = 11, flags = 45;
+
+ struct landlock_path_beneath_attr path_beneath_attr = {
+ .allowed_access = LANDLOCK_ACCESS_FS_READ_FILE,
+ .parent_fd = 14,
+ };
+
+ struct landlock_net_port_attr net_port_attr = {
+ .port = 19,
+ .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
+ };
+
+ syscall(__NR_landlock_add_rule, fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath_attr, flags);
+
+ syscall(__NR_landlock_add_rule, fd, LANDLOCK_RULE_NET_PORT,
+ &net_port_attr, flags);
+
+ return 0;
+}
+
+DEFINE_WORKLOAD(landlock);
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace'
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
` (4 preceding siblings ...)
2024-07-05 9:42 ` [PATCH v5 5/8] perf test: Add landlock workload Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 7/8] perf trace: Introduce trace__btf_scnprintf() Howard Chu
2024-07-05 9:43 ` [PATCH v5 8/8] perf trace: Remove arg_fmt->is_enum, we can get that from the BTF type Howard Chu
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
Trace landlock_add_rule syscall to see if the output is desirable.
Trace the non-syscall tracepoint 'timer:hrtimer_init' and
'timer:hrtimer_start', see if the 'mode' argument is augmented,
the 'mode' enum argument has the prefix of 'HRTIMER_MODE_'
in its name.
Committer testing:
root@x1:~# perf test enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf trace -e landlock_add_rule perf test -v enum
0.000 ( 0.010 ms): perf/749827 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd324171d4, flags: 45) = -1 EINVAL (Invalid argument)
0.012 ( 0.002 ms): perf/749827 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd324171e0, flags: 45) = -1 EINVAL (Invalid argument)
457.821 ( 0.007 ms): perf/749830 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd4acd31e4, flags: 45) = -1 EINVAL (Invalid argument)
457.832 ( 0.003 ms): perf/749830 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd4acd31f0, flags: 45) = -1 EINVAL (Invalid argument)
124: perf trace enum augmentation tests : Ok
root@x1:~#
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/lkml/20240619082042.4173621-6-howardchu95@gmail.com
Link: https://lore.kernel.org/r/20240624181345.124764-7-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/tests/shell/trace_btf_enum.sh | 61 ++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100755 tools/perf/tests/shell/trace_btf_enum.sh
diff --git a/tools/perf/tests/shell/trace_btf_enum.sh b/tools/perf/tests/shell/trace_btf_enum.sh
new file mode 100755
index 000000000000..7d407b52bea5
--- /dev/null
+++ b/tools/perf/tests/shell/trace_btf_enum.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# perf trace enum augmentation tests
+# SPDX-License-Identifier: GPL-2.0
+
+err=0
+set -e
+
+syscall="landlock_add_rule"
+non_syscall="timer:hrtimer_init,timer:hrtimer_start"
+
+TESTPROG="perf test -w landlock"
+
+. "$(dirname $0)"/lib/probe.sh
+skip_if_no_perf_trace || exit 2
+
+check_vmlinux() {
+ echo "Checking if vmlinux exists"
+ if ! ls /sys/kernel/btf/vmlinux 1>/dev/null 2>&1
+ then
+ echo "trace+enum test [Skipped missing vmlinux BTF support]"
+ err=2
+ fi
+}
+
+trace_landlock() {
+ echo "Tracing syscall ${syscall}"
+
+ # test flight just to see if landlock_add_rule and libbpf are available
+ $TESTPROG
+
+ if perf trace -e $syscall $TESTPROG 2>&1 | \
+ grep -q -E ".*landlock_add_rule\(ruleset_fd: 11, rule_type: (LANDLOCK_RULE_PATH_BENEATH|LANDLOCK_RULE_NET_PORT), rule_attr: 0x[a-f0-9]+, flags: 45\) = -1.*"
+ then
+ err=0
+ else
+ err=1
+ fi
+}
+
+trace_non_syscall() {
+ echo "Tracing non-syscall tracepoint ${non-syscall}"
+ if perf trace -e $non_syscall --max-events=1 2>&1 | \
+ grep -q -E '.*timer:hrtimer_.*\(.*mode: HRTIMER_MODE_.*\)$'
+ then
+ err=0
+ else
+ err=1
+ fi
+}
+
+check_vmlinux
+
+if [ $err = 0 ]; then
+ trace_landlock
+fi
+
+if [ $err = 0 ]; then
+ trace_non_syscall
+fi
+
+exit $err
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 7/8] perf trace: Introduce trace__btf_scnprintf()
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
` (5 preceding siblings ...)
2024-07-05 9:42 ` [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace' Howard Chu
@ 2024-07-05 9:42 ` Howard Chu
2024-07-05 9:43 ` [PATCH v5 8/8] perf trace: Remove arg_fmt->is_enum, we can get that from the BTF type Howard Chu
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:42 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <acme@redhat.com>
To have a central place that will look at the BTF type and call the
right scnprintf routine or return zero, meaning BTF pretty printing
isn't available or not implemented for a specific type.
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Howard Chu <howardchu95@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240624181345.124764-8-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 49 +++++++++++++++++++++-----------------
1 file changed, 27 insertions(+), 22 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e664001d5ed7..d9104fc4f61f 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -981,18 +981,28 @@ static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, c
static size_t trace__btf_enum_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
size_t size, int val, char *type)
{
- if (trace->btf == NULL)
- return 0;
-
if (syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type) < 0)
return 0;
return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
}
+
+static size_t trace__btf_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
+ size_t size, int val, char *type)
+{
+ if (trace->btf == NULL)
+ return 0;
+
+ if (arg_fmt->is_enum)
+ return trace__btf_enum_scnprintf(trace, arg_fmt, bf, size, val, type);
+
+ return 0;
+}
+
#else // HAVE_LIBBPF_SUPPORT
-static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg_fmt *arg_fmt __maybe_unused,
- char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
- char *type __maybe_unused)
+static size_t trace__btf_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg_fmt *arg_fmt __maybe_unused,
+ char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
+ char *type __maybe_unused)
{
return 0;
}
@@ -2183,7 +2193,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
unsigned char *args, void *augmented_args, int augmented_args_size,
struct trace *trace, struct thread *thread)
{
- size_t printed = 0;
+ size_t printed = 0, btf_printed;
unsigned long val;
u8 bit = 1;
struct syscall_arg arg = {
@@ -2237,13 +2247,11 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
if (trace->show_arg_names)
printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
- if (sc->arg_fmt[arg.idx].is_enum) {
- size_t p = trace__btf_enum_scnprintf(trace, &sc->arg_fmt[arg.idx], bf + printed,
- size - printed, val, field->type);
- if (p) {
- printed += p;
- continue;
- }
+ btf_printed = trace__btf_scnprintf(trace, &sc->arg_fmt[arg.idx], bf + printed,
+ size - printed, val, field->type);
+ if (btf_printed) {
+ printed += btf_printed;
+ continue;
}
printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
@@ -2892,7 +2900,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
size_t size = sizeof(bf);
struct tep_format_field *field = evsel->tp_format->format.fields;
struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
- size_t printed = 0;
+ size_t printed = 0, btf_printed;
unsigned long val;
u8 bit = 1;
struct syscall_arg syscall_arg = {
@@ -2942,13 +2950,10 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
if (trace->show_arg_names)
printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
- if (arg->is_enum) {
- size_t p = trace__btf_enum_scnprintf(trace, arg, bf + printed,
- size - printed, val, field->type);
- if (p) {
- printed += p;
- continue;
- }
+ btf_printed = trace__btf_scnprintf(trace, arg, bf + printed, size - printed, val, field->type);
+ if (btf_printed) {
+ printed += btf_printed;
+ continue;
}
printed += syscall_arg_fmt__scnprintf_val(arg, bf + printed, size - printed, &syscall_arg, val);
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 8/8] perf trace: Remove arg_fmt->is_enum, we can get that from the BTF type
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
` (6 preceding siblings ...)
2024-07-05 9:42 ` [PATCH v5 7/8] perf trace: Introduce trace__btf_scnprintf() Howard Chu
@ 2024-07-05 9:43 ` Howard Chu
7 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 9:43 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <acme@redhat.com>
This is to pave the way for other BTF types, i.e. we try to find BTF
type then use things like btf_is_enum(btf_type) that we cached to find
the right strtoul and scnprintf routines.
For now only enum is supported, all the other types simple return zero
for scnprintf which makes it have the same behaviour as when BTF isn't
available, i.e. fallback to no pretty printing. Ditto for strtoul.
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~#
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Howard Chu <howardchu95@gmail.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20240624181345.124764-9-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/builtin-trace.c | 101 +++++++++++++++++--------------
tools/perf/trace/beauty/beauty.h | 1 +
2 files changed, 56 insertions(+), 46 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index d9104fc4f61f..488c2cedc110 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -111,7 +111,6 @@ struct syscall_arg_fmt {
const char *name;
u16 nr_entries; // for arrays
bool show_zero;
- bool is_enum;
#ifdef HAVE_LIBBPF_SUPPORT
const struct btf_type *type;
#endif
@@ -910,33 +909,46 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
#ifdef HAVE_LIBBPF_SUPPORT
-static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
+static void syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
{
int id;
- // Already cached?
- if (arg_fmt->type != NULL)
- return 0;
-
type = strstr(type, "enum ");
if (type == NULL)
- return -1;
+ return;
type += 5; // skip "enum " to get the enumeration name
id = btf__find_by_name(btf, type);
if (id < 0)
- return -1;
+ return;
arg_fmt->type = btf__type_by_id(btf, id);
- return arg_fmt->type == NULL ? -1 : 0;
}
static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
+{
+ const struct btf_type *bt = arg->fmt->type;
+ struct btf *btf = arg->trace->btf;
+ struct btf_enum *be = btf_enum(bt);
+
+ for (int i = 0; i < btf_vlen(bt); ++i, ++be) {
+ const char *name = btf__name_by_offset(btf, be->name_off);
+ int max_len = max(size, strlen(name));
+
+ if (strncmp(name, bf, max_len) == 0) {
+ *val = be->val;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool syscall_arg__strtoul_btf_type(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
{
const struct btf_type *bt;
- char *type = arg->parm;
- struct btf_enum *be;
+ char *type = arg->type_name;
struct btf *btf;
trace__load_vmlinux_btf(arg->trace);
@@ -945,20 +957,19 @@ static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_
if (btf == NULL)
return false;
- if (syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type) < 0)
- return false;
+ if (arg->fmt->type == NULL) {
+ // See if this is an enum
+ syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type);
+ }
+ // Now let's see if we have a BTF type resolved
bt = arg->fmt->type;
- be = btf_enum(bt);
- for (int i = 0; i < btf_vlen(bt); ++i, ++be) {
- const char *name = btf__name_by_offset(btf, be->name_off);
- int max_len = max(size, strlen(name));
+ if (bt == NULL)
+ return false;
- if (strncmp(name, bf, max_len) == 0) {
- *val = be->val;
- return true;
- }
- }
+ // If it is an enum:
+ if (btf_is_enum(arg->fmt->type))
+ return syscall_arg__strtoul_btf_enum(bf, size, arg, val);
return false;
}
@@ -978,23 +989,23 @@ static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, c
return 0;
}
-static size_t trace__btf_enum_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
- size_t size, int val, char *type)
-{
- if (syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type) < 0)
- return 0;
-
- return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
-}
-
static size_t trace__btf_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
size_t size, int val, char *type)
{
if (trace->btf == NULL)
return 0;
- if (arg_fmt->is_enum)
- return trace__btf_enum_scnprintf(trace, arg_fmt, bf, size, val, type);
+ if (arg_fmt->type == NULL) {
+ // Check if this is an enum and if we have the BTF type for it.
+ syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type);
+ }
+
+ // Did we manage to find a BTF type for the syscall/tracepoint argument?
+ if (arg_fmt->type == NULL)
+ return 0;
+
+ if (btf_is_enum(arg_fmt->type))
+ return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
return 0;
}
@@ -1007,14 +1018,14 @@ static size_t trace__btf_scnprintf(struct trace *trace __maybe_unused, struct sy
return 0;
}
-static bool syscall_arg__strtoul_btf_enum(char *bf __maybe_unused, size_t size __maybe_unused,
+static bool syscall_arg__strtoul_btf_type(char *bf __maybe_unused, size_t size __maybe_unused,
struct syscall_arg *arg __maybe_unused, u64 *val __maybe_unused)
{
return false;
}
#endif // HAVE_LIBBPF_SUPPORT
-#define STUL_BTF_ENUM syscall_arg__strtoul_btf_enum
+#define STUL_BTF_TYPE syscall_arg__strtoul_btf_type
#define STRARRAY(name, array) \
{ .scnprintf = SCA_STRARRAY, \
@@ -1887,7 +1898,6 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
continue;
len = strlen(field->name);
- arg->is_enum = false;
if (strcmp(field->type, "const char *") == 0 &&
((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
@@ -1915,8 +1925,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
*/
arg->scnprintf = SCA_FD;
} else if (strstr(field->type, "enum") && use_btf != NULL) {
- *use_btf = arg->is_enum = true;
- arg->strtoul = STUL_BTF_ENUM;
+ *use_btf = true;
+ arg->strtoul = STUL_BTF_TYPE;
} else {
const struct syscall_arg_fmt *fmt =
syscall_arg_fmt__find_by_name(field->name);
@@ -2236,10 +2246,13 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
/*
* Suppress this argument if its value is zero and show_zero
* property isn't set.
+ *
+ * If it has a BTF type, then override the zero suppression knob
+ * as the common case is for zero in an enum to have an associated entry.
*/
if (val == 0 && !trace->show_zeros &&
!(sc->arg_fmt && sc->arg_fmt[arg.idx].show_zero) &&
- !(sc->arg_fmt && sc->arg_fmt[arg.idx].is_enum))
+ !(sc->arg_fmt && sc->arg_fmt[arg.idx].strtoul == STUL_BTF_TYPE))
continue;
printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
@@ -2942,7 +2955,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
val = syscall_arg_fmt__mask_val(arg, &syscall_arg, val);
/* Suppress this argument if its value is zero and show_zero property isn't set. */
- if (val == 0 && !trace->show_zeros && !arg->show_zero && !arg->is_enum)
+ if (val == 0 && !trace->show_zeros && !arg->show_zero && arg->strtoul != STUL_BTF_TYPE)
continue;
printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
@@ -3910,14 +3923,10 @@ static int trace__expand_filter(struct trace *trace, struct evsel *evsel)
struct syscall_arg syscall_arg = {
.trace = trace,
.fmt = fmt,
+ .type_name = type,
+ .parm = fmt->parm,
};
- if (fmt->is_enum) {
- syscall_arg.parm = type;
- } else {
- syscall_arg.parm = fmt->parm;
- }
-
if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
char *n, expansion[19];
int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
diff --git a/tools/perf/trace/beauty/beauty.h b/tools/perf/trace/beauty/beauty.h
index 78d10d92d351..3ed11e18ee2d 100644
--- a/tools/perf/trace/beauty/beauty.h
+++ b/tools/perf/trace/beauty/beauty.h
@@ -113,6 +113,7 @@ struct syscall_arg {
struct thread *thread;
struct trace *trace;
void *parm;
+ char *type_name;
u16 len;
u8 idx;
u8 mask;
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace'
2024-07-05 13:20 [PATCH v5 0/8] perf trace: Augment enum arguments with BTF Howard Chu
@ 2024-07-05 13:20 ` Howard Chu
0 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-05 13:20 UTC (permalink / raw)
To: acme
Cc: adrian.hunter, irogers, jolsa, kan.liang, namhyung,
linux-perf-users, linux-kernel, Arnaldo Carvalho de Melo
Trace landlock_add_rule syscall to see if the output is desirable.
Trace the non-syscall tracepoint 'timer:hrtimer_init' and
'timer:hrtimer_start', see if the 'mode' argument is augmented,
the 'mode' enum argument has the prefix of 'HRTIMER_MODE_'
in its name.
Committer testing:
root@x1:~# perf test enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf test -v enum
124: perf trace enum augmentation tests : Ok
root@x1:~# perf trace -e landlock_add_rule perf test -v enum
0.000 ( 0.010 ms): perf/749827 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd324171d4, flags: 45) = -1 EINVAL (Invalid argument)
0.012 ( 0.002 ms): perf/749827 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd324171e0, flags: 45) = -1 EINVAL (Invalid argument)
457.821 ( 0.007 ms): perf/749830 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_PATH_BENEATH, rule_attr: 0x7ffd4acd31e4, flags: 45) = -1 EINVAL (Invalid argument)
457.832 ( 0.003 ms): perf/749830 landlock_add_rule(ruleset_fd: 11, rule_type: LANDLOCK_RULE_NET_PORT, rule_attr: 0x7ffd4acd31f0, flags: 45) = -1 EINVAL (Invalid argument)
124: perf trace enum augmentation tests : Ok
root@x1:~#
Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/lkml/20240619082042.4173621-6-howardchu95@gmail.com
Link: https://lore.kernel.org/r/20240624181345.124764-7-howardchu95@gmail.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/tests/shell/trace_btf_enum.sh | 61 ++++++++++++++++++++++++
1 file changed, 61 insertions(+)
create mode 100755 tools/perf/tests/shell/trace_btf_enum.sh
diff --git a/tools/perf/tests/shell/trace_btf_enum.sh b/tools/perf/tests/shell/trace_btf_enum.sh
new file mode 100755
index 000000000000..7d407b52bea5
--- /dev/null
+++ b/tools/perf/tests/shell/trace_btf_enum.sh
@@ -0,0 +1,61 @@
+#!/bin/sh
+# perf trace enum augmentation tests
+# SPDX-License-Identifier: GPL-2.0
+
+err=0
+set -e
+
+syscall="landlock_add_rule"
+non_syscall="timer:hrtimer_init,timer:hrtimer_start"
+
+TESTPROG="perf test -w landlock"
+
+. "$(dirname $0)"/lib/probe.sh
+skip_if_no_perf_trace || exit 2
+
+check_vmlinux() {
+ echo "Checking if vmlinux exists"
+ if ! ls /sys/kernel/btf/vmlinux 1>/dev/null 2>&1
+ then
+ echo "trace+enum test [Skipped missing vmlinux BTF support]"
+ err=2
+ fi
+}
+
+trace_landlock() {
+ echo "Tracing syscall ${syscall}"
+
+ # test flight just to see if landlock_add_rule and libbpf are available
+ $TESTPROG
+
+ if perf trace -e $syscall $TESTPROG 2>&1 | \
+ grep -q -E ".*landlock_add_rule\(ruleset_fd: 11, rule_type: (LANDLOCK_RULE_PATH_BENEATH|LANDLOCK_RULE_NET_PORT), rule_attr: 0x[a-f0-9]+, flags: 45\) = -1.*"
+ then
+ err=0
+ else
+ err=1
+ fi
+}
+
+trace_non_syscall() {
+ echo "Tracing non-syscall tracepoint ${non-syscall}"
+ if perf trace -e $non_syscall --max-events=1 2>&1 | \
+ grep -q -E '.*timer:hrtimer_.*\(.*mode: HRTIMER_MODE_.*\)$'
+ then
+ err=0
+ else
+ err=1
+ fi
+}
+
+check_vmlinux
+
+if [ $err = 0 ]; then
+ trace_landlock
+fi
+
+if [ $err = 0 ]; then
+ trace_non_syscall
+fi
+
+exit $err
--
2.45.2
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v5 4/8] perf trace: Filter enum arguments with enum names
2024-07-05 9:42 ` [PATCH v5 4/8] perf trace: Filter enum arguments with enum names Howard Chu
@ 2024-07-10 17:48 ` Ian Rogers
2024-07-11 15:14 ` Howard Chu
0 siblings, 1 reply; 14+ messages in thread
From: Ian Rogers @ 2024-07-10 17:48 UTC (permalink / raw)
To: Howard Chu
Cc: acme, adrian.hunter, jolsa, kan.liang, namhyung, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, Alexander Shishkin,
Ingo Molnar, Mark Rutland, Peter Zijlstra
On Fri, Jul 5, 2024 at 2:43 AM Howard Chu <howardchu95@gmail.com> wrote:
>
> Before:
>
> perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
> No resolver (strtoul) for "mode" in "timer:hrtimer_start", can't set filter "(mode!=HRTIMER_MODE_ABS_PINNED_HARD) && (common_pid != 281988)"
>
> After:
>
> perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
> 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12351248764875, softexpires: 12351248764875, mode: HRTIMER_MODE_ABS)
>
> && and ||:
>
> perf $ ./perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_ABS' --max-events=1
> 0.000 Hyprland/534 timer:hrtimer_start(hrtimer: 0xffff9497801a84d0, function: 0xffffffffc04cdbe0, expires: 12639434638458, softexpires: 12639433638458, mode: HRTIMER_MODE_REL)
>
> perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_REL || mode == HRTIMER_MODE_PINNED' --max-events=1
> 0.000 ldlck-test/60639 timer:hrtimer_start(hrtimer: 0xffffb16404ee7bf8, function: 0xffffffffa7790420, expires: 12772614418016, softexpires: 12772614368016, mode: HRTIMER_MODE_REL)
>
> Switching it up, using both enum name and integer value(--filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0'):
>
> perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0' --max-events=3
> 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12601748739825, softexpires: 12601748739825, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> 0.036 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12518758748124, softexpires: 12518758748124, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> 0.172 tmux: server/41881 timer:hrtimer_start(hrtimer: 0xffffb164081e7838, function: 0xffffffffa7790420, expires: 12518768255836, softexpires: 12518768205836, mode: HRTIMER_MODE_ABS)
>
> P.S.
> perf $ pahole hrtimer_mode
> enum hrtimer_mode {
> HRTIMER_MODE_ABS = 0,
> HRTIMER_MODE_REL = 1,
> HRTIMER_MODE_PINNED = 2,
> HRTIMER_MODE_SOFT = 4,
> HRTIMER_MODE_HARD = 8,
> HRTIMER_MODE_ABS_PINNED = 2,
> HRTIMER_MODE_REL_PINNED = 3,
> HRTIMER_MODE_ABS_SOFT = 4,
> HRTIMER_MODE_REL_SOFT = 5,
> HRTIMER_MODE_ABS_PINNED_SOFT = 6,
> HRTIMER_MODE_REL_PINNED_SOFT = 7,
> HRTIMER_MODE_ABS_HARD = 8,
> HRTIMER_MODE_REL_HARD = 9,
> HRTIMER_MODE_ABS_PINNED_HARD = 10,
> HRTIMER_MODE_REL_PINNED_HARD = 11,
> };
>
> Committer testing:
>
> root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS' --max-events=2
> 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff2a5050, function: 0xffffffff9e22ddd0, expires: 241502326000000, softexpires: 241502326000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> 18446744073709.488 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff425050, function: 0xffffffff9e22ddd0, expires: 241501814000000, softexpires: 241501814000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD' --max-events=2
> 0.000 podman/510644 timer:hrtimer_start(hrtimer: 0xffffa2024f5f7dd0, function: 0xffffffff9e2170c0, expires: 241530497418194, softexpires: 241530497368194, mode: HRTIMER_MODE_REL)
> 40.251 gnome-shell/2484 timer:hrtimer_start(hrtimer: 0xffff8d48bda17650, function: 0xffffffffc0661550, expires: 241550528619247, softexpires: 241550527619247, mode: HRTIMER_MODE_REL)
> root@x1:~# perf trace -v -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_REL' --max-events=2
> Using CPUID GenuineIntel-6-BA-3
> vmlinux BTF loaded
> <SNIP>
> 0
> 0xa
> 0x1
> New filter for timer:hrtimer_start: (mode != 0 && mode != 0xa && mode != 0x1) && (common_pid != 524049 && common_pid != 4041)
> mmap size 528384B
> ^Croot@x1:~#
>
> Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
> Signed-off-by: Howard Chu <howardchu95@gmail.com>
> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Adrian Hunter <adrian.hunter@intel.com>
> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Cc: Ian Rogers <irogers@google.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: Kan Liang <kan.liang@linux.intel.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Link: https://lore.kernel.org/lkml/ZnCcliuecJABD5FN@x1
> Link: https://lore.kernel.org/r/20240624181345.124764-5-howardchu95@gmail.com
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> tools/perf/builtin-trace.c | 62 ++++++++++++++++++++++++++++++++++----
> 1 file changed, 56 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index 5618feb7d01a..e664001d5ed7 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
> @@ -932,6 +932,37 @@ static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, stru
> return arg_fmt->type == NULL ? -1 : 0;
> }
>
> +static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
> +{
> + const struct btf_type *bt;
> + char *type = arg->parm;
> + struct btf_enum *be;
> + struct btf *btf;
> +
> + trace__load_vmlinux_btf(arg->trace);
> +
> + btf = arg->trace->btf;
> + if (btf == NULL)
> + return false;
> +
> + if (syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type) < 0)
> + return false;
> +
> + bt = arg->fmt->type;
> + be = btf_enum(bt);
> + for (int i = 0; i < btf_vlen(bt); ++i, ++be) {
> + const char *name = btf__name_by_offset(btf, be->name_off);
> + int max_len = max(size, strlen(name));
> +
> + if (strncmp(name, bf, max_len) == 0) {
> + *val = be->val;
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
> {
> struct btf_enum *be = btf_enum(type);
> @@ -965,8 +996,16 @@ static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, stru
> {
> return 0;
> }
> +
> +static bool syscall_arg__strtoul_btf_enum(char *bf __maybe_unused, size_t size __maybe_unused,
> + struct syscall_arg *arg __maybe_unused, u64 *val __maybe_unused)
> +{
> + return false;
> +}
> #endif // HAVE_LIBBPF_SUPPORT
>
> +#define STUL_BTF_ENUM syscall_arg__strtoul_btf_enum
> +
> #define STRARRAY(name, array) \
> { .scnprintf = SCA_STRARRAY, \
> .strtoul = STUL_STRARRAY, \
> @@ -1867,6 +1906,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> arg->scnprintf = SCA_FD;
> } else if (strstr(field->type, "enum") && use_btf != NULL) {
> *use_btf = arg->is_enum = true;
> + arg->strtoul = STUL_BTF_ENUM;
> } else {
> const struct syscall_arg_fmt *fmt =
> syscall_arg_fmt__find_by_name(field->name);
> @@ -3792,7 +3832,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
> return __trace__deliver_event(trace, event->event);
> }
>
> -static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg)
> +static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg,
> + char **type)
> {
> struct tep_format_field *field;
> struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
> @@ -3801,13 +3842,15 @@ static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel
> return NULL;
>
> for (field = evsel->tp_format->format.fields; field; field = field->next, ++fmt)
> - if (strcmp(field->name, arg) == 0)
> + if (strcmp(field->name, arg) == 0) {
> + *type = field->type;
> return fmt;
> + }
>
> return NULL;
> }
>
> -static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel *evsel)
> +static int trace__expand_filter(struct trace *trace, struct evsel *evsel)
> {
> char *tok, *left = evsel->filter, *new_filter = evsel->filter;
>
> @@ -3840,14 +3883,14 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
> struct syscall_arg_fmt *fmt;
> int left_size = tok - left,
> right_size = right_end - right;
> - char arg[128];
> + char arg[128], *type;
>
> while (isspace(left[left_size - 1]))
> --left_size;
>
> scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
>
> - fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg);
> + fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg, &type);
> if (fmt == NULL) {
> pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
> arg, evsel->name, evsel->filter);
> @@ -3860,9 +3903,16 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
> if (fmt->strtoul) {
> u64 val;
> struct syscall_arg syscall_arg = {
> - .parm = fmt->parm,
> + .trace = trace,
> + .fmt = fmt,
> };
>
> + if (fmt->is_enum) {
> + syscall_arg.parm = type;
> + } else {
> + syscall_arg.parm = fmt->parm;
> + }
Hi Howard,
minor nit that cases like this shouldn't use curly braces as per:
https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces
Thanks,
Ian
> +
> if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
> char *n, expansion[19];
> int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args
2024-07-05 9:42 ` [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args Howard Chu
@ 2024-07-10 17:54 ` Ian Rogers
2024-07-11 15:16 ` Howard Chu
0 siblings, 1 reply; 14+ messages in thread
From: Ian Rogers @ 2024-07-10 17:54 UTC (permalink / raw)
To: Howard Chu
Cc: acme, adrian.hunter, jolsa, kan.liang, namhyung, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, Alexander Shishkin,
Günther Noack, Ingo Molnar, Mark Rutland,
Mickaël Salaün, Peter Zijlstra
On Fri, Jul 5, 2024 at 2:43 AM Howard Chu <howardchu95@gmail.com> wrote:
>
> In this patch, BTF is used to turn enum value to the corresponding
> name. There is only one system call that uses enum value as its
> argument, that is `landlock_add_rule()`.
>
> The vmlinux btf is loaded lazily, when user decided to trace the
> `landlock_add_rule` syscall. But if one decide to run `perf trace`
> without any arguments, the behaviour is to trace `landlock_add_rule`,
> so vmlinux btf will be loaded by default.
>
> The laziest behaviour is to load vmlinux btf when a
> `landlock_add_rule` syscall hits. But I think you could lose some
> samples when loading vmlinux btf at run time, for it can delay the
> handling of other samples. I might need your precious opinions on
> this...
>
> before:
>
> ```
> perf $ ./perf trace -e landlock_add_rule
> 0.000 ( 0.008 ms): ldlck-test/438194 landlock_add_rule(rule_type: 2) = -1 EBADFD (File descriptor in bad state)
> 0.010 ( 0.001 ms): ldlck-test/438194 landlock_add_rule(rule_type: 1) = -1 EBADFD (File descriptor in bad state)
> ```
>
> after:
>
> ```
> perf $ ./perf trace -e landlock_add_rule
> 0.000 ( 0.029 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_NET_PORT) = -1 EBADFD (File descriptor in bad state)
> 0.036 ( 0.004 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_PATH_BENEATH) = -1 EBADFD (File descriptor in bad state)
> ```
>
> Committer notes:
>
> Made it build with NO_LIBBPF=1, simplified btf_enum_fprintf(), see [1]
> for the discussion.
>
> Signed-off-by: Howard Chu <howardchu95@gmail.com>
> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> Cc: Adrian Hunter <adrian.hunter@intel.com>
> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Cc: Günther Noack <gnoack@google.com>
> Cc: Ian Rogers <irogers@google.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Cc: Kan Liang <kan.liang@linux.intel.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Mickaël Salaün <mic@digikod.net>
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Link: https://lore.kernel.org/lkml/20240613022757.3589783-1-howardchu95@gmail.com
> Link: https://lore.kernel.org/lkml/ZnXAhFflUl_LV1QY@x1 # [1]
> Link: https://lore.kernel.org/r/20240624181345.124764-3-howardchu95@gmail.com
> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> ---
> tools/perf/builtin-trace.c | 110 +++++++++++++++++++++++++++++++++++--
> 1 file changed, 106 insertions(+), 4 deletions(-)
>
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index 8449f2beb54d..1391564911d9 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
> @@ -19,6 +19,7 @@
> #ifdef HAVE_LIBBPF_SUPPORT
> #include <bpf/bpf.h>
> #include <bpf/libbpf.h>
> +#include <bpf/btf.h>
> #ifdef HAVE_BPF_SKEL
> #include "bpf_skel/augmented_raw_syscalls.skel.h"
> #endif
> @@ -110,6 +111,10 @@ struct syscall_arg_fmt {
> const char *name;
> u16 nr_entries; // for arrays
> bool show_zero;
> + bool is_enum;
> +#ifdef HAVE_LIBBPF_SUPPORT
> + const struct btf_type *type;
> +#endif
> };
>
> struct syscall_fmt {
> @@ -139,6 +144,9 @@ struct trace {
> } syscalls;
> #ifdef HAVE_BPF_SKEL
> struct augmented_raw_syscalls_bpf *skel;
> +#endif
> +#ifdef HAVE_LIBBPF_SUPPORT
> + struct btf *btf;
> #endif
> struct record_opts opts;
> struct evlist *evlist;
> @@ -204,6 +212,20 @@ struct trace {
> } oe;
> };
>
> +static void trace__load_vmlinux_btf(struct trace *trace __maybe_unused)
> +{
> +#ifdef HAVE_LIBBPF_SUPPORT
> + if (trace->btf != NULL)
> + return;
> +
> + trace->btf = btf__load_vmlinux_btf();
> + if (verbose > 0) {
> + fprintf(trace->output, trace->btf ? "vmlinux BTF loaded\n" :
> + "Failed to load vmlinux BTF\n");
> + }
> +#endif
> +}
> +
> struct tp_field {
> int offset;
> union {
> @@ -887,6 +909,64 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
>
> #define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
>
> +#ifdef HAVE_LIBBPF_SUPPORT
> +static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
> +{
> + int id;
> +
> + // Already cached?
Hi Howard,
I'm on nit patrol again, just to note that most comments are /* */
style although we do have // comments - the ratio of /* */ to // is
about 10:1. The kernel is similar in this regard. There's no clear
guidance so we could ignore this, but fwiw I generally try to stick
with /* */ for consistency with the rest of the surrounding code.
Thanks,
Ian
> + if (arg_fmt->type != NULL)
> + return 0;
> +
> + type = strstr(type, "enum ");
> + if (type == NULL)
> + return -1;
> +
> + type += 5; // skip "enum " to get the enumeration name
> +
> + id = btf__find_by_name(btf, type);
> + if (id < 0)
> + return -1;
> +
> + arg_fmt->type = btf__type_by_id(btf, id);
> + return arg_fmt->type == NULL ? -1 : 0;
> +}
> +
> +static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
> +{
> + struct btf_enum *be = btf_enum(type);
> + const int nr_entries = btf_vlen(type);
> +
> + for (int i = 0; i < nr_entries; ++i, ++be) {
> + if (be->val == val) {
> + return scnprintf(bf, size, "%s",
> + btf__name_by_offset(btf, be->name_off));
> + }
> + }
> +
> + return 0;
> +}
> +
> +static size_t trace__btf_enum_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
> + size_t size, int val, char *type)
> +{
> + if (trace->btf == NULL)
> + return 0;
> +
> + if (syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type) < 0)
> + return 0;
> +
> + return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
> +}
> +#else // HAVE_LIBBPF_SUPPORT
> +static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg_fmt *arg_fmt __maybe_unused,
> + char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
> + char *type __maybe_unused)
> +{
> + return 0;
> +}
> +#endif // HAVE_LIBBPF_SUPPORT
> +
> #define STRARRAY(name, array) \
> { .scnprintf = SCA_STRARRAY, \
> .strtoul = STUL_STRARRAY, \
> @@ -1238,6 +1318,7 @@ struct syscall {
> bool is_exit;
> bool is_open;
> bool nonexistent;
> + bool use_btf;
> struct tep_format_field *args;
> const char *name;
> const struct syscall_fmt *fmt;
> @@ -1744,7 +1825,8 @@ static const struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *n
> }
>
> static struct tep_format_field *
> -syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field)
> +syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field,
> + bool *use_btf)
> {
> struct tep_format_field *last_field = NULL;
> int len;
> @@ -1756,6 +1838,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> continue;
>
> len = strlen(field->name);
> + arg->is_enum = false;
>
> if (strcmp(field->type, "const char *") == 0 &&
> ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
> @@ -1782,6 +1865,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> * 7 unsigned long
> */
> arg->scnprintf = SCA_FD;
> + } else if (strstr(field->type, "enum") && use_btf != NULL) {
> + *use_btf = arg->is_enum = true;
> } else {
> const struct syscall_arg_fmt *fmt =
> syscall_arg_fmt__find_by_name(field->name);
> @@ -1798,7 +1883,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
>
> static int syscall__set_arg_fmts(struct syscall *sc)
> {
> - struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args);
> + struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args,
> + &sc->use_btf);
>
> if (last_field)
> sc->args_size = last_field->offset + last_field->size;
> @@ -1811,6 +1897,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
> char tp_name[128];
> struct syscall *sc;
> const char *name = syscalltbl__name(trace->sctbl, id);
> + int err;
>
> #ifdef HAVE_SYSCALL_TABLE_SUPPORT
> if (trace->syscalls.table == NULL) {
> @@ -1883,7 +1970,13 @@ static int trace__read_syscall_info(struct trace *trace, int id)
> sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
> sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
>
> - return syscall__set_arg_fmts(sc);
> + err = syscall__set_arg_fmts(sc);
> +
> + /* after calling syscall__set_arg_fmts() we'll know whether use_btf is true */
> + if (sc->use_btf)
> + trace__load_vmlinux_btf(trace);
> +
> + return err;
> }
>
> static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
> @@ -1891,7 +1984,7 @@ static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
> struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
>
> if (fmt != NULL) {
> - syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
> + syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields, NULL);
> return 0;
> }
>
> @@ -2103,6 +2196,15 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
> if (trace->show_arg_names)
> printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
>
> + if (sc->arg_fmt[arg.idx].is_enum) {
> + size_t p = trace__btf_enum_scnprintf(trace, &sc->arg_fmt[arg.idx], bf + printed,
> + size - printed, val, field->type);
> + if (p) {
> + printed += p;
> + continue;
> + }
> + }
> +
> printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
> bf + printed, size - printed, &arg, val);
> }
> --
> 2.45.2
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 4/8] perf trace: Filter enum arguments with enum names
2024-07-10 17:48 ` Ian Rogers
@ 2024-07-11 15:14 ` Howard Chu
0 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-11 15:14 UTC (permalink / raw)
To: Ian Rogers
Cc: acme, adrian.hunter, jolsa, kan.liang, namhyung, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, Alexander Shishkin,
Ingo Molnar, Mark Rutland, Peter Zijlstra
Hello Ian,
On Thu, Jul 11, 2024 at 1:49 AM Ian Rogers <irogers@google.com> wrote:
>
> On Fri, Jul 5, 2024 at 2:43 AM Howard Chu <howardchu95@gmail.com> wrote:
> >
> > Before:
> >
> > perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
> > No resolver (strtoul) for "mode" in "timer:hrtimer_start", can't set filter "(mode!=HRTIMER_MODE_ABS_PINNED_HARD) && (common_pid != 281988)"
> >
> > After:
> >
> > perf $ ./perf trace -e timer:hrtimer_start --filter='mode!=HRTIMER_MODE_ABS_PINNED_HARD' --max-events=1
> > 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12351248764875, softexpires: 12351248764875, mode: HRTIMER_MODE_ABS)
> >
> > && and ||:
> >
> > perf $ ./perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_ABS' --max-events=1
> > 0.000 Hyprland/534 timer:hrtimer_start(hrtimer: 0xffff9497801a84d0, function: 0xffffffffc04cdbe0, expires: 12639434638458, softexpires: 12639433638458, mode: HRTIMER_MODE_REL)
> >
> > perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_REL || mode == HRTIMER_MODE_PINNED' --max-events=1
> > 0.000 ldlck-test/60639 timer:hrtimer_start(hrtimer: 0xffffb16404ee7bf8, function: 0xffffffffa7790420, expires: 12772614418016, softexpires: 12772614368016, mode: HRTIMER_MODE_REL)
> >
> > Switching it up, using both enum name and integer value(--filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0'):
> >
> > perf $ ./perf trace -e timer:hrtimer_start --filter='mode == HRTIMER_MODE_ABS_PINNED_HARD || mode == 0' --max-events=3
> > 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12601748739825, softexpires: 12601748739825, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> > 0.036 :0/0 timer:hrtimer_start(hrtimer: 0xffff9498a6ca5f18, function: 0xffffffffa77a5be0, expires: 12518758748124, softexpires: 12518758748124, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> > 0.172 tmux: server/41881 timer:hrtimer_start(hrtimer: 0xffffb164081e7838, function: 0xffffffffa7790420, expires: 12518768255836, softexpires: 12518768205836, mode: HRTIMER_MODE_ABS)
> >
> > P.S.
> > perf $ pahole hrtimer_mode
> > enum hrtimer_mode {
> > HRTIMER_MODE_ABS = 0,
> > HRTIMER_MODE_REL = 1,
> > HRTIMER_MODE_PINNED = 2,
> > HRTIMER_MODE_SOFT = 4,
> > HRTIMER_MODE_HARD = 8,
> > HRTIMER_MODE_ABS_PINNED = 2,
> > HRTIMER_MODE_REL_PINNED = 3,
> > HRTIMER_MODE_ABS_SOFT = 4,
> > HRTIMER_MODE_REL_SOFT = 5,
> > HRTIMER_MODE_ABS_PINNED_SOFT = 6,
> > HRTIMER_MODE_REL_PINNED_SOFT = 7,
> > HRTIMER_MODE_ABS_HARD = 8,
> > HRTIMER_MODE_REL_HARD = 9,
> > HRTIMER_MODE_ABS_PINNED_HARD = 10,
> > HRTIMER_MODE_REL_PINNED_HARD = 11,
> > };
> >
> > Committer testing:
> >
> > root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS' --max-events=2
> > 0.000 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff2a5050, function: 0xffffffff9e22ddd0, expires: 241502326000000, softexpires: 241502326000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> > 18446744073709.488 :0/0 timer:hrtimer_start(hrtimer: 0xffff8d4eff425050, function: 0xffffffff9e22ddd0, expires: 241501814000000, softexpires: 241501814000000, mode: HRTIMER_MODE_ABS_PINNED_HARD)
> > root@x1:~# perf trace -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD' --max-events=2
> > 0.000 podman/510644 timer:hrtimer_start(hrtimer: 0xffffa2024f5f7dd0, function: 0xffffffff9e2170c0, expires: 241530497418194, softexpires: 241530497368194, mode: HRTIMER_MODE_REL)
> > 40.251 gnome-shell/2484 timer:hrtimer_start(hrtimer: 0xffff8d48bda17650, function: 0xffffffffc0661550, expires: 241550528619247, softexpires: 241550527619247, mode: HRTIMER_MODE_REL)
> > root@x1:~# perf trace -v -e timer:hrtimer_start --filter='mode != HRTIMER_MODE_ABS && mode != HRTIMER_MODE_ABS_PINNED_HARD && mode != HRTIMER_MODE_REL' --max-events=2
> > Using CPUID GenuineIntel-6-BA-3
> > vmlinux BTF loaded
> > <SNIP>
> > 0
> > 0xa
> > 0x1
> > New filter for timer:hrtimer_start: (mode != 0 && mode != 0xa && mode != 0x1) && (common_pid != 524049 && common_pid != 4041)
> > mmap size 528384B
> > ^Croot@x1:~#
> >
> > Suggested-by: Arnaldo Carvalho de Melo <acme@kernel.org>
> > Signed-off-by: Howard Chu <howardchu95@gmail.com>
> > Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > Cc: Adrian Hunter <adrian.hunter@intel.com>
> > Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> > Cc: Ian Rogers <irogers@google.com>
> > Cc: Ingo Molnar <mingo@redhat.com>
> > Cc: Jiri Olsa <jolsa@kernel.org>
> > Cc: Kan Liang <kan.liang@linux.intel.com>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > Cc: Namhyung Kim <namhyung@kernel.org>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Link: https://lore.kernel.org/lkml/ZnCcliuecJABD5FN@x1
> > Link: https://lore.kernel.org/r/20240624181345.124764-5-howardchu95@gmail.com
> > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > ---
> > tools/perf/builtin-trace.c | 62 ++++++++++++++++++++++++++++++++++----
> > 1 file changed, 56 insertions(+), 6 deletions(-)
> >
> > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > index 5618feb7d01a..e664001d5ed7 100644
> > --- a/tools/perf/builtin-trace.c
> > +++ b/tools/perf/builtin-trace.c
> > @@ -932,6 +932,37 @@ static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, stru
> > return arg_fmt->type == NULL ? -1 : 0;
> > }
> >
> > +static bool syscall_arg__strtoul_btf_enum(char *bf, size_t size, struct syscall_arg *arg, u64 *val)
> > +{
> > + const struct btf_type *bt;
> > + char *type = arg->parm;
> > + struct btf_enum *be;
> > + struct btf *btf;
> > +
> > + trace__load_vmlinux_btf(arg->trace);
> > +
> > + btf = arg->trace->btf;
> > + if (btf == NULL)
> > + return false;
> > +
> > + if (syscall_arg_fmt__cache_btf_enum(arg->fmt, btf, type) < 0)
> > + return false;
> > +
> > + bt = arg->fmt->type;
> > + be = btf_enum(bt);
> > + for (int i = 0; i < btf_vlen(bt); ++i, ++be) {
> > + const char *name = btf__name_by_offset(btf, be->name_off);
> > + int max_len = max(size, strlen(name));
> > +
> > + if (strncmp(name, bf, max_len) == 0) {
> > + *val = be->val;
> > + return true;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > +
> > static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
> > {
> > struct btf_enum *be = btf_enum(type);
> > @@ -965,8 +996,16 @@ static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, stru
> > {
> > return 0;
> > }
> > +
> > +static bool syscall_arg__strtoul_btf_enum(char *bf __maybe_unused, size_t size __maybe_unused,
> > + struct syscall_arg *arg __maybe_unused, u64 *val __maybe_unused)
> > +{
> > + return false;
> > +}
> > #endif // HAVE_LIBBPF_SUPPORT
> >
> > +#define STUL_BTF_ENUM syscall_arg__strtoul_btf_enum
> > +
> > #define STRARRAY(name, array) \
> > { .scnprintf = SCA_STRARRAY, \
> > .strtoul = STUL_STRARRAY, \
> > @@ -1867,6 +1906,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> > arg->scnprintf = SCA_FD;
> > } else if (strstr(field->type, "enum") && use_btf != NULL) {
> > *use_btf = arg->is_enum = true;
> > + arg->strtoul = STUL_BTF_ENUM;
> > } else {
> > const struct syscall_arg_fmt *fmt =
> > syscall_arg_fmt__find_by_name(field->name);
> > @@ -3792,7 +3832,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
> > return __trace__deliver_event(trace, event->event);
> > }
> >
> > -static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg)
> > +static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg,
> > + char **type)
> > {
> > struct tep_format_field *field;
> > struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
> > @@ -3801,13 +3842,15 @@ static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel
> > return NULL;
> >
> > for (field = evsel->tp_format->format.fields; field; field = field->next, ++fmt)
> > - if (strcmp(field->name, arg) == 0)
> > + if (strcmp(field->name, arg) == 0) {
> > + *type = field->type;
> > return fmt;
> > + }
> >
> > return NULL;
> > }
> >
> > -static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel *evsel)
> > +static int trace__expand_filter(struct trace *trace, struct evsel *evsel)
> > {
> > char *tok, *left = evsel->filter, *new_filter = evsel->filter;
> >
> > @@ -3840,14 +3883,14 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
> > struct syscall_arg_fmt *fmt;
> > int left_size = tok - left,
> > right_size = right_end - right;
> > - char arg[128];
> > + char arg[128], *type;
> >
> > while (isspace(left[left_size - 1]))
> > --left_size;
> >
> > scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
> >
> > - fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg);
> > + fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg, &type);
> > if (fmt == NULL) {
> > pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
> > arg, evsel->name, evsel->filter);
> > @@ -3860,9 +3903,16 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
> > if (fmt->strtoul) {
> > u64 val;
> > struct syscall_arg syscall_arg = {
> > - .parm = fmt->parm,
> > + .trace = trace,
> > + .fmt = fmt,
> > };
> >
> > + if (fmt->is_enum) {
> > + syscall_arg.parm = type;
> > + } else {
> > + syscall_arg.parm = fmt->parm;
> > + }
>
> Hi Howard,
>
> minor nit that cases like this shouldn't use curly braces as per:
> https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces
Thanks for the review. I think these two lines are deleted from
Arnaldo's patch 'perf trace: Remove arg_fmt->is_enum, we can get that
from the BTF type
(b06414bc07f59ef0269ceb60a63126a01ab8018f)' that's done on top of this
patch, so I didn't pay too much attention to this, sorry for the
confusion. I will reorganize this patch series.
Thanks,
Howard
>
> Thanks,
> Ian
>
> > +
> > if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
> > char *n, expansion[19];
> > int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
> > --
> > 2.45.2
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args
2024-07-10 17:54 ` Ian Rogers
@ 2024-07-11 15:16 ` Howard Chu
0 siblings, 0 replies; 14+ messages in thread
From: Howard Chu @ 2024-07-11 15:16 UTC (permalink / raw)
To: Ian Rogers
Cc: acme, adrian.hunter, jolsa, kan.liang, namhyung, linux-perf-users,
linux-kernel, Arnaldo Carvalho de Melo, Alexander Shishkin,
Günther Noack, Ingo Molnar, Mark Rutland,
Mickaël Salaün, Peter Zijlstra
Hello,
Thank you for the advice! Although I am not the person who wrote this
comment, I think it's good to change it to /* */ instead.
Thanks,
Howard
On Thu, Jul 11, 2024 at 1:54 AM Ian Rogers <irogers@google.com> wrote:
>
> On Fri, Jul 5, 2024 at 2:43 AM Howard Chu <howardchu95@gmail.com> wrote:
> >
> > In this patch, BTF is used to turn enum value to the corresponding
> > name. There is only one system call that uses enum value as its
> > argument, that is `landlock_add_rule()`.
> >
> > The vmlinux btf is loaded lazily, when user decided to trace the
> > `landlock_add_rule` syscall. But if one decide to run `perf trace`
> > without any arguments, the behaviour is to trace `landlock_add_rule`,
> > so vmlinux btf will be loaded by default.
> >
> > The laziest behaviour is to load vmlinux btf when a
> > `landlock_add_rule` syscall hits. But I think you could lose some
> > samples when loading vmlinux btf at run time, for it can delay the
> > handling of other samples. I might need your precious opinions on
> > this...
> >
> > before:
> >
> > ```
> > perf $ ./perf trace -e landlock_add_rule
> > 0.000 ( 0.008 ms): ldlck-test/438194 landlock_add_rule(rule_type: 2) = -1 EBADFD (File descriptor in bad state)
> > 0.010 ( 0.001 ms): ldlck-test/438194 landlock_add_rule(rule_type: 1) = -1 EBADFD (File descriptor in bad state)
> > ```
> >
> > after:
> >
> > ```
> > perf $ ./perf trace -e landlock_add_rule
> > 0.000 ( 0.029 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_NET_PORT) = -1 EBADFD (File descriptor in bad state)
> > 0.036 ( 0.004 ms): ldlck-test/438194 landlock_add_rule(rule_type: LANDLOCK_RULE_PATH_BENEATH) = -1 EBADFD (File descriptor in bad state)
> > ```
> >
> > Committer notes:
> >
> > Made it build with NO_LIBBPF=1, simplified btf_enum_fprintf(), see [1]
> > for the discussion.
> >
> > Signed-off-by: Howard Chu <howardchu95@gmail.com>
> > Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > Cc: Adrian Hunter <adrian.hunter@intel.com>
> > Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> > Cc: Günther Noack <gnoack@google.com>
> > Cc: Ian Rogers <irogers@google.com>
> > Cc: Ingo Molnar <mingo@redhat.com>
> > Cc: Jiri Olsa <jolsa@kernel.org>
> > Cc: Kan Liang <kan.liang@linux.intel.com>
> > Cc: Mark Rutland <mark.rutland@arm.com>
> > Cc: Mickaël Salaün <mic@digikod.net>
> > Cc: Namhyung Kim <namhyung@kernel.org>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Link: https://lore.kernel.org/lkml/20240613022757.3589783-1-howardchu95@gmail.com
> > Link: https://lore.kernel.org/lkml/ZnXAhFflUl_LV1QY@x1 # [1]
> > Link: https://lore.kernel.org/r/20240624181345.124764-3-howardchu95@gmail.com
> > Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
> > ---
> > tools/perf/builtin-trace.c | 110 +++++++++++++++++++++++++++++++++++--
> > 1 file changed, 106 insertions(+), 4 deletions(-)
> >
> > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > index 8449f2beb54d..1391564911d9 100644
> > --- a/tools/perf/builtin-trace.c
> > +++ b/tools/perf/builtin-trace.c
> > @@ -19,6 +19,7 @@
> > #ifdef HAVE_LIBBPF_SUPPORT
> > #include <bpf/bpf.h>
> > #include <bpf/libbpf.h>
> > +#include <bpf/btf.h>
> > #ifdef HAVE_BPF_SKEL
> > #include "bpf_skel/augmented_raw_syscalls.skel.h"
> > #endif
> > @@ -110,6 +111,10 @@ struct syscall_arg_fmt {
> > const char *name;
> > u16 nr_entries; // for arrays
> > bool show_zero;
> > + bool is_enum;
> > +#ifdef HAVE_LIBBPF_SUPPORT
> > + const struct btf_type *type;
> > +#endif
> > };
> >
> > struct syscall_fmt {
> > @@ -139,6 +144,9 @@ struct trace {
> > } syscalls;
> > #ifdef HAVE_BPF_SKEL
> > struct augmented_raw_syscalls_bpf *skel;
> > +#endif
> > +#ifdef HAVE_LIBBPF_SUPPORT
> > + struct btf *btf;
> > #endif
> > struct record_opts opts;
> > struct evlist *evlist;
> > @@ -204,6 +212,20 @@ struct trace {
> > } oe;
> > };
> >
> > +static void trace__load_vmlinux_btf(struct trace *trace __maybe_unused)
> > +{
> > +#ifdef HAVE_LIBBPF_SUPPORT
> > + if (trace->btf != NULL)
> > + return;
> > +
> > + trace->btf = btf__load_vmlinux_btf();
> > + if (verbose > 0) {
> > + fprintf(trace->output, trace->btf ? "vmlinux BTF loaded\n" :
> > + "Failed to load vmlinux BTF\n");
> > + }
> > +#endif
> > +}
> > +
> > struct tp_field {
> > int offset;
> > union {
> > @@ -887,6 +909,64 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
> >
> > #define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
> >
> > +#ifdef HAVE_LIBBPF_SUPPORT
> > +static int syscall_arg_fmt__cache_btf_enum(struct syscall_arg_fmt *arg_fmt, struct btf *btf, char *type)
> > +{
> > + int id;
> > +
> > + // Already cached?
>
> Hi Howard,
>
> I'm on nit patrol again, just to note that most comments are /* */
> style although we do have // comments - the ratio of /* */ to // is
> about 10:1. The kernel is similar in this regard. There's no clear
> guidance so we could ignore this, but fwiw I generally try to stick
> with /* */ for consistency with the rest of the surrounding code.
>
> Thanks,
> Ian
> > + if (arg_fmt->type != NULL)
> > + return 0;
> > +
> > + type = strstr(type, "enum ");
> > + if (type == NULL)
> > + return -1;
> > +
> > + type += 5; // skip "enum " to get the enumeration name
> > +
> > + id = btf__find_by_name(btf, type);
> > + if (id < 0)
> > + return -1;
> > +
> > + arg_fmt->type = btf__type_by_id(btf, id);
> > + return arg_fmt->type == NULL ? -1 : 0;
> > +}
> > +
> > +static size_t btf_enum_scnprintf(const struct btf_type *type, struct btf *btf, char *bf, size_t size, int val)
> > +{
> > + struct btf_enum *be = btf_enum(type);
> > + const int nr_entries = btf_vlen(type);
> > +
> > + for (int i = 0; i < nr_entries; ++i, ++be) {
> > + if (be->val == val) {
> > + return scnprintf(bf, size, "%s",
> > + btf__name_by_offset(btf, be->name_off));
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static size_t trace__btf_enum_scnprintf(struct trace *trace, struct syscall_arg_fmt *arg_fmt, char *bf,
> > + size_t size, int val, char *type)
> > +{
> > + if (trace->btf == NULL)
> > + return 0;
> > +
> > + if (syscall_arg_fmt__cache_btf_enum(arg_fmt, trace->btf, type) < 0)
> > + return 0;
> > +
> > + return btf_enum_scnprintf(arg_fmt->type, trace->btf, bf, size, val);
> > +}
> > +#else // HAVE_LIBBPF_SUPPORT
> > +static size_t trace__btf_enum_scnprintf(struct trace *trace __maybe_unused, struct syscall_arg_fmt *arg_fmt __maybe_unused,
> > + char *bf __maybe_unused, size_t size __maybe_unused, int val __maybe_unused,
> > + char *type __maybe_unused)
> > +{
> > + return 0;
> > +}
> > +#endif // HAVE_LIBBPF_SUPPORT
> > +
> > #define STRARRAY(name, array) \
> > { .scnprintf = SCA_STRARRAY, \
> > .strtoul = STUL_STRARRAY, \
> > @@ -1238,6 +1318,7 @@ struct syscall {
> > bool is_exit;
> > bool is_open;
> > bool nonexistent;
> > + bool use_btf;
> > struct tep_format_field *args;
> > const char *name;
> > const struct syscall_fmt *fmt;
> > @@ -1744,7 +1825,8 @@ static const struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *n
> > }
> >
> > static struct tep_format_field *
> > -syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field)
> > +syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field,
> > + bool *use_btf)
> > {
> > struct tep_format_field *last_field = NULL;
> > int len;
> > @@ -1756,6 +1838,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> > continue;
> >
> > len = strlen(field->name);
> > + arg->is_enum = false;
> >
> > if (strcmp(field->type, "const char *") == 0 &&
> > ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
> > @@ -1782,6 +1865,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> > * 7 unsigned long
> > */
> > arg->scnprintf = SCA_FD;
> > + } else if (strstr(field->type, "enum") && use_btf != NULL) {
> > + *use_btf = arg->is_enum = true;
> > } else {
> > const struct syscall_arg_fmt *fmt =
> > syscall_arg_fmt__find_by_name(field->name);
> > @@ -1798,7 +1883,8 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
> >
> > static int syscall__set_arg_fmts(struct syscall *sc)
> > {
> > - struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args);
> > + struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args,
> > + &sc->use_btf);
> >
> > if (last_field)
> > sc->args_size = last_field->offset + last_field->size;
> > @@ -1811,6 +1897,7 @@ static int trace__read_syscall_info(struct trace *trace, int id)
> > char tp_name[128];
> > struct syscall *sc;
> > const char *name = syscalltbl__name(trace->sctbl, id);
> > + int err;
> >
> > #ifdef HAVE_SYSCALL_TABLE_SUPPORT
> > if (trace->syscalls.table == NULL) {
> > @@ -1883,7 +1970,13 @@ static int trace__read_syscall_info(struct trace *trace, int id)
> > sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
> > sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
> >
> > - return syscall__set_arg_fmts(sc);
> > + err = syscall__set_arg_fmts(sc);
> > +
> > + /* after calling syscall__set_arg_fmts() we'll know whether use_btf is true */
> > + if (sc->use_btf)
> > + trace__load_vmlinux_btf(trace);
> > +
> > + return err;
> > }
> >
> > static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
> > @@ -1891,7 +1984,7 @@ static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
> > struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
> >
> > if (fmt != NULL) {
> > - syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
> > + syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields, NULL);
> > return 0;
> > }
> >
> > @@ -2103,6 +2196,15 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
> > if (trace->show_arg_names)
> > printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
> >
> > + if (sc->arg_fmt[arg.idx].is_enum) {
> > + size_t p = trace__btf_enum_scnprintf(trace, &sc->arg_fmt[arg.idx], bf + printed,
> > + size - printed, val, field->type);
> > + if (p) {
> > + printed += p;
> > + continue;
> > + }
> > + }
> > +
> > printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
> > bf + printed, size - printed, &arg, val);
> > }
> > --
> > 2.45.2
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-07-11 15:16 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-07-05 9:42 [PATCH v4 0/8] perf trace: Augment enum arguments with BTF Howard Chu
2024-07-05 9:42 ` [PATCH v5 1/8] perf trace: Fix iteration of syscall ids in syscalltbl->entries Howard Chu
2024-07-05 9:42 ` [PATCH v5 2/8] perf trace: BTF-based enum pretty printing for syscall args Howard Chu
2024-07-10 17:54 ` Ian Rogers
2024-07-11 15:16 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 3/8] perf trace: Augment non-syscall tracepoints with enum arguments with BTF Howard Chu
2024-07-05 9:42 ` [PATCH v5 4/8] perf trace: Filter enum arguments with enum names Howard Chu
2024-07-10 17:48 ` Ian Rogers
2024-07-11 15:14 ` Howard Chu
2024-07-05 9:42 ` [PATCH v5 5/8] perf test: Add landlock workload Howard Chu
2024-07-05 9:42 ` [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace' Howard Chu
2024-07-05 9:42 ` [PATCH v5 7/8] perf trace: Introduce trace__btf_scnprintf() Howard Chu
2024-07-05 9:43 ` [PATCH v5 8/8] perf trace: Remove arg_fmt->is_enum, we can get that from the BTF type Howard Chu
-- strict thread matches above, loose matches on Subject: below --
2024-07-05 13:20 [PATCH v5 0/8] perf trace: Augment enum arguments with BTF Howard Chu
2024-07-05 13:20 ` [PATCH v5 6/8] perf test trace_btf_enum: Add regression test for the BTF augmentation of enums in 'perf trace' Howard Chu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).