diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-09 05:47:15 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-28 07:26:14 -0500 |
commit | 35b9d88ecd8c5fb720ba0dd325262f356d0b03e7 (patch) | |
tree | 536902f734862d5b04a6122c81386fddb19f4bcd /tools/perf/util/evlist.c | |
parent | 0f82ebc452f921590e216b28eee0b41f5e434a48 (diff) |
perf evlist: Introduce {prepare,start}_workload refactored from 'perf record'
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>
Diffstat (limited to 'tools/perf/util/evlist.c')
-rw-r--r-- | tools/perf/util/evlist.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b774341e797f..a472247af191 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include "thread_map.h" | 13 | #include "thread_map.h" |
14 | #include "evlist.h" | 14 | #include "evlist.h" |
15 | #include "evsel.h" | 15 | #include "evsel.h" |
16 | #include <unistd.h> | ||
16 | 17 | ||
17 | #include "parse-events.h" | 18 | #include "parse-events.h" |
18 | 19 | ||
@@ -33,6 +34,7 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
33 | INIT_HLIST_HEAD(&evlist->heads[i]); | 34 | INIT_HLIST_HEAD(&evlist->heads[i]); |
34 | INIT_LIST_HEAD(&evlist->entries); | 35 | INIT_LIST_HEAD(&evlist->entries); |
35 | perf_evlist__set_maps(evlist, cpus, threads); | 36 | perf_evlist__set_maps(evlist, cpus, threads); |
37 | evlist->workload.pid = -1; | ||
36 | } | 38 | } |
37 | 39 | ||
38 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, | 40 | struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, |
@@ -674,3 +676,97 @@ out_err: | |||
674 | 676 | ||
675 | return err; | 677 | return err; |
676 | } | 678 | } |
679 | |||
680 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | ||
681 | struct perf_record_opts *opts, | ||
682 | const char *argv[]) | ||
683 | { | ||
684 | int child_ready_pipe[2], go_pipe[2]; | ||
685 | char bf; | ||
686 | |||
687 | if (pipe(child_ready_pipe) < 0) { | ||
688 | perror("failed to create 'ready' pipe"); | ||
689 | return -1; | ||
690 | } | ||
691 | |||
692 | if (pipe(go_pipe) < 0) { | ||
693 | perror("failed to create 'go' pipe"); | ||
694 | goto out_close_ready_pipe; | ||
695 | } | ||
696 | |||
697 | evlist->workload.pid = fork(); | ||
698 | if (evlist->workload.pid < 0) { | ||
699 | perror("failed to fork"); | ||
700 | goto out_close_pipes; | ||
701 | } | ||
702 | |||
703 | if (!evlist->workload.pid) { | ||
704 | if (opts->pipe_output) | ||
705 | dup2(2, 1); | ||
706 | |||
707 | close(child_ready_pipe[0]); | ||
708 | close(go_pipe[1]); | ||
709 | fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); | ||
710 | |||
711 | /* | ||
712 | * Do a dummy execvp to get the PLT entry resolved, | ||
713 | * so we avoid the resolver overhead on the real | ||
714 | * execvp call. | ||
715 | */ | ||
716 | execvp("", (char **)argv); | ||
717 | |||
718 | /* | ||
719 | * Tell the parent we're ready to go | ||
720 | */ | ||
721 | close(child_ready_pipe[1]); | ||
722 | |||
723 | /* | ||
724 | * Wait until the parent tells us to go. | ||
725 | */ | ||
726 | if (read(go_pipe[0], &bf, 1) == -1) | ||
727 | perror("unable to read pipe"); | ||
728 | |||
729 | execvp(argv[0], (char **)argv); | ||
730 | |||
731 | perror(argv[0]); | ||
732 | kill(getppid(), SIGUSR1); | ||
733 | exit(-1); | ||
734 | } | ||
735 | |||
736 | if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) | ||
737 | evlist->threads->map[0] = evlist->workload.pid; | ||
738 | |||
739 | close(child_ready_pipe[1]); | ||
740 | close(go_pipe[0]); | ||
741 | /* | ||
742 | * wait for child to settle | ||
743 | */ | ||
744 | if (read(child_ready_pipe[0], &bf, 1) == -1) { | ||
745 | perror("unable to read pipe"); | ||
746 | goto out_close_pipes; | ||
747 | } | ||
748 | |||
749 | evlist->workload.cork_fd = go_pipe[1]; | ||
750 | close(child_ready_pipe[0]); | ||
751 | return 0; | ||
752 | |||
753 | out_close_pipes: | ||
754 | close(go_pipe[0]); | ||
755 | close(go_pipe[1]); | ||
756 | out_close_ready_pipe: | ||
757 | close(child_ready_pipe[0]); | ||
758 | close(child_ready_pipe[1]); | ||
759 | return -1; | ||
760 | } | ||
761 | |||
762 | int perf_evlist__start_workload(struct perf_evlist *evlist) | ||
763 | { | ||
764 | if (evlist->workload.cork_fd > 0) { | ||
765 | /* | ||
766 | * Remove the cork, let it rip! | ||
767 | */ | ||
768 | return close(evlist->workload.cork_fd); | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||