Adding thread process and API to start/stop it.

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

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 253bafd4dbe7..6ad57ba6657e 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -65,6 +65,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;
@@ -74,6 +79,8 @@ struct record_thread {
        struct record            *rec;
        unsigned long long        samples;
        u64                       bytes_written;
+       pthread_t                 pt;
+       int                       state;
 };
 
 struct record {
@@ -1145,6 +1152,80 @@ 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; i < rec->threads_cnt; i++) {
+               struct record_thread *th = threads + i;
+
+               th->state = RECORD_THREAD__STOP;
+       }
+
+       for (i = 1; !err && i < rec->threads_cnt; i++) {
+               struct record_thread *th = threads + i;
+
+               err = pthread_join(th->pt, NULL);
+       }
+
+       return err;
+}
+
 static int __cmd_record(struct record *rec, int argc, const char **argv)
 {
        int err;
@@ -1270,6 +1351,14 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
                goto out_child;
        }
 
+       /*
+        * We need to call this before record__synthesize, so in case we
+        * sample system wide perf threads get synthesized as well.
+        */
+       err = record__threads_start(rec);
+       if (err < 0)
+               goto out_child;
+
        err = record__synthesize(rec, false);
        if (err < 0)
                goto out_child;
@@ -1450,6 +1539,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.17.1

Reply via email to