[PATCH v5 perf,bpf 14/15] perf: introduce side band thread

From: Song Liu
Date: Thu Feb 28 2019 - 00:07:48 EST


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@xxxxxx>
---
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(+)

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);

--
2.17.1