Merge branch 'perf/live' into perf/core
authorIngo Molnar <mingo@elte.hu>
Thu, 15 Apr 2010 07:13:26 +0000 (09:13 +0200)
committerIngo Molnar <mingo@elte.hu>
Thu, 15 Apr 2010 07:13:26 +0000 (09:13 +0200)
Conflicts:
tools/perf/builtin-record.c

Merge reason: add the live tracing feature, resolve conflict.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
tools/perf/builtin-record.c

  #include <unistd.h>
  #include <sched.h>
  
 +enum write_mode_t {
 +      WRITE_FORCE,
 +      WRITE_APPEND
 +};
 +
  static int                    *fd[MAX_NR_CPUS][MAX_COUNTERS];
  
 +static unsigned int           user_interval                   = UINT_MAX;
  static long                   default_interval                =      0;
  
  static int                    nr_cpus                         =      0;
  static unsigned int           page_size;
  static unsigned int           mmap_pages                      =    128;
 +static unsigned int           user_freq                       = UINT_MAX;
  static int                    freq                            =   1000;
  static int                    output;
+ static int                    pipe_output                     =      0;
  static const char             *output_name                    = "perf.data";
  static int                    group                           =      0;
  static unsigned int           realtime_prio                   =      0;
@@@ -54,7 -48,8 +55,7 @@@ static pid_t                  *all_tids                       =      NULL
  static int                    thread_num                      =      0;
  static pid_t                  child_pid                       =     -1;
  static bool                   inherit                         =   true;
 -static bool                   force                           =  false;
 -static bool                   append_file                     =  false;
 +static enum write_mode_t      write_mode                      = WRITE_FORCE;
  static bool                   call_graph                      =  false;
  static bool                   inherit_stat                    =  false;
  static bool                   no_samples                      =  false;
@@@ -109,6 -104,11 +110,11 @@@ static void mmap_write_tail(struct mmap
        pc->data_tail = tail;
  }
  
+ static void advance_output(size_t size)
+ {
+       bytes_written += size;
+ }
  static void write_output(void *buf, size_t size)
  {
        while (size) {
@@@ -257,19 -257,10 +263,19 @@@ static void create_counter(int counter
        if (nr_counters > 1)
                attr->sample_type |= PERF_SAMPLE_ID;
  
 -      if (freq) {
 -              attr->sample_type       |= PERF_SAMPLE_PERIOD;
 -              attr->freq              = 1;
 -              attr->sample_freq       = freq;
 +      /*
 +       * We default some events to a 1 default interval. But keep
 +       * it a weak assumption overridable by the user.
 +       */
 +      if (!attr->sample_period || (user_freq != UINT_MAX &&
 +                                   user_interval != UINT_MAX)) {
 +              if (freq) {
 +                      attr->sample_type       |= PERF_SAMPLE_PERIOD;
 +                      attr->freq              = 1;
 +                      attr->sample_freq       = freq;
 +              } else {
 +                      attr->sample_period = default_interval;
 +              }
        }
  
        if (no_samples)
@@@ -435,10 -426,19 +441,19 @@@ static int process_buildids(void
  
  static void atexit_header(void)
  {
-       session->header.data_size += bytes_written;
+       if (!pipe_output) {
+               session->header.data_size += bytes_written;
  
-       process_buildids();
-       perf_header__write(&session->header, output, true);
+               process_buildids();
+               perf_header__write(&session->header, output, true);
+       } else {
+               int err;
+               err = event__synthesize_build_ids(process_synthesized_event,
+                                                 session);
+               if (err < 0)
+                       pr_err("Couldn't synthesize build ids.\n");
+       }
  }
  
  static int __cmd_record(int argc, const char **argv)
                exit(-1);
        }
  
-       if (!stat(output_name, &st) && st.st_size) {
+       if (!strcmp(output_name, "-"))
+               pipe_output = 1;
+       else if (!stat(output_name, &st) && st.st_size) {
 -              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 {
 +              if (write_mode == WRITE_FORCE) {
                        char oldname[PATH_MAX];
                        snprintf(oldname, sizeof(oldname), "%s.old",
                                 output_name);
                        unlink(oldname);
                        rename(output_name, oldname);
                }
 -      } else {
 -              append_file = false;
 +      } else if (write_mode == WRITE_APPEND) {
 +              write_mode = WRITE_FORCE;
        }
  
        flags = O_CREAT|O_RDWR;
 -      if (append_file)
 +      if (write_mode == WRITE_APPEND)
                file_new = 0;
        else
                flags |= O_TRUNC;
  
-       output = open(output_name, flags, S_IRUSR|S_IWUSR);
+       if (pipe_output)
+               output = STDOUT_FILENO;
+       else
+               output = open(output_name, flags, S_IRUSR | S_IWUSR);
        if (output < 0) {
                perror("failed to create output file");
                exit(-1);
        }
  
 -      session = perf_session__new(output_name, O_WRONLY, force);
 +      session = perf_session__new(output_name, O_WRONLY,
 +                                  write_mode == WRITE_FORCE);
        if (session == NULL) {
                pr_err("Not enough memory for reading perf file header\n");
                return -1;
        }
  
        if (!file_new) {
-               err = perf_header__read(&session->header, output);
+               err = perf_header__read(session, output);
                if (err < 0)
                        return err;
        }
                }
  
                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);
                        open_counters(cpumap[i]);
        }
  
-       if (file_new) {
+       if (pipe_output) {
+               err = perf_header__write_pipe(output);
+               if (err < 0)
+                       return err;
+       } else if (file_new) {
                err = perf_header__write(&session->header, output, false);
                if (err < 0)
                        return err;
  
        post_processing_offset = lseek(output, 0, SEEK_CUR);
  
+       if (pipe_output) {
+               err = event__synthesize_attrs(&session->header,
+                                             process_synthesized_event,
+                                             session);
+               if (err < 0) {
+                       pr_err("Couldn't synthesize attrs.\n");
+                       return err;
+               }
+               err = event__synthesize_event_types(process_synthesized_event,
+                                                   session);
+               if (err < 0) {
+                       pr_err("Couldn't synthesize event_types.\n");
+                       return err;
+               }
+               err = event__synthesize_tracing_data(output, attrs,
+                                                    nr_counters,
+                                                    process_synthesized_event,
+                                                    session);
+               if (err <= 0) {
+                       pr_err("Couldn't record tracing data.\n");
+                       return err;
+               }
+               advance_output(err);
+       }
        err = event__synthesize_kernel_mmap(process_synthesized_event,
                                            session, "_text");
        if (err < 0)
@@@ -676,8 -721,6 +730,8 @@@ static const char * const record_usage[
        NULL
  };
  
 +static bool force, append_file;
 +
  static const struct option options[] = {
        OPT_CALLBACK('e', "event", NULL, "event",
                     "event selector. use 'perf list' to list available events",
        OPT_INTEGER('C', "profile_cpu", &profile_cpu,
                            "CPU to profile on"),
        OPT_BOOLEAN('f', "force", &force,
 -                      "overwrite existing data file"),
 -      OPT_LONG('c', "count", &default_interval,
 +                      "overwrite existing data file (deprecated)"),
 +      OPT_LONG('c', "count", &user_interval,
                    "event period to sample"),
        OPT_STRING('o', "output", &output_name, "file",
                    "output file name"),
        OPT_BOOLEAN('i', "inherit", &inherit,
                    "child tasks inherit counters"),
 -      OPT_INTEGER('F', "freq", &freq,
 +      OPT_INTEGER('F', "freq", &user_freq,
                    "profile at this frequency"),
        OPT_INTEGER('m', "mmap-pages", &mmap_pages,
                    "number of mmap data pages"),
  
  int cmd_record(int argc, const char **argv, const char *prefix __used)
  {
 -      int counter;
        int i,j;
  
        argc = parse_options(argc, argv, options, record_usage,
                !system_wide && profile_cpu == -1)
                usage_with_options(record_usage, options);
  
 +      if (force && append_file) {
 +              fprintf(stderr, "Can't overwrite and append at the same time."
 +                              " You need to choose between -f and -A");
 +              usage_with_options(record_usage, options);
 +      } else if (append_file) {
 +              write_mode = WRITE_APPEND;
 +      } else {
 +              write_mode = WRITE_FORCE;
 +      }
 +
        symbol__init();
  
        if (!nr_counters) {
        if (!event_array)
                return -ENOMEM;
  
 +      if (user_interval != UINT_MAX)
 +              default_interval = user_interval;
 +      if (user_freq != UINT_MAX)
 +              freq = user_freq;
 +
        /*
         * User specified count overrides default frequency.
         */
                exit(EXIT_FAILURE);
        }
  
 -      for (counter = 0; counter < nr_counters; counter++) {
 -              if (attrs[counter].sample_period)
 -                      continue;
 -
 -              attrs[counter].sample_period = default_interval;
 -      }
 -
        return __cmd_record(argc, argv);
  }