]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/builtin-record.c
x86/build: Move _etext to actual end of .text
[linux.git] / tools / perf / builtin-record.c
index f3f7f310033663f5b61752cfb6c835b280f8436e..4e2d953d4bc58d158c4b7d135bdcee8e079b84be 100644 (file)
@@ -62,6 +62,9 @@ struct switch_output {
        unsigned long    time;
        const char      *str;
        bool             set;
+       char             **filenames;
+       int              num_files;
+       int              cur_file;
 };
 
 struct record {
@@ -392,7 +395,7 @@ static int record__process_auxtrace(struct perf_tool *tool,
        size_t padding;
        u8 pad[8] = {0};
 
-       if (!perf_data__is_pipe(data)) {
+       if (!perf_data__is_pipe(data) && !perf_data__is_dir(data)) {
                off_t file_offset;
                int fd = perf_data__fd(data);
                int err;
@@ -837,6 +840,8 @@ static void record__init_features(struct record *rec)
        if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
                perf_header__clear_feat(&session->header, HEADER_CLOCKID);
 
+       perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
+
        perf_header__clear_feat(&session->header, HEADER_STAT);
 }
 
@@ -890,6 +895,7 @@ record__switch_output(struct record *rec, bool at_exit)
 {
        struct perf_data *data = &rec->data;
        int fd, err;
+       char *new_filename;
 
        /* Same Size:      "2015122520103046"*/
        char timestamp[] = "InvalidTimestamp";
@@ -910,7 +916,7 @@ record__switch_output(struct record *rec, bool at_exit)
 
        fd = perf_data__switch(data, timestamp,
                                    rec->session->header.data_offset,
-                                   at_exit);
+                                   at_exit, &new_filename);
        if (fd >= 0 && !at_exit) {
                rec->bytes_written = 0;
                rec->session->header.data_size = 0;
@@ -920,6 +926,21 @@ record__switch_output(struct record *rec, bool at_exit)
                fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
                        data->path, timestamp);
 
+       if (rec->switch_output.num_files) {
+               int n = rec->switch_output.cur_file + 1;
+
+               if (n >= rec->switch_output.num_files)
+                       n = 0;
+               rec->switch_output.cur_file = n;
+               if (rec->switch_output.filenames[n]) {
+                       remove(rec->switch_output.filenames[n]);
+                       free(rec->switch_output.filenames[n]);
+               }
+               rec->switch_output.filenames[n] = new_filename;
+       } else {
+               free(new_filename);
+       }
+
        /* Output tracking events */
        if (!at_exit) {
                record__synthesize(rec, false);
@@ -1093,7 +1114,7 @@ static int record__synthesize(struct record *rec, bool tail)
                return err;
        }
 
-       err = perf_event__synthesize_bpf_events(tool, process_synthesized_event,
+       err = perf_event__synthesize_bpf_events(session, process_synthesized_event,
                                                machine, opts);
        if (err < 0)
                pr_warning("Couldn't synthesize bpf events.\n");
@@ -1116,6 +1137,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        struct perf_data *data = &rec->data;
        struct perf_session *session;
        bool disabled = false, draining = false;
+       struct perf_evlist *sb_evlist = NULL;
        int fd;
 
        atexit(record__sig_exit);
@@ -1216,6 +1238,14 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                goto out_child;
        }
 
+       if (!opts->no_bpf_event)
+               bpf_event__add_sb_event(&sb_evlist, &session->header.env);
+
+       if (perf_evlist__start_sb_thread(sb_evlist, &rec->opts.target)) {
+               pr_debug("Couldn't start the BPF side band thread:\nBPF programs starting from now on won't be annotatable\n");
+               opts->no_bpf_event = true;
+       }
+
        err = record__synthesize(rec, false);
        if (err < 0)
                goto out_child;
@@ -1466,6 +1496,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 
 out_delete_session:
        perf_session__delete(session);
+
+       if (!opts->no_bpf_event)
+               perf_evlist__stop_sb_thread(sb_evlist);
        return status;
 }
 
@@ -1870,7 +1903,7 @@ static struct option __record_options[] = {
        OPT_BOOLEAN(0, "tail-synthesize", &record.opts.tail_synthesize,
                    "synthesize non-sample events at the end of output"),
        OPT_BOOLEAN(0, "overwrite", &record.opts.overwrite, "use overwrite mode"),
-       OPT_BOOLEAN(0, "bpf-event", &record.opts.bpf_event, "record bpf events"),
+       OPT_BOOLEAN(0, "no-bpf-event", &record.opts.no_bpf_event, "record bpf events"),
        OPT_BOOLEAN(0, "strict-freq", &record.opts.strict_freq,
                    "Fail if the specified frequency can't be used"),
        OPT_CALLBACK('F', "freq", &record.opts, "freq or 'max'",
@@ -1968,9 +2001,11 @@ static struct option __record_options[] = {
        OPT_BOOLEAN(0, "timestamp-boundary", &record.timestamp_boundary,
                    "Record timestamp boundary (time of first/last samples)"),
        OPT_STRING_OPTARG_SET(0, "switch-output", &record.switch_output.str,
-                         &record.switch_output.set, "signal,size,time",
-                         "Switch output when receive SIGUSR2 or cross size,time threshold",
+                         &record.switch_output.set, "signal or size[BKMG] or time[smhd]",
+                         "Switch output when receiving SIGUSR2 (signal) or cross a size or time threshold",
                          "signal"),
+       OPT_INTEGER(0, "switch-max-files", &record.switch_output.num_files,
+                  "Limit number of switch output generated files"),
        OPT_BOOLEAN(0, "dry-run", &dry_run,
                    "Parse options then exit"),
 #ifdef HAVE_AIO_SUPPORT
@@ -2057,6 +2092,13 @@ int cmd_record(int argc, const char **argv)
                alarm(rec->switch_output.time);
        }
 
+       if (rec->switch_output.num_files) {
+               rec->switch_output.filenames = calloc(sizeof(char *),
+                                                     rec->switch_output.num_files);
+               if (!rec->switch_output.filenames)
+                       return -EINVAL;
+       }
+
        /*
         * Allow aliases to facilitate the lookup of symbols for address
         * filters. Refer to auxtrace_parse_filters().