All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Wangnan (F)" <wangnan0@huawei.com>
To: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: <ast@plumgrid.com>, <masami.hiramatsu.pt@hitachi.com>,
	<namhyung@kernel.org>, <a.p.zijlstra@chello.nl>,
	<brendan.d.gregg@gmail.com>, <daniel@iogearbox.net>,
	<dsahern@gmail.com>, <hekuang@huawei.com>, <jolsa@kernel.org>,
	<lizefan@huawei.com>, <paulus@samba.org>, <xiakaixu@huawei.com>,
	<pi3orama@163.com>, <linux-kernel@vger.kernel.org>,
	<acme@kernel.org>
Subject: Re: [PATCH 05/27] perf record, bpf: Parse and create probe points for BPF programs
Date: Thu, 17 Sep 2015 10:04:33 +0800	[thread overview]
Message-ID: <55FA1FB1.9010500@huawei.com> (raw)
In-Reply-To: <20150916214337.GJ11551@kernel.org>



On 2015/9/17 5:43, Arnaldo Carvalho de Melo wrote:
> Em Sun, Sep 06, 2015 at 07:13:21AM +0000, Wang Nan escreveu:
>> This patch introduces bpf__{un,}probe() functions to enable callers to
>> create kprobe points based on section names of BPF programs. It parses
> Ok, so now I see that when we do:
>
> 	perf record --event bpf_prog.o usleep 1
>
> We are potentially inserting multiple events, one for each eBPF section
> found in bpf_prog.o, right?

Yes.

> I.e. multiple evsels, so, when parsing, we should create the kprobes and
> from there then create evsels and insert in the normal list that would
> eventually get spliced to the evlist being processed, I think.
>
> So, and reading that comment on 4/27, we need to allow that to happen at
> parse_events() time, i.e. avoid adding a dummy evsel that would then,
> later, be "expanded" into potentially multiple non-dummy evsels.
>
> I put the first 3 patches, with some adjustments, in my perf/ebpf
> branch, will try to do the above, i.e. do away with that dummy, allow
> parsing the bpf_prog.o sections at parse_events() time.

Then I suggest a small interface modification in libbpf to return 
'struct bpf_object *',
then after loading we can iterator on each program in that object, creat 
kprobe points
then made evsels. We need to call convert_perf_probe_events() multiple 
times for each
object. Since Namhyung updates the probing interface, I think it becomes 
possible.

I'm glad to see you will working on this problem. If you have other 
ugrent business
to do, I think I can also start this work from Sept. 21 and will have 3 
days before
my vacation.

Thank you.

> - Arnaldo
>
>> the section names of each eBPF program and creates corresponding 'struct
>> perf_probe_event' structures. The parse_perf_probe_command() function is
>> used to do the main parsing work.
>>
>> Parsing result is stored into an array to satisify
>> {convert,apply}_perf_probe_events(). It accepts an array of
>> 'struct perf_probe_event' and do all the work in one call.
>>
>> Define PERF_BPF_PROBE_GROUP as "perf_bpf_probe", which will be used as
>> the group name of all eBPF probing points.
>>
>> probe_conf.max_probes is set to MAX_PROBES to support glob matching.
>>
>> Before ending of bpf__probe(), data in each 'struct perf_probe_event' is
>> cleaned. Things will be changed by following patches because they need
>> 'struct probe_trace_event' in them,
>>
>> Signed-off-by: Wang Nan <wangnan0@huawei.com>
>> Cc: Alexei Starovoitov <ast@plumgrid.com>
>> Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
>> Cc: Daniel Borkmann <daniel@iogearbox.net>
>> Cc: David Ahern <dsahern@gmail.com>
>> Cc: He Kuang <hekuang@huawei.com>
>> Cc: Jiri Olsa <jolsa@kernel.org>
>> Cc: Kaixu Xia <xiakaixu@huawei.com>
>> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
>> Cc: Namhyung Kim <namhyung@kernel.org>
>> Cc: Paul Mackerras <paulus@samba.org>
>> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
>> Cc: Zefan Li <lizefan@huawei.com>
>> Cc: pi3orama@163.com
>> Link: http://lkml.kernel.org/n/1436445342-1402-21-git-send-email-wangnan0@huawei.com
>> Link: http://lkml.kernel.org/n/1436445342-1402-23-git-send-email-wangnan0@huawei.com
>> [Merged by two patches
>>   wangnan: Utilize new perf probe API {convert,apply,cleanup}_perf_probe_events()
>> ]
>> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
>> ---
>>   tools/perf/builtin-record.c  |  19 +++++-
>>   tools/perf/util/bpf-loader.c | 149 +++++++++++++++++++++++++++++++++++++++++++
>>   tools/perf/util/bpf-loader.h |  13 ++++
>>   3 files changed, 180 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
>> index f886706..b56109f 100644
>> --- a/tools/perf/builtin-record.c
>> +++ b/tools/perf/builtin-record.c
>> @@ -1141,7 +1141,23 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
>>   	if (err)
>>   		goto out_bpf_clear;
>>   
>> -	err = -ENOMEM;
>> +	/*
>> +	 * bpf__probe must be called before symbol__init() because we
>> +	 * need init_symbol_maps. If called after symbol__init,
>> +	 * symbol_conf.sort_by_name won't take effect.
>> +	 *
>> +	 * bpf__unprobe() is safe even if bpf__probe() failed, and it
>> +	 * also calls symbol__init. Therefore, goto out_symbol_exit
>> +	 * is safe when probe failed.
>> +	 */
>> +	err = bpf__probe();
>> +	if (err) {
>> +		bpf__strerror_probe(err, errbuf, sizeof(errbuf));
>> +
>> +		pr_err("Probing at events in BPF object failed.\n");
>> +		pr_err("\t%s\n", errbuf);
>> +		goto out_symbol_exit;
>> +	}
>>   
>>   	symbol__init(NULL);
>>   
>> @@ -1202,6 +1218,7 @@ out_symbol_exit:
>>   	perf_evlist__delete(rec->evlist);
>>   	symbol__exit();
>>   	auxtrace_record__free(rec->itr);
>> +	bpf__unprobe();
>>   out_bpf_clear:
>>   	bpf__clear();
>>   	return err;
>> diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
>> index 88531ea..10505cb 100644
>> --- a/tools/perf/util/bpf-loader.c
>> +++ b/tools/perf/util/bpf-loader.c
>> @@ -9,6 +9,8 @@
>>   #include "perf.h"
>>   #include "debug.h"
>>   #include "bpf-loader.h"
>> +#include "probe-event.h"
>> +#include "probe-finder.h"
>>   
>>   #define DEFINE_PRINT_FN(name, level) \
>>   static int libbpf_##name(const char *fmt, ...)	\
>> @@ -28,6 +30,58 @@ DEFINE_PRINT_FN(debug, 1)
>>   
>>   static bool libbpf_initialized;
>>   
>> +static int
>> +config_bpf_program(struct bpf_program *prog, struct perf_probe_event *pev)
>> +{
>> +	const char *config_str;
>> +	int err;
>> +
>> +	config_str = bpf_program__title(prog, false);
>> +	if (!config_str) {
>> +		pr_debug("bpf: unable to get title for program\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	pr_debug("bpf: config program '%s'\n", config_str);
>> +	err = parse_perf_probe_command(config_str, pev);
>> +	if (err < 0) {
>> +		pr_debug("bpf: '%s' is not a valid config string\n",
>> +			 config_str);
>> +		/* parse failed, don't need clear pev. */
>> +		return -EINVAL;
>> +	}
>> +
>> +	if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
>> +		pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
>> +			 config_str, PERF_BPF_PROBE_GROUP);
>> +		err = -EINVAL;
>> +		goto errout;
>> +	} else if (!pev->group)
>> +		pev->group = strdup(PERF_BPF_PROBE_GROUP);
>> +
>> +	if (!pev->group) {
>> +		pr_debug("bpf: strdup failed\n");
>> +		err = -ENOMEM;
>> +		goto errout;
>> +	}
>> +
>> +	if (!pev->event) {
>> +		pr_debug("bpf: '%s': event name is missing\n",
>> +			 config_str);
>> +		err = -EINVAL;
>> +		goto errout;
>> +	}
>> +
>> +	pr_debug("bpf: config '%s' is ok\n", config_str);
>> +
>> +	return 0;
>> +
>> +errout:
>> +	if (pev)
>> +		clear_perf_probe_event(pev);
>> +	return err;
>> +}
>> +
>>   int bpf__prepare_load(const char *filename)
>>   {
>>   	struct bpf_object *obj;
>> @@ -59,6 +113,90 @@ void bpf__clear(void)
>>   		bpf_object__close(obj);
>>   }
>>   
>> +static bool is_probed;
>> +
>> +int bpf__unprobe(void)
>> +{
>> +	struct strfilter *delfilter;
>> +	int ret;
>> +
>> +	if (!is_probed)
>> +		return 0;
>> +
>> +	delfilter = strfilter__new(PERF_BPF_PROBE_GROUP ":*", NULL);
>> +	if (!delfilter) {
>> +		pr_debug("Failed to create delfilter when unprobing\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	ret = del_perf_probe_events(delfilter);
>> +	strfilter__delete(delfilter);
>> +	if (ret < 0 && is_probed)
>> +		pr_debug("Error: failed to delete events: %s\n",
>> +			 strerror(-ret));
>> +	else
>> +		is_probed = false;
>> +	return ret < 0 ? ret : 0;
>> +}
>> +
>> +int bpf__probe(void)
>> +{
>> +	int err, nr_events = 0;
>> +	struct bpf_object *obj, *tmp;
>> +	struct bpf_program *prog;
>> +	struct perf_probe_event *pevs;
>> +
>> +	pevs = calloc(MAX_PROBES, sizeof(pevs[0]));
>> +	if (!pevs)
>> +		return -ENOMEM;
>> +
>> +	bpf_object__for_each_safe(obj, tmp) {
>> +		bpf_object__for_each_program(prog, obj) {
>> +			err = config_bpf_program(prog, &pevs[nr_events++]);
>> +			if (err < 0)
>> +				goto out;
>> +
>> +			if (nr_events >= MAX_PROBES) {
>> +				pr_debug("Too many (more than %d) events\n",
>> +					 MAX_PROBES);
>> +				err = -ERANGE;
>> +				goto out;
>> +			};
>> +		}
>> +	}
>> +
>> +	if (!nr_events) {
>> +		/*
>> +		 * Don't call following code to prevent perf report failure
>> +		 * init_symbol_maps can fail when perf is started by non-root
>> +		 * user, which prevent non-root user track normal events even
>> +		 * without using BPF, because bpf__probe() is called by
>> +		 * 'perf record' unconditionally.
>> +		 */
>> +		err = 0;
>> +		goto out;
>> +	}
>> +
>> +	probe_conf.max_probes = MAX_PROBES;
>> +	/* Let convert_perf_probe_events generates probe_trace_event (tevs) */
>> +	err = convert_perf_probe_events(pevs, nr_events);
>> +	if (err < 0) {
>> +		pr_debug("bpf_probe: failed to convert perf probe events");
>> +		goto out;
>> +	}
>> +
>> +	err = apply_perf_probe_events(pevs, nr_events);
>> +	if (err < 0)
>> +		pr_debug("bpf probe: failed to probe events\n");
>> +	else
>> +		is_probed = true;
>> +out_cleanup:
>> +	cleanup_perf_probe_events(pevs, nr_events);
>> +out:
>> +	free(pevs);
>> +	return err < 0 ? err : 0;
>> +}
>> +
>>   #define bpf__strerror_head(err, buf, size) \
>>   	char sbuf[STRERR_BUFSIZE], *emsg;\
>>   	if (!size)\
>> @@ -90,3 +228,14 @@ int bpf__strerror_prepare_load(const char *filename, int err,
>>   	bpf__strerror_end(buf, size);
>>   	return 0;
>>   }
>> +
>> +int bpf__strerror_probe(int err, char *buf, size_t size)
>> +{
>> +	bpf__strerror_head(err, buf, size);
>> +	bpf__strerror_entry(ERANGE, "Too many (more than %d) events",
>> +			    MAX_PROBES);
>> +	bpf__strerror_entry(ENOENT, "Selected kprobe point doesn't exist.");
>> +	bpf__strerror_entry(EEXIST, "Selected kprobe point already exist, try perf probe -d '*'.");
>> +	bpf__strerror_end(buf, size);
>> +	return 0;
>> +}
>> diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
>> index 12be630..6b09a85 100644
>> --- a/tools/perf/util/bpf-loader.h
>> +++ b/tools/perf/util/bpf-loader.h
>> @@ -9,10 +9,15 @@
>>   #include <string.h>
>>   #include "debug.h"
>>   
>> +#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
>> +
>>   #ifdef HAVE_LIBBPF_SUPPORT
>>   int bpf__prepare_load(const char *filename);
>>   int bpf__strerror_prepare_load(const char *filename, int err,
>>   			       char *buf, size_t size);
>> +int bpf__probe(void);
>> +int bpf__unprobe(void);
>> +int bpf__strerror_probe(int err, char *buf, size_t size);
>>   
>>   void bpf__clear(void);
>>   #else
>> @@ -22,6 +27,8 @@ static inline int bpf__prepare_load(const char *filename __maybe_unused)
>>   	return -1;
>>   }
>>   
>> +static inline int bpf__probe(void) { return 0; }
>> +static inline int bpf__unprobe(void) { return 0; }
>>   static inline void bpf__clear(void) { }
>>   
>>   static inline int
>> @@ -43,5 +50,11 @@ bpf__strerror_prepare_load(const char *filename __maybe_unused,
>>   {
>>   	return __bpf_strerror(buf, size);
>>   }
>> +
>> +static inline int bpf__strerror_probe(int err __maybe_unused,
>> +				      char *buf, size_t size)
>> +{
>> +	return __bpf_strerror(buf, size);
>> +}
>>   #endif
>>   #endif
>> -- 
>> 2.1.0
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/



  reply	other threads:[~2015-09-17  2:06 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-06  7:13 [GIT PULL 00/27] perf tools: filtering events using eBPF programs Wang Nan
2015-09-06  7:13 ` [PATCH 01/27] perf tools: Don't write to evsel if parser doesn't collect evsel Wang Nan
2015-09-23  8:43   ` [tip:perf/core] perf tools: Don' t assume that the parser returns non empty evsel list tip-bot for Wang Nan
2015-09-06  7:13 ` [PATCH 02/27] perf tools: Make perf depend on libbpf Wang Nan
2015-09-06  7:13 ` [PATCH 03/27] perf ebpf: Add the libbpf glue Wang Nan
2015-09-06  7:13 ` [PATCH 04/27] perf tools: Enable passing bpf object file to --event Wang Nan
2015-09-06  7:13 ` [PATCH 05/27] perf record, bpf: Parse and create probe points for BPF programs Wang Nan
2015-09-16 21:43   ` Arnaldo Carvalho de Melo
2015-09-17  2:04     ` Wangnan (F) [this message]
2015-09-06  7:13 ` [PATCH 06/27] perf bpf: Collect 'struct perf_probe_event' for bpf_program Wang Nan
2015-09-06  7:13 ` [PATCH 07/27] perf record: Load all eBPF object into kernel Wang Nan
2015-09-06  7:13 ` [PATCH 08/27] perf tools: Add bpf_fd field to evsel and config it Wang Nan
2015-09-06  7:13 ` [PATCH 09/27] perf tools: Attach eBPF program to perf event Wang Nan
2015-09-06  7:13 ` [PATCH 10/27] perf tools: Allow BPF placeholder dummy events to collect --filter options Wang Nan
2015-09-06  7:13 ` [PATCH 11/27] perf tools: Sync setting of real bpf events with placeholder Wang Nan
2015-09-06  7:13 ` [PATCH 12/27] perf record: Add clang options for compiling BPF scripts Wang Nan
2015-09-06  7:13 ` [PATCH 13/27] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event Wang Nan
2015-09-06  7:13 ` [PATCH 14/27] perf test: Enforce LLVM test for BPF test Wang Nan
2015-09-06  7:13 ` [PATCH 15/27] perf test: Add 'perf test BPF' Wang Nan
2015-09-06  7:13 ` [PATCH 16/27] bpf tools: Load a program with different instances using preprocessor Wang Nan
2015-09-06  7:13 ` [PATCH 17/27] perf probe: Reset args and nargs for probe_trace_event when failure Wang Nan
2015-09-06  7:13 ` [PATCH 18/27] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan
2015-09-16  7:30   ` [tip:perf/core] perf tools: regs_query_register_offset() infrastructure tip-bot for Wang Nan
2015-09-06  7:13 ` [PATCH 19/27] perf tools: Introduce regs_query_register_offset() for x86 Wang Nan
2015-09-14 21:37   ` Arnaldo Carvalho de Melo
2015-09-15  1:36     ` Wangnan (F)
2015-09-16  7:30   ` [tip:perf/core] perf tools: Introduce regs_query_register_offset( ) " tip-bot for Wang Nan
2015-09-06  7:13 ` [PATCH 20/27] perf tools: Add prologue for BPF programs for fetching arguments Wang Nan
2015-09-06  7:13 ` [PATCH 21/27] perf tools: Generate prologue for BPF programs Wang Nan
2015-09-06  7:13 ` [PATCH 22/27] perf tools: Use same BPF program if arguments are identical Wang Nan
2015-09-06  7:13 ` [PATCH 23/27] perf record: Support custom vmlinux path Wang Nan
2015-09-06  7:13 ` [PATCH 24/27] perf probe: Init symbol as kprobe Wang Nan
2015-09-06  7:13 ` [PATCH 25/27] perf tools: Allow BPF program attach to uprobe events Wang Nan
2015-09-06  7:13 ` [PATCH 26/27] perf test: Enforce LLVM test, add kbuild test Wang Nan
2015-09-06  7:13 ` [PATCH 27/27] perf test: Test BPF prologue Wang Nan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55FA1FB1.9010500@huawei.com \
    --to=wangnan0@huawei.com \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=acme@redhat.com \
    --cc=ast@plumgrid.com \
    --cc=brendan.d.gregg@gmail.com \
    --cc=daniel@iogearbox.net \
    --cc=dsahern@gmail.com \
    --cc=hekuang@huawei.com \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lizefan@huawei.com \
    --cc=masami.hiramatsu.pt@hitachi.com \
    --cc=namhyung@kernel.org \
    --cc=paulus@samba.org \
    --cc=pi3orama@163.com \
    --cc=xiakaixu@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.