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

Message ID 20190228050643.958685-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. 28, 2019, 5:06 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(+)

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