[PATCH 43/49] perf record: Add record_thread start/stop/process functions

Jiri Olsa
2018-01-09T15:37:46Z

Adding thread process and API to start/stop it.

Link: http://lkml.kernel.org/n/tip-bwa3w7lt63ffe78w4ggjc9dw@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
tools/perf/builtin-record.c | 83 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index fb15d4457cfa..5457eacf8821 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -64,6 +64,11 @@ struct switch_output {
bool set;
};

+enum {
+ RECORD_THREAD__RUNNING = 0,
+ RECORD_THREAD__STOP = 1,
+};
+
struct record_thread {
struct perf_mmap **mmap;
int mmap_nr;
@@ -73,6 +78,8 @@ struct record_thread {
struct record *rec;
unsigned long long samples;
u64 bytes_written;
+ pthread_t pt;
+ int state;
};

struct record {
@@ -1114,6 +1121,75 @@ record__threads_config(struct record *rec)
return ret;
}

+static void*
+record_thread__process(struct record *rec)
+{
+ while (thread->state != RECORD_THREAD__STOP) {
+ unsigned long long hits = thread->samples;
+ int err;
+
+ if (record__mmap_read_all(thread->rec) < 0)
+ break;
+
+ if (hits == thread->samples) {
+ err = fdarray__poll(&thread->pollfd, 500);
+ /*
+ * Propagate error, only if there's any. Ignore positive
+ * number of returned events and interrupt error.
+ */
+ if (err > 0 || (err < 0 && errno == EINTR))
+ err = 0;
+ rec->waking++;
+
+ if (fdarray__filter(&thread->pollfd, POLLERR|POLLHUP,
+ perf_mmap__put_filtered, NULL) == 0)
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static void *worker(void *arg)
+{
+ struct record_thread *th = arg;
+ struct record *rec = th->rec;
+
+ thread = th;
+ thread->state = RECORD_THREAD__RUNNING;
+
+ return record_thread__process(rec);
+}
+
+static int record__threads_start(struct record *rec)
+{
+ struct record_thread *threads = rec->threads;
+ int i, err = 0;
+
+ for (i = 1; !err && i < rec->threads_cnt; i++) {
+ struct record_thread *th = threads + i;
+
+ err = pthread_create(&th->pt, NULL, worker, th);
+ }
+
+ return err;
+}
+
+static int record__threads_stop(struct record *rec)
+{
+ struct record_thread *threads = rec->threads;
+ int i, err = 0;
+
+ for (i = 1; !err && i < rec->threads_cnt; i++) {
+ struct record_thread *th = threads + i;
+
+ th->state = RECORD_THREAD__STOP;
+ err = pthread_join(th->pt, NULL);
+ }
+
+ return err;
+}
+
static int __cmd_record(struct record *rec, int argc, const char **argv)
{
int err;
@@ -1250,6 +1326,10 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
}
}

+ err = record__threads_start(rec);
+ if (err < 0)
+ goto out_child;
+
/*
* When perf is starting the traced process, all the events
* (apart from group members) have enable_on_exec=1 set,
@@ -1414,6 +1494,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
trigger_off(&auxtrace_snapshot_trigger);
trigger_off(&switch_output_trigger);

+ if (record__threads_stop(rec))
+ pr_err("failed to stop threads\n");
+
if (forks && workload_exec_errno) {
char msg[STRERR_BUFSIZE];
const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
--
2.13.6