perf script: Add period as a default output column
[sfrench/cifs-2.6.git] / tools / perf / builtin-script.c
index f57035b89c15d11a5178cd3468cf5bd9b03405c1..9708a12905715e78759c88c397dcf27d5c5a863b 100644 (file)
@@ -44,6 +44,7 @@ enum perf_output_field {
        PERF_OUTPUT_ADDR            = 1U << 10,
        PERF_OUTPUT_SYMOFFSET       = 1U << 11,
        PERF_OUTPUT_SRCLINE         = 1U << 12,
+       PERF_OUTPUT_PERIOD          = 1U << 13,
 };
 
 struct output_option {
@@ -63,6 +64,7 @@ struct output_option {
        {.str = "addr",  .field = PERF_OUTPUT_ADDR},
        {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},
        {.str = "srcline", .field = PERF_OUTPUT_SRCLINE},
+       {.str = "period", .field = PERF_OUTPUT_PERIOD},
 };
 
 /* default set to maintain compatibility with current format */
@@ -80,7 +82,8 @@ static struct {
                .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
                              PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
                              PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
-                                 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
+                             PERF_OUTPUT_PERIOD,
 
                .invalid_fields = PERF_OUTPUT_TRACE,
        },
@@ -91,7 +94,8 @@ static struct {
                .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
                              PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
                              PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
-                                 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
+                             PERF_OUTPUT_PERIOD,
 
                .invalid_fields = PERF_OUTPUT_TRACE,
        },
@@ -110,7 +114,8 @@ static struct {
                .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
                              PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
                              PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
-                                 PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,
+                             PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
+                             PERF_OUTPUT_PERIOD,
 
                .invalid_fields = PERF_OUTPUT_TRACE,
        },
@@ -184,10 +189,6 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",
                                            PERF_OUTPUT_IP))
                        return -EINVAL;
-
-               if (!no_callchain &&
-                   !(attr->sample_type & PERF_SAMPLE_CALLCHAIN))
-                       symbol_conf.use_callchain = false;
        }
 
        if (PRINT_FIELD(ADDR) &&
@@ -233,6 +234,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
                                        PERF_OUTPUT_CPU))
                return -EINVAL;
 
+       if (PRINT_FIELD(PERIOD) &&
+               perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD",
+                                       PERF_OUTPUT_PERIOD))
+               return -EINVAL;
+
        return 0;
 }
 
@@ -290,6 +296,19 @@ static int perf_session__check_output_opt(struct perf_session *session)
                set_print_ip_opts(&evsel->attr);
        }
 
+       if (!no_callchain) {
+               bool use_callchain = false;
+
+               evlist__for_each(session->evlist, evsel) {
+                       if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+                               use_callchain = true;
+                               break;
+                       }
+               }
+               if (!use_callchain)
+                       symbol_conf.use_callchain = false;
+       }
+
        /*
         * set default for tracepoints to print symbols only
         * if callchains are present
@@ -439,6 +458,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
 
        print_sample_start(sample, thread, evsel);
 
+       if (PRINT_FIELD(PERIOD))
+               printf("%10" PRIu64 " ", sample->period);
+
        if (PRINT_FIELD(EVNAME)) {
                const char *evname = perf_evsel__name(evsel);
                printf("%s: ", evname ? evname : "[unknown]");
@@ -476,6 +498,11 @@ static int default_start_script(const char *script __maybe_unused,
        return 0;
 }
 
+static int default_flush_script(void)
+{
+       return 0;
+}
+
 static int default_stop_script(void)
 {
        return 0;
@@ -489,6 +516,7 @@ static int default_generate_script(struct pevent *pevent __maybe_unused,
 
 static struct scripting_ops default_scripting_ops = {
        .start_script           = default_start_script,
+       .flush_script           = default_flush_script,
        .stop_script            = default_stop_script,
        .process_event          = process_event,
        .generate_script        = default_generate_script,
@@ -504,6 +532,11 @@ static void setup_scripting(void)
        scripting_ops = &default_scripting_ops;
 }
 
+static int flush_scripting(void)
+{
+       return scripting_ops->flush_script();
+}
+
 static int cleanup_scripting(void)
 {
        pr_debug("\nperf script stopped\n");
@@ -552,7 +585,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 
        scripting_ops->process_event(event, sample, evsel, thread, &al);
 
-       evsel->hists.stats.total_period += sample->period;
        return 0;
 }
 
@@ -1471,12 +1503,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
        bool show_full_info = false;
        bool header = false;
        bool header_only = false;
+       bool script_started = false;
        char *rec_script_path = NULL;
        char *rep_script_path = NULL;
        struct perf_session *session;
        char *script_path = NULL;
        const char **__argv;
-       int i, j, err;
+       int i, j, err = 0;
        struct perf_script script = {
                .tool = {
                        .sample          = process_sample_event,
@@ -1488,7 +1521,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
        };
@@ -1523,7 +1556,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                     "comma separated output fields prepend with 'type:'. "
                     "Valid types: hw,sw,trace,raw. "
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
-                    "addr,symoff", parse_output_fields),
+                    "addr,symoff,period", parse_output_fields),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
        OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
@@ -1718,26 +1751,28 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                exit(-1);
        }
 
-       if (symbol__init() < 0)
-               return -1;
        if (!script_name)
                setup_pager();
 
        session = perf_session__new(&file, false, &script.tool);
        if (session == NULL)
-               return -ENOMEM;
+               return -1;
 
        if (header || header_only) {
                perf_session__fprintf_info(session, stdout, show_full_info);
                if (header_only)
-                       return 0;
+                       goto out_delete;
        }
 
+       if (symbol__init(&session->header.env) < 0)
+               goto out_delete;
+
        script.session = session;
 
        if (cpu_list) {
-               if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
-                       return -1;
+               err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
+               if (err < 0)
+                       goto out_delete;
        }
 
        if (!no_callchain)
@@ -1752,53 +1787,62 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                if (output_set_by_user()) {
                        fprintf(stderr,
                                "custom fields not supported for generated scripts");
-                       return -1;
+                       err = -EINVAL;
+                       goto out_delete;
                }
 
                input = open(file.path, O_RDONLY);      /* input_name */
                if (input < 0) {
+                       err = -errno;
                        perror("failed to open file");
-                       return -1;
+                       goto out_delete;
                }
 
                err = fstat(input, &perf_stat);
                if (err < 0) {
                        perror("failed to stat file");
-                       return -1;
+                       goto out_delete;
                }
 
                if (!perf_stat.st_size) {
                        fprintf(stderr, "zero-sized file, nothing to do!\n");
-                       return 0;
+                       goto out_delete;
                }
 
                scripting_ops = script_spec__lookup(generate_script_lang);
                if (!scripting_ops) {
                        fprintf(stderr, "invalid language specifier");
-                       return -1;
+                       err = -ENOENT;
+                       goto out_delete;
                }
 
                err = scripting_ops->generate_script(session->tevent.pevent,
                                                     "perf-script");
-               goto out;
+               goto out_delete;
        }
 
        if (script_name) {
                err = scripting_ops->start_script(script_name, argc, argv);
                if (err)
-                       goto out;
+                       goto out_delete;
                pr_debug("perf script started with script %s\n\n", script_name);
+               script_started = true;
        }
 
 
        err = perf_session__check_output_opt(session);
        if (err < 0)
-               goto out;
+               goto out_delete;
 
        err = __cmd_script(&script);
 
+       flush_scripting();
+
+out_delete:
        perf_session__delete(session);
-       cleanup_scripting();
+
+       if (script_started)
+               cleanup_scripting();
 out:
        return err;
 }