x86_64: Print modules like i386 does
[safe/jmp/linux-2.6] / tools / perf / builtin-record.c
index 4decbd1..2654253 100644 (file)
@@ -123,7 +123,8 @@ static void write_event(event_t *buf, size_t size)
        write_output(buf, size);
 }
 
-static int process_synthesized_event(event_t *event)
+static int process_synthesized_event(event_t *event,
+                                    struct perf_session *self __used)
 {
        write_event(event, event->header.size);
        return 0;
@@ -277,7 +278,7 @@ static void create_counter(int counter, int cpu, pid_t pid)
 
        attr->mmap              = track;
        attr->comm              = track;
-       attr->inherit           = (cpu < 0) && inherit;
+       attr->inherit           = inherit;
        attr->disabled          = 1;
 
 try_again:
@@ -409,6 +410,9 @@ 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 = target_pid == -1 && argc > 0;
+       char buf;
 
        page_size = sysconf(_SC_PAGE_SIZE);
        nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
@@ -419,11 +423,25 @@ static int __cmd_record(int argc, const char **argv)
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
 
+       if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
+               perror("failed to create pipes");
+               exit(-1);
+       }
+
        if (!stat(output_name, &st) && st.st_size) {
-               if (!force && !append_file) {
-                       fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n",
-                                       output_name);
-                       exit(-1);
+               if (!force) {
+                       if (!append_file) {
+                               pr_err("Error, output file %s exists, use -A "
+                                      "to append or -f to overwrite.\n",
+                                      output_name);
+                               exit(-1);
+                       }
+               } else {
+                       char oldname[PATH_MAX];
+                       snprintf(oldname, sizeof(oldname), "%s.old",
+                                output_name);
+                       unlink(oldname);
+                       rename(output_name, oldname);
                }
        } else {
                append_file = 0;
@@ -466,56 +484,79 @@ static int __cmd_record(int argc, const char **argv)
 
        atexit(atexit_header);
 
-       if (!system_wide) {
-               pid = target_pid;
-               if (pid == -1)
-                       pid = getpid();
-
-               open_counters(profile_cpu, pid);
-       } else {
-               if (profile_cpu != -1) {
-                       open_counters(profile_cpu, target_pid);
-               } else {
-                       for (i = 0; i < nr_cpus; i++)
-                               open_counters(i, target_pid);
+       if (forks) {
+               pid = fork();
+               if (pid < 0) {
+                       perror("failed to fork");
+                       exit(-1);
                }
-       }
 
-       if (file_new) {
-               err = perf_header__write(&session->header, output, false);
-               if (err < 0)
-                       return err;
-       }
+               if (!pid) {
+                       close(child_ready_pipe[0]);
+                       close(go_pipe[1]);
+                       fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
 
-       if (!system_wide)
-               event__synthesize_thread(pid, process_synthesized_event);
-       else
-               event__synthesize_threads(process_synthesized_event);
+                       /*
+                        * Do a dummy execvp to get the PLT entry resolved,
+                        * so we avoid the resolver overhead on the real
+                        * execvp call.
+                        */
+                       execvp("", (char **)argv);
 
-       if (target_pid == -1 && argc) {
-               pid = fork();
-               if (pid < 0)
-                       die("failed to fork");
+                       /*
+                        * Tell the parent we're ready to go
+                        */
+                       close(child_ready_pipe[1]);
 
-               if (!pid) {
-                       if (execvp(argv[0], (char **)argv)) {
-                               perror(argv[0]);
-                               exit(-1);
-                       }
-               } else {
                        /*
-                        * Wait a bit for the execv'ed child to appear
-                        * and be updated in /proc
-                        * FIXME: Do you know a less heuristical solution?
+                        * Wait until the parent tells us to go.
                         */
-                       usleep(1000);
-                       event__synthesize_thread(pid,
-                                                process_synthesized_event);
+                       if (read(go_pipe[0], &buf, 1) == -1)
+                               perror("unable to read pipe");
+
+                       execvp(argv[0], (char **)argv);
+
+                       perror(argv[0]);
+                       exit(-1);
                }
 
                child_pid = pid;
+
+               if (!system_wide)
+                       target_pid = 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);
+               }
+               close(child_ready_pipe[0]);
+       }
+
+
+       if ((!system_wide && !inherit) || profile_cpu != -1) {
+               open_counters(profile_cpu, target_pid);
+       } else {
+               for (i = 0; i < nr_cpus; i++)
+                       open_counters(i, target_pid);
        }
 
+       if (file_new) {
+               err = perf_header__write(&session->header, output, false);
+               if (err < 0)
+                       return err;
+       }
+
+       if (!system_wide && profile_cpu == -1)
+               event__synthesize_thread(pid, process_synthesized_event,
+                                        session);
+       else
+               event__synthesize_threads(process_synthesized_event, session);
+
        if (realtime_prio) {
                struct sched_param param;
 
@@ -526,6 +567,12 @@ static int __cmd_record(int argc, const char **argv)
                }
        }
 
+       /*
+        * Let the child rip
+        */
+       if (forks)
+               close(go_pipe[1]);
+
        for (;;) {
                int hits = samples;
 
@@ -620,13 +667,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
 {
        int counter;
 
-       symbol__init(0);
-
        argc = parse_options(argc, argv, options, record_usage,
-               PARSE_OPT_STOP_AT_NON_OPTION);
-       if (!argc && target_pid == -1 && !system_wide)
+                           PARSE_OPT_STOP_AT_NON_OPTION);
+       if (!argc && target_pid == -1 && !system_wide && profile_cpu == -1)
                usage_with_options(record_usage, options);
 
+       symbol__init();
+
        if (!nr_counters) {
                nr_counters     = 1;
                attrs[0].type   = PERF_TYPE_HARDWARE;