Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-microblaze.git] / tools / perf / builtin-script.c
index 4474577..484ce60 100644 (file)
@@ -82,38 +82,64 @@ static bool                 native_arch;
 unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
 
 enum perf_output_field {
-       PERF_OUTPUT_COMM            = 1U << 0,
-       PERF_OUTPUT_TID             = 1U << 1,
-       PERF_OUTPUT_PID             = 1U << 2,
-       PERF_OUTPUT_TIME            = 1U << 3,
-       PERF_OUTPUT_CPU             = 1U << 4,
-       PERF_OUTPUT_EVNAME          = 1U << 5,
-       PERF_OUTPUT_TRACE           = 1U << 6,
-       PERF_OUTPUT_IP              = 1U << 7,
-       PERF_OUTPUT_SYM             = 1U << 8,
-       PERF_OUTPUT_DSO             = 1U << 9,
-       PERF_OUTPUT_ADDR            = 1U << 10,
-       PERF_OUTPUT_SYMOFFSET       = 1U << 11,
-       PERF_OUTPUT_SRCLINE         = 1U << 12,
-       PERF_OUTPUT_PERIOD          = 1U << 13,
-       PERF_OUTPUT_IREGS           = 1U << 14,
-       PERF_OUTPUT_BRSTACK         = 1U << 15,
-       PERF_OUTPUT_BRSTACKSYM      = 1U << 16,
-       PERF_OUTPUT_DATA_SRC        = 1U << 17,
-       PERF_OUTPUT_WEIGHT          = 1U << 18,
-       PERF_OUTPUT_BPF_OUTPUT      = 1U << 19,
-       PERF_OUTPUT_CALLINDENT      = 1U << 20,
-       PERF_OUTPUT_INSN            = 1U << 21,
-       PERF_OUTPUT_INSNLEN         = 1U << 22,
-       PERF_OUTPUT_BRSTACKINSN     = 1U << 23,
-       PERF_OUTPUT_BRSTACKOFF      = 1U << 24,
-       PERF_OUTPUT_SYNTH           = 1U << 25,
-       PERF_OUTPUT_PHYS_ADDR       = 1U << 26,
-       PERF_OUTPUT_UREGS           = 1U << 27,
-       PERF_OUTPUT_METRIC          = 1U << 28,
-       PERF_OUTPUT_MISC            = 1U << 29,
-       PERF_OUTPUT_SRCCODE         = 1U << 30,
-       PERF_OUTPUT_IPC             = 1U << 31,
+       PERF_OUTPUT_COMM            = 1ULL << 0,
+       PERF_OUTPUT_TID             = 1ULL << 1,
+       PERF_OUTPUT_PID             = 1ULL << 2,
+       PERF_OUTPUT_TIME            = 1ULL << 3,
+       PERF_OUTPUT_CPU             = 1ULL << 4,
+       PERF_OUTPUT_EVNAME          = 1ULL << 5,
+       PERF_OUTPUT_TRACE           = 1ULL << 6,
+       PERF_OUTPUT_IP              = 1ULL << 7,
+       PERF_OUTPUT_SYM             = 1ULL << 8,
+       PERF_OUTPUT_DSO             = 1ULL << 9,
+       PERF_OUTPUT_ADDR            = 1ULL << 10,
+       PERF_OUTPUT_SYMOFFSET       = 1ULL << 11,
+       PERF_OUTPUT_SRCLINE         = 1ULL << 12,
+       PERF_OUTPUT_PERIOD          = 1ULL << 13,
+       PERF_OUTPUT_IREGS           = 1ULL << 14,
+       PERF_OUTPUT_BRSTACK         = 1ULL << 15,
+       PERF_OUTPUT_BRSTACKSYM      = 1ULL << 16,
+       PERF_OUTPUT_DATA_SRC        = 1ULL << 17,
+       PERF_OUTPUT_WEIGHT          = 1ULL << 18,
+       PERF_OUTPUT_BPF_OUTPUT      = 1ULL << 19,
+       PERF_OUTPUT_CALLINDENT      = 1ULL << 20,
+       PERF_OUTPUT_INSN            = 1ULL << 21,
+       PERF_OUTPUT_INSNLEN         = 1ULL << 22,
+       PERF_OUTPUT_BRSTACKINSN     = 1ULL << 23,
+       PERF_OUTPUT_BRSTACKOFF      = 1ULL << 24,
+       PERF_OUTPUT_SYNTH           = 1ULL << 25,
+       PERF_OUTPUT_PHYS_ADDR       = 1ULL << 26,
+       PERF_OUTPUT_UREGS           = 1ULL << 27,
+       PERF_OUTPUT_METRIC          = 1ULL << 28,
+       PERF_OUTPUT_MISC            = 1ULL << 29,
+       PERF_OUTPUT_SRCCODE         = 1ULL << 30,
+       PERF_OUTPUT_IPC             = 1ULL << 31,
+       PERF_OUTPUT_TOD             = 1ULL << 32,
+};
+
+struct perf_script {
+       struct perf_tool        tool;
+       struct perf_session     *session;
+       bool                    show_task_events;
+       bool                    show_mmap_events;
+       bool                    show_switch_events;
+       bool                    show_namespace_events;
+       bool                    show_lost_events;
+       bool                    show_round_events;
+       bool                    show_bpf_events;
+       bool                    show_cgroup_events;
+       bool                    show_text_poke_events;
+       bool                    allocated;
+       bool                    per_event_dump;
+       bool                    stitch_lbr;
+       struct evswitch         evswitch;
+       struct perf_cpu_map     *cpus;
+       struct perf_thread_map *threads;
+       int                     name_width;
+       const char              *time_str;
+       struct perf_time_interval *ptime_range;
+       int                     range_size;
+       int                     range_num;
 };
 
 struct output_option {
@@ -152,6 +178,7 @@ struct output_option {
        {.str = "misc", .field = PERF_OUTPUT_MISC},
        {.str = "srccode", .field = PERF_OUTPUT_SRCCODE},
        {.str = "ipc", .field = PERF_OUTPUT_IPC},
+       {.str = "tod", .field = PERF_OUTPUT_TOD},
 };
 
 enum {
@@ -388,7 +415,7 @@ static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *
        return evsel__do_check_stype(evsel, sample_type, sample_msg, field, false);
 }
 
-static int perf_evsel__check_attr(struct evsel *evsel, struct perf_session *session)
+static int evsel__check_attr(struct evsel *evsel, struct perf_session *session)
 {
        struct perf_event_attr *attr = &evsel->core.attr;
        bool allow_user_set;
@@ -443,8 +470,7 @@ static int perf_evsel__check_attr(struct evsel *evsel, struct perf_session *sess
                return -EINVAL;
        }
        if (PRINT_FIELD(BRSTACKINSN) && !allow_user_set &&
-           !(perf_evlist__combined_branch_type(session->evlist) &
-             PERF_SAMPLE_BRANCH_ANY)) {
+           !(evlist__combined_branch_type(session->evlist) & PERF_SAMPLE_BRANCH_ANY)) {
                pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"
                       "Hint: run 'perf record -b ...'\n");
                return -EINVAL;
@@ -503,6 +529,7 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
  */
 static int perf_session__check_output_opt(struct perf_session *session)
 {
+       bool tod = false;
        unsigned int j;
        struct evsel *evsel;
 
@@ -522,13 +549,14 @@ static int perf_session__check_output_opt(struct perf_session *session)
                }
 
                if (evsel && output[j].fields &&
-                       perf_evsel__check_attr(evsel, session))
+                       evsel__check_attr(evsel, session))
                        return -1;
 
                if (evsel == NULL)
                        continue;
 
                set_print_ip_opts(&evsel->core.attr);
+               tod |= output[j].fields & PERF_OUTPUT_TOD;
        }
 
        if (!no_callchain) {
@@ -569,13 +597,17 @@ static int perf_session__check_output_opt(struct perf_session *session)
                }
        }
 
+       if (tod && !session->header.env.clock.enabled) {
+               pr_err("Can't provide 'tod' time, missing clock data. "
+                      "Please record with -k/--clockid option.\n");
+               return -1;
+       }
 out:
        return 0;
 }
 
 static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask,
-                                    FILE *fp
-)
+                                    FILE *fp)
 {
        unsigned i = 0, r;
        int printed = 0;
@@ -593,6 +625,56 @@ static int perf_sample__fprintf_regs(struct regs_dump *regs, uint64_t mask,
        return printed;
 }
 
+#define DEFAULT_TOD_FMT "%F %H:%M:%S"
+
+static char*
+tod_scnprintf(struct perf_script *script, char *buf, int buflen,
+            u64 timestamp)
+{
+       u64 tod_ns, clockid_ns;
+       struct perf_env *env;
+       unsigned long nsec;
+       struct tm ltime;
+       char date[64];
+       time_t sec;
+
+       buf[0] = '\0';
+       if (buflen < 64 || !script)
+               return buf;
+
+       env = &script->session->header.env;
+       if (!env->clock.enabled) {
+               scnprintf(buf, buflen, "disabled");
+               return buf;
+       }
+
+       clockid_ns = env->clock.clockid_ns;
+       tod_ns     = env->clock.tod_ns;
+
+       if (timestamp > clockid_ns)
+               tod_ns += timestamp - clockid_ns;
+       else
+               tod_ns -= clockid_ns - timestamp;
+
+       sec  = (time_t) (tod_ns / NSEC_PER_SEC);
+       nsec = tod_ns - sec * NSEC_PER_SEC;
+
+       if (localtime_r(&sec, &ltime) == NULL) {
+               scnprintf(buf, buflen, "failed");
+       } else {
+               strftime(date, sizeof(date), DEFAULT_TOD_FMT, &ltime);
+
+               if (symbol_conf.nanosecs) {
+                       snprintf(buf, buflen, "%s.%09lu", date, nsec);
+               } else {
+                       snprintf(buf, buflen, "%s.%06lu",
+                                date, nsec / NSEC_PER_USEC);
+               }
+       }
+
+       return buf;
+}
+
 static int perf_sample__fprintf_iregs(struct perf_sample *sample,
                                      struct perf_event_attr *attr, FILE *fp)
 {
@@ -607,7 +689,8 @@ static int perf_sample__fprintf_uregs(struct perf_sample *sample,
                                         attr->sample_regs_user, fp);
 }
 
-static int perf_sample__fprintf_start(struct perf_sample *sample,
+static int perf_sample__fprintf_start(struct perf_script *script,
+                                     struct perf_sample *sample,
                                      struct thread *thread,
                                      struct evsel *evsel,
                                      u32 type, FILE *fp)
@@ -616,6 +699,7 @@ static int perf_sample__fprintf_start(struct perf_sample *sample,
        unsigned long secs;
        unsigned long long nsecs;
        int printed = 0;
+       char tstr[128];
 
        if (PRINT_FIELD(COMM)) {
                if (latency_format)
@@ -684,6 +768,11 @@ static int perf_sample__fprintf_start(struct perf_sample *sample,
                printed += ret;
        }
 
+       if (PRINT_FIELD(TOD)) {
+               tod_scnprintf(script, tstr, sizeof(tstr), sample->time);
+               printed += fprintf(fp, "%s ", tstr);
+       }
+
        if (PRINT_FIELD(TIME)) {
                u64 t = sample->time;
                if (reltime) {
@@ -1668,31 +1757,7 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,
        return 0;
 }
 
-struct perf_script {
-       struct perf_tool        tool;
-       struct perf_session     *session;
-       bool                    show_task_events;
-       bool                    show_mmap_events;
-       bool                    show_switch_events;
-       bool                    show_namespace_events;
-       bool                    show_lost_events;
-       bool                    show_round_events;
-       bool                    show_bpf_events;
-       bool                    show_cgroup_events;
-       bool                    allocated;
-       bool                    per_event_dump;
-       bool                    stitch_lbr;
-       struct evswitch         evswitch;
-       struct perf_cpu_map     *cpus;
-       struct perf_thread_map *threads;
-       int                     name_width;
-       const char              *time_str;
-       struct perf_time_interval *ptime_range;
-       int                     range_size;
-       int                     range_num;
-};
-
-static int perf_evlist__max_name_len(struct evlist *evlist)
+static int evlist__max_name_len(struct evlist *evlist)
 {
        struct evsel *evsel;
        int max = 0;
@@ -1739,7 +1804,7 @@ static void script_print_metric(struct perf_stat_config *config __maybe_unused,
 
        if (!fmt)
                return;
-       perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel,
+       perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,
                                   PERF_RECORD_SAMPLE, mctx->fp);
        fputs("\tmetric: ", mctx->fp);
        if (color)
@@ -1754,7 +1819,7 @@ static void script_new_line(struct perf_stat_config *config __maybe_unused,
 {
        struct metric_ctx *mctx = ctx;
 
-       perf_sample__fprintf_start(mctx->sample, mctx->thread, mctx->evsel,
+       perf_sample__fprintf_start(NULL, mctx->sample, mctx->thread, mctx->evsel,
                                   PERF_RECORD_SAMPLE, mctx->fp);
        fputs("\tmetric: ", mctx->fp);
 }
@@ -1865,7 +1930,7 @@ static void process_event(struct perf_script *script,
 
        ++es->samples;
 
-       perf_sample__fprintf_start(sample, thread, evsel,
+       perf_sample__fprintf_start(script, sample, thread, evsel,
                                   PERF_RECORD_SAMPLE, fp);
 
        if (PRINT_FIELD(PERIOD))
@@ -1875,7 +1940,7 @@ static void process_event(struct perf_script *script,
                const char *evname = evsel__name(evsel);
 
                if (!script->name_width)
-                       script->name_width = perf_evlist__max_name_len(script->session->evlist);
+                       script->name_width = evlist__max_name_len(script->session->evlist);
 
                fprintf(fp, "%*s: ", script->name_width, evname ?: "[unknown]");
        }
@@ -2120,7 +2185,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
        }
 
        if (evsel->core.attr.sample_type) {
-               err = perf_evsel__check_attr(evsel, scr->session);
+               err = evsel__check_attr(evsel, scr->session);
                if (err)
                        return err;
        }
@@ -2129,7 +2194,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
         * Check if we need to enable callchains based
         * on events sample_type.
         */
-       sample_type = perf_evlist__combined_sample_type(evlist);
+       sample_type = evlist__combined_sample_type(evlist);
        callchain_param_setup(sample_type);
 
        /* Enable fields for callchain entries */
@@ -2174,11 +2239,11 @@ static int print_event_with_time(struct perf_tool *tool,
                thread = machine__findnew_thread(machine, pid, tid);
 
        if (thread && evsel) {
-               perf_sample__fprintf_start(sample, thread, evsel,
+               perf_sample__fprintf_start(script, sample, thread, evsel,
                                           event->header.type, stdout);
        }
 
-       perf_event__fprintf(event, stdout);
+       perf_event__fprintf(event, machine, stdout);
 
        thread__put(thread);
 
@@ -2313,7 +2378,7 @@ process_finished_round_event(struct perf_tool *tool __maybe_unused,
                             struct ordered_events *oe __maybe_unused)
 
 {
-       perf_event__fprintf(event, stdout);
+       perf_event__fprintf(event, NULL, stdout);
        return 0;
 }
 
@@ -2330,6 +2395,18 @@ process_bpf_events(struct perf_tool *tool __maybe_unused,
                           sample->tid);
 }
 
+static int process_text_poke_events(struct perf_tool *tool,
+                                   union perf_event *event,
+                                   struct perf_sample *sample,
+                                   struct machine *machine)
+{
+       if (perf_event__process_text_poke(tool, event, sample, machine) < 0)
+               return -1;
+
+       return print_event(tool, event, sample, machine, sample->pid,
+                          sample->tid);
+}
+
 static void sig_handler(int sig __maybe_unused)
 {
        session_done = 1;
@@ -2438,6 +2515,10 @@ static int __cmd_script(struct perf_script *script)
                script->tool.ksymbol = process_bpf_events;
                script->tool.bpf     = process_bpf_events;
        }
+       if (script->show_text_poke_events) {
+               script->tool.ksymbol   = process_bpf_events;
+               script->tool.text_poke = process_text_poke_events;
+       }
 
        if (perf_script__setup_per_event_dump(script)) {
                pr_err("Couldn't create the per event dump files\n");
@@ -3171,7 +3252,7 @@ static int have_cmd(int argc, const char **argv)
 static void script__setup_sample_type(struct perf_script *script)
 {
        struct perf_session *session = script->session;
-       u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
+       u64 sample_type = evlist__combined_sample_type(session->evlist);
 
        if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
                if ((sample_type & PERF_SAMPLE_REGS_USER) &&
@@ -3423,7 +3504,7 @@ int cmd_script(int argc, const char **argv)
                     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
                     "addr,symoff,srcline,period,iregs,uregs,brstack,"
                     "brstacksym,flags,bpf-output,brstackinsn,brstackoff,"
-                    "callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc",
+                    "callindent,insn,insnlen,synth,phys_addr,metric,misc,ipc,tod",
                     parse_output_fields),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
@@ -3474,6 +3555,8 @@ int cmd_script(int argc, const char **argv)
                    "Show round events (if recorded)"),
        OPT_BOOLEAN('\0', "show-bpf-events", &script.show_bpf_events,
                    "Show bpf related events (if recorded)"),
+       OPT_BOOLEAN('\0', "show-text-poke-events", &script.show_text_poke_events,
+                   "Show text poke related events (if recorded)"),
        OPT_BOOLEAN('\0', "per-event-dump", &script.per_event_dump,
                    "Dump trace output to files named by the monitored events"),
        OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),