perf evlist: Introduce {prepare,start}_workload refactored from 'perf record'
authorArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 9 Nov 2011 10:47:15 +0000 (08:47 -0200)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 28 Nov 2011 12:26:14 +0000 (10:26 -0200)
So that we can easily start a workload in other tools.

Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-zdsksd4aphu0nltg2lpwsw3x@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-record.c
tools/perf/perf.h
tools/perf/util/evlist.c
tools/perf/util/evlist.h

index c3ac5415c097ca3009af0393ea355dc7f36aa6d9..4799195ed246fae9f6e00d839742ded920c75a4a 100644 (file)
@@ -47,11 +47,9 @@ static struct perf_record_opts record_opts = {
 static unsigned int            page_size;
 static unsigned int            mmap_pages                      = UINT_MAX;
 static int                     output;
-static int                     pipe_output                     =      0;
 static const char              *output_name                    = NULL;
 static bool                    group                           =  false;
 static int                     realtime_prio                   =      0;
-static pid_t                   child_pid                       =     -1;
 static enum write_mode_t       write_mode                      = WRITE_FORCE;
 static bool                    no_buildid                      =  false;
 static bool                    no_buildid_cache                =  false;
@@ -144,9 +142,9 @@ static void sig_atexit(void)
 {
        int status;
 
-       if (child_pid > 0) {
+       if (evsel_list->workload.pid > 0) {
                if (!child_finished)
-                       kill(child_pid, SIGTERM);
+                       kill(evsel_list->workload.pid, SIGTERM);
 
                wait(&status);
                if (WIFSIGNALED(status))
@@ -304,7 +302,7 @@ static int process_buildids(void)
 
 static void atexit_header(void)
 {
-       if (!pipe_output) {
+       if (!record_opts.pipe_output) {
                session->header.data_size += bytes_written;
 
                if (!no_buildid)
@@ -377,9 +375,7 @@ static int __cmd_record(int argc, const char **argv)
        int flags;
        int err;
        unsigned long waking = 0;
-       int child_ready_pipe[2], go_pipe[2];
        const bool forks = argc > 0;
-       char buf;
        struct machine *machine;
 
        progname = argv[0];
@@ -391,20 +387,15 @@ static int __cmd_record(int argc, const char **argv)
        signal(SIGINT, sig_handler);
        signal(SIGUSR1, sig_handler);
 
-       if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
-               perror("failed to create pipes");
-               exit(-1);
-       }
-
        if (!output_name) {
                if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode))
-                       pipe_output = true;
+                       record_opts.pipe_output = true;
                else
                        output_name = "perf.data";
        }
        if (output_name) {
                if (!strcmp(output_name, "-"))
-                       pipe_output = true;
+                       record_opts.pipe_output = true;
                else if (!stat(output_name, &st) && st.st_size) {
                        if (write_mode == WRITE_FORCE) {
                                char oldname[PATH_MAX];
@@ -424,7 +415,7 @@ static int __cmd_record(int argc, const char **argv)
        else
                flags |= O_TRUNC;
 
-       if (pipe_output)
+       if (record_opts.pipe_output)
                output = STDOUT_FILENO;
        else
                output = open(output_name, flags, S_IRUSR | S_IWUSR);
@@ -470,57 +461,11 @@ static int __cmd_record(int argc, const char **argv)
                mmap_pages = (512 * 1024) / page_size;
 
        if (forks) {
-               child_pid = fork();
-               if (child_pid < 0) {
-                       perror("failed to fork");
-                       exit(-1);
-               }
-
-               if (!child_pid) {
-                       if (pipe_output)
-                               dup2(2, 1);
-                       close(child_ready_pipe[0]);
-                       close(go_pipe[1]);
-                       fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
-
-                       /*
-                        * Do a dummy execvp to get the PLT entry resolved,
-                        * so we avoid the resolver overhead on the real
-                        * execvp call.
-                        */
-                       execvp("", (char **)argv);
-
-                       /*
-                        * Tell the parent we're ready to go
-                        */
-                       close(child_ready_pipe[1]);
-
-                       /*
-                        * Wait until the parent tells us to go.
-                        */
-                       if (read(go_pipe[0], &buf, 1) == -1)
-                               perror("unable to read pipe");
-
-                       execvp(argv[0], (char **)argv);
-
-                       perror(argv[0]);
-                       kill(getppid(), SIGUSR1);
-                       exit(-1);
-               }
-
-               if (!record_opts.system_wide && record_opts.target_tid == -1 && record_opts.target_pid == -1)
-                       evsel_list->threads->map[0] = child_pid;
-
-               close(child_ready_pipe[1]);
-               close(go_pipe[0]);
-               /*
-                * wait for child to settle
-                */
-               if (read(child_ready_pipe[0], &buf, 1) == -1) {
-                       perror("unable to read pipe");
-                       exit(-1);
+               err = perf_evlist__prepare_workload(evsel_list, &record_opts, argv);
+               if (err < 0) {
+                       pr_err("Couldn't run the workload!\n");
+                       goto out_delete_session;
                }
-               close(child_ready_pipe[0]);
        }
 
        open_counters(evsel_list);
@@ -530,7 +475,7 @@ static int __cmd_record(int argc, const char **argv)
         */
        atexit(atexit_header);
 
-       if (pipe_output) {
+       if (record_opts.pipe_output) {
                err = perf_header__write_pipe(output);
                if (err < 0)
                        return err;
@@ -543,7 +488,7 @@ static int __cmd_record(int argc, const char **argv)
 
        post_processing_offset = lseek(output, 0, SEEK_CUR);
 
-       if (pipe_output) {
+       if (record_opts.pipe_output) {
                err = perf_session__synthesize_attrs(session,
                                                     process_synthesized_event);
                if (err < 0) {
@@ -629,7 +574,7 @@ static int __cmd_record(int argc, const char **argv)
         * Let the child rip
         */
        if (forks)
-               close(go_pipe[1]);
+               perf_evlist__start_workload(evsel_list);
 
        for (;;) {
                int hits = samples;
index eb6a13881887818ba24731d85cc906aa42b6aecb..32ee6ca8eabd2b47d5235ac94a0dc7ed59b01fba 100644 (file)
@@ -193,6 +193,7 @@ struct perf_record_opts {
        bool         no_delay;
        bool         no_inherit;
        bool         no_samples;
+       bool         pipe_output;
        bool         raw_samples;
        bool         sample_address;
        bool         sample_time;
index b774341e797fffbbf39f125ea94e1dee74aa2fe6..a472247af191b3178e984eae71c1608cf7cb7176 100644 (file)
@@ -13,6 +13,7 @@
 #include "thread_map.h"
 #include "evlist.h"
 #include "evsel.h"
+#include <unistd.h>
 
 #include "parse-events.h"
 
@@ -33,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
                INIT_HLIST_HEAD(&evlist->heads[i]);
        INIT_LIST_HEAD(&evlist->entries);
        perf_evlist__set_maps(evlist, cpus, threads);
+       evlist->workload.pid = -1;
 }
 
 struct perf_evlist *perf_evlist__new(struct cpu_map *cpus,
@@ -674,3 +676,97 @@ out_err:
 
        return err;
 }
+
+int perf_evlist__prepare_workload(struct perf_evlist *evlist,
+                                 struct perf_record_opts *opts,
+                                 const char *argv[])
+{
+       int child_ready_pipe[2], go_pipe[2];
+       char bf;
+
+       if (pipe(child_ready_pipe) < 0) {
+               perror("failed to create 'ready' pipe");
+               return -1;
+       }
+
+       if (pipe(go_pipe) < 0) {
+               perror("failed to create 'go' pipe");
+               goto out_close_ready_pipe;
+       }
+
+       evlist->workload.pid = fork();
+       if (evlist->workload.pid < 0) {
+               perror("failed to fork");
+               goto out_close_pipes;
+       }
+
+       if (!evlist->workload.pid) {
+               if (opts->pipe_output)
+                       dup2(2, 1);
+
+               close(child_ready_pipe[0]);
+               close(go_pipe[1]);
+               fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
+
+               /*
+                * Do a dummy execvp to get the PLT entry resolved,
+                * so we avoid the resolver overhead on the real
+                * execvp call.
+                */
+               execvp("", (char **)argv);
+
+               /*
+                * Tell the parent we're ready to go
+                */
+               close(child_ready_pipe[1]);
+
+               /*
+                * Wait until the parent tells us to go.
+                */
+               if (read(go_pipe[0], &bf, 1) == -1)
+                       perror("unable to read pipe");
+
+               execvp(argv[0], (char **)argv);
+
+               perror(argv[0]);
+               kill(getppid(), SIGUSR1);
+               exit(-1);
+       }
+
+       if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1)
+               evlist->threads->map[0] = evlist->workload.pid;
+
+       close(child_ready_pipe[1]);
+       close(go_pipe[0]);
+       /*
+        * wait for child to settle
+        */
+       if (read(child_ready_pipe[0], &bf, 1) == -1) {
+               perror("unable to read pipe");
+               goto out_close_pipes;
+       }
+
+       evlist->workload.cork_fd = go_pipe[1];
+       close(child_ready_pipe[0]);
+       return 0;
+
+out_close_pipes:
+       close(go_pipe[0]);
+       close(go_pipe[1]);
+out_close_ready_pipe:
+       close(child_ready_pipe[0]);
+       close(child_ready_pipe[1]);
+       return -1;
+}
+
+int perf_evlist__start_workload(struct perf_evlist *evlist)
+{
+       if (evlist->workload.cork_fd > 0) {
+               /*
+                * Remove the cork, let it rip!
+                */
+               return close(evlist->workload.cork_fd);
+       }
+
+       return 0;
+}
index 231c06f8286b4cc9b157311e9d2e7a52b4c635f1..07d56b3e6d610a19064e55ee566485ed42b88c15 100644 (file)
@@ -6,6 +6,7 @@
 #include "../perf.h"
 #include "event.h"
 #include "util.h"
+#include <unistd.h>
 
 struct pollfd;
 struct thread_map;
@@ -22,6 +23,10 @@ struct perf_evlist {
        int              nr_fds;
        int              nr_mmaps;
        int              mmap_len;
+       struct {
+               int     cork_fd;
+               pid_t   pid;
+       } workload;
        bool             overwrite;
        union perf_event event_copy;
        struct perf_mmap *mmap;
@@ -68,6 +73,11 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group);
 void perf_evlist__config_attrs(struct perf_evlist *evlist,
                               struct perf_record_opts *opts);
 
+int perf_evlist__prepare_workload(struct perf_evlist *evlist,
+                                 struct perf_record_opts *opts,
+                                 const char *argv[]);
+int perf_evlist__start_workload(struct perf_evlist *evlist);
+
 int perf_evlist__alloc_mmap(struct perf_evlist *evlist);
 int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite);
 void perf_evlist__munmap(struct perf_evlist *evlist);