[v4,perf,bpf,14/15] perf: introduce side band thread
diff mbox series

Message ID 20190226002019.3748539-15-songliubraving@fb.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series
  • perf annotation of BPF programs
Related show

Commit Message

Song Liu Feb. 26, 2019, 12:20 a.m. UTC
This patch introduces side band thread that captures extended information
for events like PERF_RECORD_BPF_EVENT.

This new thread uses its own evlist that uses ring buffer with very low
watermark for lower latency. In the next patch, we uses this thread to
handle PERF_RECORD_BPF_EVENT.

Signed-off-by: Song Liu <songliubraving@fb.com>
---
 tools/perf/builtin-record.c |   7 +++
 tools/perf/builtin-top.c    |   7 +++
 tools/perf/util/evlist.c    | 100 ++++++++++++++++++++++++++++++++++++
 tools/perf/util/evlist.h    |  13 +++++
 4 files changed, 127 insertions(+)

Comments

Jiri Olsa Feb. 27, 2019, 1:21 p.m. UTC | #1
On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:

SNIP

> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index 8c902276d4b4..61b87c8111e6 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -19,6 +19,7 @@
>  #include "debug.h"
>  #include "units.h"
>  #include "asm/bug.h"
> +#include "bpf-event.h"
>  #include <signal.h>
>  #include <unistd.h>
>  
> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>  	}
>  	return leader;
>  }
> +
> +static struct perf_evlist *sb_evlist;
> +pthread_t poll_thread;

so some of the things are static and some like poll_args
you alloced on the stack.. I dont like this interface,
could we come up with something generic? perhaps
encapsulated in perf_evlist, like:

struct perf_evlist {
	...
	struct {
		pthread_t	th;
		int		state;
	} thread;
};

typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)

perf_evlist__start_thread(perf_evlist, perf_evlist__thread_cb_t cb);
perf_evlist__stop_thread(perf_evlist);


jirka
Song Liu Feb. 27, 2019, 5:52 p.m. UTC | #2
> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
> 
> SNIP
> 
>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>> index 8c902276d4b4..61b87c8111e6 100644
>> --- a/tools/perf/util/evlist.c
>> +++ b/tools/perf/util/evlist.c
>> @@ -19,6 +19,7 @@
>> #include "debug.h"
>> #include "units.h"
>> #include "asm/bug.h"
>> +#include "bpf-event.h"
>> #include <signal.h>
>> #include <unistd.h>
>> 
>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>> 	}
>> 	return leader;
>> }
>> +
>> +static struct perf_evlist *sb_evlist;
>> +pthread_t poll_thread;
> 
> so some of the things are static and some like poll_args
> you alloced on the stack.. I dont like this interface,
> could we come up with something generic? perhaps
> encapsulated in perf_evlist, like:

I picked global sb_evlist and poll_thread because there 
should be only one sb_evlist and one thread polling it. 
There might be multiple evsel on the sb_evlist. 

I am not sure I understand your suggestion..

> struct perf_evlist {
> 	...
> 	struct {
> 		pthread_t	th;
> 		int		state;
> 	} thread;

This will not be used by the main perf_evlist, right?

> };
> 
> typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)

How do we use this callback? We need a way to specify which
events to poll (mmap, bpf_event, ksymbol, etc). How do we do 
that with the callback function?

Thanks,
Song

> perf_evlist__start_thread(perf_evlist, perf_evlist__thread_cb_t cb);
> perf_evlist__stop_thread(perf_evlist);
> 
> 
> jirka
Jiri Olsa March 4, 2019, 1:52 p.m. UTC | #3
On Wed, Feb 27, 2019 at 05:52:52PM +0000, Song Liu wrote:
> 
> 
> > On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> > 
> > On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
> > 
> > SNIP
> > 
> >> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >> index 8c902276d4b4..61b87c8111e6 100644
> >> --- a/tools/perf/util/evlist.c
> >> +++ b/tools/perf/util/evlist.c
> >> @@ -19,6 +19,7 @@
> >> #include "debug.h"
> >> #include "units.h"
> >> #include "asm/bug.h"
> >> +#include "bpf-event.h"
> >> #include <signal.h>
> >> #include <unistd.h>
> >> 
> >> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
> >> 	}
> >> 	return leader;
> >> }
> >> +
> >> +static struct perf_evlist *sb_evlist;
> >> +pthread_t poll_thread;
> > 
> > so some of the things are static and some like poll_args
> > you alloced on the stack.. I dont like this interface,
> > could we come up with something generic? perhaps
> > encapsulated in perf_evlist, like:
> 
> I picked global sb_evlist and poll_thread because there 
> should be only one sb_evlist and one thread polling it. 
> There might be multiple evsel on the sb_evlist. 
> 
> I am not sure I understand your suggestion..
> 
> > struct perf_evlist {
> > 	...
> > 	struct {
> > 		pthread_t	th;
> > 		int		state;
> > 	} thread;
> 
> This will not be used by the main perf_evlist, right?

no, just by the thread interface

> 
> > };
> > 
> > typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)
> 
> How do we use this callback? We need a way to specify which
> events to poll (mmap, bpf_event, ksymbol, etc). How do we do 
> that with the callback function?

you provide your own callback

jirka
Song Liu March 4, 2019, 7:49 p.m. UTC | #4
> On Mar 4, 2019, at 5:52 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Wed, Feb 27, 2019 at 05:52:52PM +0000, Song Liu wrote:
>> 
>> 
>>> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
>>> 
>>> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
>>> 
>>> SNIP
>>> 
>>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>>>> index 8c902276d4b4..61b87c8111e6 100644
>>>> --- a/tools/perf/util/evlist.c
>>>> +++ b/tools/perf/util/evlist.c
>>>> @@ -19,6 +19,7 @@
>>>> #include "debug.h"
>>>> #include "units.h"
>>>> #include "asm/bug.h"
>>>> +#include "bpf-event.h"
>>>> #include <signal.h>
>>>> #include <unistd.h>
>>>> 
>>>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>>>> 	}
>>>> 	return leader;
>>>> }
>>>> +
>>>> +static struct perf_evlist *sb_evlist;
>>>> +pthread_t poll_thread;
>>> 
>>> so some of the things are static and some like poll_args
>>> you alloced on the stack.. I dont like this interface,
>>> could we come up with something generic? perhaps
>>> encapsulated in perf_evlist, like:
>> 
>> I picked global sb_evlist and poll_thread because there 
>> should be only one sb_evlist and one thread polling it. 
>> There might be multiple evsel on the sb_evlist. 
>> 
>> I am not sure I understand your suggestion..
>> 
>>> struct perf_evlist {
>>> 	...
>>> 	struct {
>>> 		pthread_t	th;
>>> 		int		state;
>>> 	} thread;
>> 
>> This will not be used by the main perf_evlist, right?
> 
> no, just by the thread interface

What is "state" here?

> 
>> 
>>> };
>>> 
>>> typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)
>> 
>> How do we use this callback? We need a way to specify which
>> events to poll (mmap, bpf_event, ksymbol, etc). How do we do 
>> that with the callback function?
> 
> you provide your own callback

I guess I get your point now. I can try that. 

Thanks,
Song

> jirka
Jiri Olsa March 4, 2019, 8:41 p.m. UTC | #5
On Mon, Mar 04, 2019 at 07:49:06PM +0000, Song Liu wrote:
> 
> 
> > On Mar 4, 2019, at 5:52 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> > 
> > On Wed, Feb 27, 2019 at 05:52:52PM +0000, Song Liu wrote:
> >> 
> >> 
> >>> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> >>> 
> >>> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
> >>> 
> >>> SNIP
> >>> 
> >>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >>>> index 8c902276d4b4..61b87c8111e6 100644
> >>>> --- a/tools/perf/util/evlist.c
> >>>> +++ b/tools/perf/util/evlist.c
> >>>> @@ -19,6 +19,7 @@
> >>>> #include "debug.h"
> >>>> #include "units.h"
> >>>> #include "asm/bug.h"
> >>>> +#include "bpf-event.h"
> >>>> #include <signal.h>
> >>>> #include <unistd.h>
> >>>> 
> >>>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
> >>>> 	}
> >>>> 	return leader;
> >>>> }
> >>>> +
> >>>> +static struct perf_evlist *sb_evlist;
> >>>> +pthread_t poll_thread;
> >>> 
> >>> so some of the things are static and some like poll_args
> >>> you alloced on the stack.. I dont like this interface,
> >>> could we come up with something generic? perhaps
> >>> encapsulated in perf_evlist, like:
> >> 
> >> I picked global sb_evlist and poll_thread because there 
> >> should be only one sb_evlist and one thread polling it. 
> >> There might be multiple evsel on the sb_evlist. 
> >> 
> >> I am not sure I understand your suggestion..
> >> 
> >>> struct perf_evlist {
> >>> 	...
> >>> 	struct {
> >>> 		pthread_t	th;
> >>> 		int		state;
> >>> 	} thread;
> >> 
> >> This will not be used by the main perf_evlist, right?
> > 
> > no, just by the thread interface
> 
> What is "state" here?

it's replacement for the 'done' pointer u had,
which I did not like.. leting each thread having
its own state is better IMO

jirka
Song Liu March 4, 2019, 8:44 p.m. UTC | #6
> On Mar 4, 2019, at 12:41 PM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Mon, Mar 04, 2019 at 07:49:06PM +0000, Song Liu wrote:
>> 
>> 
>>> On Mar 4, 2019, at 5:52 AM, Jiri Olsa <jolsa@redhat.com> wrote:
>>> 
>>> On Wed, Feb 27, 2019 at 05:52:52PM +0000, Song Liu wrote:
>>>> 
>>>> 
>>>>> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
>>>>> 
>>>>> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
>>>>> 
>>>>> SNIP
>>>>> 
>>>>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>>>>>> index 8c902276d4b4..61b87c8111e6 100644
>>>>>> --- a/tools/perf/util/evlist.c
>>>>>> +++ b/tools/perf/util/evlist.c
>>>>>> @@ -19,6 +19,7 @@
>>>>>> #include "debug.h"
>>>>>> #include "units.h"
>>>>>> #include "asm/bug.h"
>>>>>> +#include "bpf-event.h"
>>>>>> #include <signal.h>
>>>>>> #include <unistd.h>
>>>>>> 
>>>>>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>>>>>> 	}
>>>>>> 	return leader;
>>>>>> }
>>>>>> +
>>>>>> +static struct perf_evlist *sb_evlist;
>>>>>> +pthread_t poll_thread;
>>>>> 
>>>>> so some of the things are static and some like poll_args
>>>>> you alloced on the stack.. I dont like this interface,
>>>>> could we come up with something generic? perhaps
>>>>> encapsulated in perf_evlist, like:
>>>> 
>>>> I picked global sb_evlist and poll_thread because there 
>>>> should be only one sb_evlist and one thread polling it. 
>>>> There might be multiple evsel on the sb_evlist. 
>>>> 
>>>> I am not sure I understand your suggestion..
>>>> 
>>>>> struct perf_evlist {
>>>>> 	...
>>>>> 	struct {
>>>>> 		pthread_t	th;
>>>>> 		int		state;
>>>>> 	} thread;
>>>> 
>>>> This will not be used by the main perf_evlist, right?
>>> 
>>> no, just by the thread interface
>> 
>> What is "state" here?
> 
> it's replacement for the 'done' pointer u had,
> which I did not like.. leting each thread having
> its own state is better IMO
> 
> jirka

I see. Let me try that. 

Song
Song Liu March 4, 2019, 9:40 p.m. UTC | #7
> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
> 
> SNIP
> 
>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>> index 8c902276d4b4..61b87c8111e6 100644
>> --- a/tools/perf/util/evlist.c
>> +++ b/tools/perf/util/evlist.c
>> @@ -19,6 +19,7 @@
>> #include "debug.h"
>> #include "units.h"
>> #include "asm/bug.h"
>> +#include "bpf-event.h"
>> #include <signal.h>
>> #include <unistd.h>
>> 
>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>> 	}
>> 	return leader;
>> }
>> +
>> +static struct perf_evlist *sb_evlist;
>> +pthread_t poll_thread;
> 
> so some of the things are static and some like poll_args
> you alloced on the stack.. I dont like this interface,
> could we come up with something generic? perhaps
> encapsulated in perf_evlist, like:
> 
> struct perf_evlist {
> 	...
> 	struct {
> 		pthread_t	th;
> 		int		state;
> 	} thread;
> };
> 
> typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)
> 
> perf_evlist__start_thread(perf_evlist, perf_evlist__thread_cb_t cb);
> perf_evlist__stop_thread(perf_evlist);
> 
> 
> jirka

More questions on this proposal: 

IIUC, this approach creates one perf_evlist and one thread for each side band
event (only bpf for now, more afterwards). Each of these perf_evlists will 
create its own ring buffer. 

On the other hand, current patch allows different events to share the thread, 
the perf_evlist, and the ring buffer. 

If my understanding is correct, current patch would be more efficient down the 
road? Did I miss some downsides of current patch?

Thanks,
Song
Jiri Olsa March 5, 2019, 11:03 a.m. UTC | #8
On Mon, Mar 04, 2019 at 09:40:07PM +0000, Song Liu wrote:
> 
> 
> > On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> > 
> > On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
> > 
> > SNIP
> > 
> >> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> >> index 8c902276d4b4..61b87c8111e6 100644
> >> --- a/tools/perf/util/evlist.c
> >> +++ b/tools/perf/util/evlist.c
> >> @@ -19,6 +19,7 @@
> >> #include "debug.h"
> >> #include "units.h"
> >> #include "asm/bug.h"
> >> +#include "bpf-event.h"
> >> #include <signal.h>
> >> #include <unistd.h>
> >> 
> >> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
> >> 	}
> >> 	return leader;
> >> }
> >> +
> >> +static struct perf_evlist *sb_evlist;
> >> +pthread_t poll_thread;
> > 
> > so some of the things are static and some like poll_args
> > you alloced on the stack.. I dont like this interface,
> > could we come up with something generic? perhaps
> > encapsulated in perf_evlist, like:
> > 
> > struct perf_evlist {
> > 	...
> > 	struct {
> > 		pthread_t	th;
> > 		int		state;
> > 	} thread;
> > };
> > 
> > typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)
> > 
> > perf_evlist__start_thread(perf_evlist, perf_evlist__thread_cb_t cb);
> > perf_evlist__stop_thread(perf_evlist);
> > 
> > 
> > jirka
> 
> More questions on this proposal: 
> 
> IIUC, this approach creates one perf_evlist and one thread for each side band
> event (only bpf for now, more afterwards). Each of these perf_evlists will 
> create its own ring buffer. 
> 
> On the other hand, current patch allows different events to share the thread, 
> the perf_evlist, and the ring buffer. 

you can have those events in single evlist no?

> 
> If my understanding is correct, current patch would be more efficient down the 
> road? Did I miss some downsides of current patch?

I'd just like something configurable and with single handle
not scattered around the code, so it's easy to add new callback 

jirka
Song Liu March 5, 2019, 8:37 p.m. UTC | #9
> On Mar 5, 2019, at 3:03 AM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Mon, Mar 04, 2019 at 09:40:07PM +0000, Song Liu wrote:
>> 
>> 
>>> On Feb 27, 2019, at 5:21 AM, Jiri Olsa <jolsa@redhat.com> wrote:
>>> 
>>> On Mon, Feb 25, 2019 at 04:20:18PM -0800, Song Liu wrote:
>>> 
>>> SNIP
>>> 
>>>> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
>>>> index 8c902276d4b4..61b87c8111e6 100644
>>>> --- a/tools/perf/util/evlist.c
>>>> +++ b/tools/perf/util/evlist.c
>>>> @@ -19,6 +19,7 @@
>>>> #include "debug.h"
>>>> #include "units.h"
>>>> #include "asm/bug.h"
>>>> +#include "bpf-event.h"
>>>> #include <signal.h>
>>>> #include <unistd.h>
>>>> 
>>>> @@ -1841,3 +1842,102 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
>>>> 	}
>>>> 	return leader;
>>>> }
>>>> +
>>>> +static struct perf_evlist *sb_evlist;
>>>> +pthread_t poll_thread;
>>> 
>>> so some of the things are static and some like poll_args
>>> you alloced on the stack.. I dont like this interface,
>>> could we come up with something generic? perhaps
>>> encapsulated in perf_evlist, like:
>>> 
>>> struct perf_evlist {
>>> 	...
>>> 	struct {
>>> 		pthread_t	th;
>>> 		int		state;
>>> 	} thread;
>>> };
>>> 
>>> typedef int (perf_evlist__thread_cb_t)(perf_evlist, union perf_event *event,....)
>>> 
>>> perf_evlist__start_thread(perf_evlist, perf_evlist__thread_cb_t cb);
>>> perf_evlist__stop_thread(perf_evlist);
>>> 
>>> 
>>> jirka
>> 
>> More questions on this proposal: 
>> 
>> IIUC, this approach creates one perf_evlist and one thread for each side band
>> event (only bpf for now, more afterwards). Each of these perf_evlists will 
>> create its own ring buffer. 
>> 
>> On the other hand, current patch allows different events to share the thread, 
>> the perf_evlist, and the ring buffer. 
> 
> you can have those events in single evlist no?
> 
>> 
>> If my understanding is correct, current patch would be more efficient down the 
>> road? Did I miss some downsides of current patch?
> 
> I'd just like something configurable and with single handle
> not scattered around the code, so it's easy to add new callback 
> 
> jirka

To make adding callbacks easy, we need to register callback per perf_evsel, so 
multiple side band events could share the perf_evlist. It will be something like:

typedef int (perf_evsel__sb_cb_t)(union perf_event *event, void *data);

struct perf_evsel {
	...
	struct {
		perf_evsel__sb_cb_t *cb;
		void *data;
	} side_band;
};

perf_evlist__add_sb_event(struct perf_evlist *evlist, 
			  struct perf_event_attr *attr, 
			  perf_evsel__sb_cb_t cb, 
			  void *data);
perf_evlist__start_sb_evlist(struct perf_evlist *evlist);
perf_evlist__stop_sb_evlist(struct perf_evlist *evlist);


Does this look like a good approach?

Thanks,
Song

Patch
diff mbox series

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2355e0a9eda0..d10c1d5a9e89 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1106,6 +1106,7 @@  static int __cmd_record(struct record *rec, int argc, const char **argv)
 	struct perf_data *data = &rec->data;
 	struct perf_session *session;
 	bool disabled = false, draining = false;
+	struct perf_evlist_sb_poll_args poll_args;
 	int fd;
 
 	atexit(record__sig_exit);
@@ -1206,6 +1207,10 @@  static int __cmd_record(struct record *rec, int argc, const char **argv)
 		goto out_child;
 	}
 
+	poll_args.env = &session->header.env;
+	poll_args.done = &done;
+	perf_evlist__start_polling_thread(&rec->opts.target, &poll_args);
+
 	err = record__synthesize(rec, false);
 	if (err < 0)
 		goto out_child;
@@ -1456,6 +1461,8 @@  static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 out_delete_session:
 	perf_session__delete(session);
+
+	perf_evlist__stop_polling_thread();
 	return status;
 }
 
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index ccdf5689452f..f41545445917 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1524,6 +1524,7 @@  int cmd_top(int argc, const char **argv)
 			"number of thread to run event synthesize"),
 	OPT_END()
 	};
+	struct perf_evlist_sb_poll_args poll_args;
 	const char * const top_usage[] = {
 		"perf top [<options>]",
 		NULL
@@ -1654,8 +1655,14 @@  int cmd_top(int argc, const char **argv)
 
 	top.record_opts.bpf_event = !top.no_bpf_event;
 
+	poll_args.env = &perf_env;
+	poll_args.done = &done;
+	perf_evlist__start_polling_thread(target, &poll_args);
+
 	status = __cmd_top(&top);
 
+	perf_evlist__stop_polling_thread();
+
 out_delete_evlist:
 	perf_evlist__delete(top.evlist);
 
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 8c902276d4b4..61b87c8111e6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -19,6 +19,7 @@ 
 #include "debug.h"
 #include "units.h"
 #include "asm/bug.h"
+#include "bpf-event.h"
 #include <signal.h>
 #include <unistd.h>
 
@@ -1841,3 +1842,102 @@  struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list,
 	}
 	return leader;
 }
+
+static struct perf_evlist *sb_evlist;
+pthread_t poll_thread;
+
+int perf_evlist__new_side_band_event(struct perf_event_attr *attr)
+{
+	struct perf_evsel *evsel;
+
+	if (!sb_evlist)
+		sb_evlist = perf_evlist__new();
+
+	if (!sb_evlist)
+		return -1;
+
+	evsel = perf_evsel__new_idx(attr, sb_evlist->nr_entries);
+	if (!evsel)
+		goto out_err;
+
+	perf_evlist__add(sb_evlist, evsel);
+	return 0;
+
+out_err:
+	perf_evlist__delete(sb_evlist);
+	return -1;
+}
+
+static void *perf_evlist__poll_thread(void *arg)
+{
+	struct perf_evlist_sb_poll_args *args = arg;
+	int i;
+
+	while (!*(args->done)) {
+		perf_evlist__poll(sb_evlist, 1000);
+
+		for (i = 0; i < sb_evlist->nr_mmaps; i++) {
+			struct perf_mmap *map = &sb_evlist->mmap[i];
+			union perf_event *event;
+
+			if (perf_mmap__read_init(map))
+				continue;
+			while ((event = perf_mmap__read_event(map)) != NULL) {
+				pr_debug("processing vip event of type %d\n",
+					 event->header.type);
+				switch (event->header.type) {
+				default:
+					break;
+				}
+				perf_mmap__consume(map);
+			}
+			perf_mmap__read_done(map);
+		}
+	}
+	return NULL;
+}
+
+int perf_evlist__start_polling_thread(struct target *target,
+				      struct perf_evlist_sb_poll_args *args)
+{
+	struct perf_evsel *counter;
+
+	if (sb_evlist == NULL)
+		return 0;
+
+	if (perf_evlist__create_maps(sb_evlist, target))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(sb_evlist, counter) {
+		if (perf_evsel__open(counter, sb_evlist->cpus,
+				     sb_evlist->threads) < 0)
+			goto out_delete_evlist;
+	}
+
+	if (perf_evlist__mmap(sb_evlist, UINT_MAX))
+		goto out_delete_evlist;
+
+	evlist__for_each_entry(sb_evlist, counter) {
+		if (perf_evsel__enable(counter))
+			goto out_delete_evlist;
+	}
+
+	if (pthread_create(&poll_thread, NULL, perf_evlist__poll_thread, args))
+		goto out_delete_evlist;
+
+	return 0;
+
+out_delete_evlist:
+	perf_evlist__delete(sb_evlist);
+	sb_evlist = NULL;
+	return -1;
+}
+
+void perf_evlist__stop_polling_thread(void)
+{
+	if (!sb_evlist)
+		return;
+	pthread_join(poll_thread, NULL);
+	perf_evlist__exit(sb_evlist);
+	sb_evlist = NULL;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 868294491194..4182e50659e0 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -58,6 +58,12 @@  struct perf_evsel_str_handler {
 	void	   *handler;
 };
 
+struct perf_evlist_sb_poll_args {
+	struct perf_env	*env;
+
+	volatile int	*done;
+};
+
 struct perf_evlist *perf_evlist__new(void);
 struct perf_evlist *perf_evlist__new_default(void);
 struct perf_evlist *perf_evlist__new_dummy(void);
@@ -84,6 +90,13 @@  int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
 
 int perf_evlist__add_dummy(struct perf_evlist *evlist);
 
+int perf_evlist__new_side_band_event(struct perf_event_attr *attr);
+
+int perf_evlist__start_polling_thread(struct target *target,
+				      struct perf_evlist_sb_poll_args *args);
+
+void perf_evlist__stop_polling_thread(void);
+
 int perf_evlist__add_newtp(struct perf_evlist *evlist,
 			   const char *sys, const char *name, void *handler);