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

perf bpf: Allow BPF program config probing options

By extending the syntax of BPF object section names, this patch allows users to
config probing options like what they can do in 'perf probe'.

The error message in 'perf probe' is also updated.

Test result:

For following BPF file test_probe_glob.c:

# cat test_probe_glob.c
__attribute__((section("inlines=no;func=SyS_dup?"), used))

int func(void *ctx)
{
return 1;
}

char _license[] __attribute__((section("license"), used)) = "GPL";
int _version __attribute__((section("version"), used)) = 0x40300;
#
# ./perf record -e ./test_probe_glob.c ls /
...
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data ]
# ./perf evlist
perf_bpf_probe:func_1
perf_bpf_probe:func

After changing "inlines=no" to "inlines=yes":

# ./perf record -e ./test_probe_glob.c ls /
...
[ perf record: Woken up 2 times to write data ]
[ perf record: Captured and wrote 0.013 MB perf.data ]
# ./perf evlist
perf_bpf_probe:func_3
perf_bpf_probe:func_2
perf_bpf_probe:func_1
perf_bpf_probe:func

Then test 'force':

Use following program:

# cat test_probe_force.c
__attribute__((section("func=sys_write"), used))

int funca(void *ctx)
{
return 1;
}

__attribute__((section("force=yes;func=sys_write"), used))

int funcb(void *ctx)
{
return 1;
}

char _license[] __attribute__((section("license"), used)) = "GPL";
int _version __attribute__((section("version"), used)) = 0x40300;
#

# perf record -e ./test_probe_force.c usleep 1
Error: event "func" already exists.
Hint: Remove existing event by 'perf probe -d'
or force duplicates by 'perf probe -f'
or set 'force=yes' in BPF source.
event syntax error: './test_probe_force.c'
\___ Probe point exist. Try 'perf probe -d "*"' and set 'force=yes'

(add -v to see detail)
...

Then replace 'force=no' to 'force=yes':

# vim test_probe_force.c
# perf record -e ./test_probe_force.c usleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.017 MB perf.data ]
# perf evlist
perf_bpf_probe:func_1
perf_bpf_probe:func
#

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1447675815-166222-7-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
03e01f56 5dbd16c0

+56 -4
+51 -2
tools/perf/util/bpf-loader.c
··· 7 7 8 8 #include <bpf/libbpf.h> 9 9 #include <linux/err.h> 10 + #include <linux/string.h> 10 11 #include "perf.h" 11 12 #include "debug.h" 12 13 #include "bpf-loader.h" ··· 130 129 return 0; 131 130 } 132 131 132 + static int 133 + config__bool(const char *value, 134 + bool *pbool, bool invert) 135 + { 136 + int err; 137 + bool bool_value; 138 + 139 + if (!pbool) 140 + return -EINVAL; 141 + 142 + err = strtobool(value, &bool_value); 143 + if (err) 144 + return err; 145 + 146 + *pbool = invert ? !bool_value : bool_value; 147 + return 0; 148 + } 149 + 150 + static int 151 + config__inlines(const char *value, 152 + struct perf_probe_event *pev __maybe_unused) 153 + { 154 + return config__bool(value, &probe_conf.no_inlines, true); 155 + } 156 + 157 + static int 158 + config__force(const char *value, 159 + struct perf_probe_event *pev __maybe_unused) 160 + { 161 + return config__bool(value, &probe_conf.force_add, false); 162 + } 163 + 133 164 static struct { 134 165 const char *key; 135 166 const char *usage; ··· 179 146 .usage = "module=<module name> ", 180 147 .desc = "Set kprobe module", 181 148 .func = config__module, 182 - } 149 + }, 150 + { 151 + .key = "inlines", 152 + .usage = "inlines=[yes|no] ", 153 + .desc = "Probe at inline symbol", 154 + .func = config__inlines, 155 + }, 156 + { 157 + .key = "force", 158 + .usage = "force=[yes|no] ", 159 + .desc = "Forcibly add events with existing name", 160 + .func = config__force, 161 + }, 183 162 }; 184 163 185 164 static int ··· 284 239 struct bpf_prog_priv *priv = NULL; 285 240 const char *config_str; 286 241 int err; 242 + 243 + /* Initialize per-program probing setting */ 244 + probe_conf.no_inlines = false; 245 + probe_conf.force_add = false; 287 246 288 247 config_str = bpf_program__title(prog, false); 289 248 if (IS_ERR(config_str)) { ··· 593 544 scnprintf(buf, size, "%s (add -v to see detail)", emsg); 594 545 break; 595 546 } 596 - bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); 547 + bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'"); 597 548 bpf__strerror_entry(EACCES, "You need to be root"); 598 549 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0"); 599 550 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
+5 -2
tools/perf/util/probe-event.c
··· 2326 2326 goto out; 2327 2327 2328 2328 if (!allow_suffix) { 2329 - pr_warning("Error: event \"%s\" already exists. " 2330 - "(Use -f to force duplicates.)\n", buf); 2329 + pr_warning("Error: event \"%s\" already exists.\n" 2330 + " Hint: Remove existing event by 'perf probe -d'\n" 2331 + " or force duplicates by 'perf probe -f'\n" 2332 + " or set 'force=yes' in BPF source.\n", 2333 + buf); 2331 2334 ret = -EEXIST; 2332 2335 goto out; 2333 2336 }