From 0808921a14ffa170186288508c807f2166b7d8df Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Feb 2015 21:51:50 -0800 Subject: [PATCH 01/21] perf trace: Only insert blank duration bracket when tracing syscalls When printing just events, i.e. '--no-sys --ev some:events' it makes no sense to waste screen space. Before: # trace --no-sys --ev probe:* 84481.704 ( ): probe:vfs_getname:(ffffffff811ed023) pathname="/etc/services") 84481.892 ( ): probe:vfs_getname:(ffffffff811ed023) pathname="/etc/services") 84482.230 ( ): probe:vfs_getname:(ffffffff811ed023) pathname="/etc/resolv.conf") 84482.481 ( ): probe:vfs_getname:(ffffffff811ed023) pathname="/etc/hosts") 85097.725 ( ): probe:vfs_getname:(ffffffff811ed023) pathname="/root" # After: # trace --no-sys --ev probe:* 0.000 probe:vfs_getname:(ffffffff811ed023) pathname="/root") 1.711 probe:vfs_getname:(ffffffff811ed023) pathname="/etc/localtime") 2.103 probe:vfs_getname:(ffffffff811ed023) pathname="/etc/localtime") ^C# Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-jhryxgnam8zecq0q0wsy6pyb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b1c1df9bfb26..3a696aa70630 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1840,7 +1840,11 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, { trace__printf_interrupted_entry(trace, sample); trace__fprintf_tstamp(trace, sample->time, trace->output); - fprintf(trace->output, "(%9.9s): %s:", " ", evsel->name); + + if (trace->trace_syscalls) + fprintf(trace->output, "( ): "); + + fprintf(trace->output, "%s:", evsel->name); if (evsel->tp_format) { event_format__fprintf(evsel->tp_format, sample->cpu, From cfd70a26aadf0a9af80bbce035e5760736727a94 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 10:09:55 -0800 Subject: [PATCH 02/21] perf evlist: Introduce set_filter_pid method To filter out events for a certain pid, for instance, when tracing system wide, so that the tracer itself doesn't creates an event loop. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-byoia9dzu4gmkdv87etnd9zf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 13 +++++++++++++ tools/perf/util/evlist.h | 1 + 2 files changed, 14 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a8b2c5726aba..39302a455a58 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1085,6 +1085,19 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) return err; } +int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid) +{ + char *filter; + int ret; + + if (asprintf(&filter, "common_pid != %d", pid) < 0) + return -1; + + ret = perf_evlist__set_filter(evlist, filter); + free(filter); + return ret; +} + bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) { struct perf_evsel *pos; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index c94a9e03ecf1..715fa3a296f4 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -77,6 +77,7 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, const char *sys, const char *name, void *handler); int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); +int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); struct perf_evsel * perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); From 241b057ce5c01a24c280f124fab60109cb562589 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 10:15:21 -0800 Subject: [PATCH 03/21] perf trace: Filter out the trace pid when no threads are specified To avoid tracing the tracer. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-shmwd1khzpaobr3i0j1ygapg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 3a696aa70630..cb33e4c8821a 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2151,6 +2151,15 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (err < 0) goto out_error_open; + /* + * Better not use !target__has_task() here because we need to cover the + * case where no threads were specified in the command line, but a + * workload was, and in that case we will fill in the thread_map when + * we fork the workload in perf_evlist__prepare_workload. + */ + if (evlist->threads->map[0] == -1) + perf_evlist__set_filter_pid(evlist, getpid()); + err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); if (err < 0) goto out_error_mmap; From be199ada4fbbe5f742f854dce8e455cfcfcf7adb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 11:33:47 -0800 Subject: [PATCH 04/21] perf evlist: Introduce set_filter_pids method We need to filter multiple pids in trace, i.e. trace itself, gnome-terminal, X.org, etc. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-frtpkg7qapqwf7asa35wf8am@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 27 +++++++++++++++++++++++---- tools/perf/util/evlist.h | 1 + 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 39302a455a58..8d0b62361129 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1085,19 +1085,38 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) return err; } -int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid) +int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids) { char *filter; - int ret; + int ret = -1; + size_t i; - if (asprintf(&filter, "common_pid != %d", pid) < 0) - return -1; + for (i = 0; i < npids; ++i) { + if (i == 0) { + if (asprintf(&filter, "common_pid != %d", pids[i]) < 0) + return -1; + } else { + char *tmp; + + if (asprintf(&tmp, "%s && common_pid != %d", filter, pids[i]) < 0) + goto out_free; + + free(filter); + filter = tmp; + } + } ret = perf_evlist__set_filter(evlist, filter); +out_free: free(filter); return ret; } +int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid) +{ + return perf_evlist__set_filter_pids(evlist, 1, &pid); +} + bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) { struct perf_evsel *pos; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 715fa3a296f4..c19ff45c9ad5 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -78,6 +78,7 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); +int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); struct perf_evsel * perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); From f078c3852c7367b78552be432bc24ca93ebbd4cf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 11:36:52 -0800 Subject: [PATCH 05/21] perf trace: Introduce --filter-pids When tracing in X we get event loops due to the tracing activity, i.e. updates to a gnome-terminal that generate syscalls for X.org, etc. To get a more useful view of what is happening, syscall wise, system wide, we need to filter those, like in: # ps ax|egrep '981|2296|1519' | grep -v egrep 981 tty1 Ss+ 5:40 /usr/bin/Xorg :0 -background none ... 1519 ? Sl 2:22 /usr/bin/gnome-shell 2296 ? Sl 4:16 /usr/libexec/gnome-terminal-server # # trace -e write --filter-pids 981,2296,1519 0.385 ( 0.021 ms): goa-daemon/2061 write(fd: 1, buf: 0x7fbeb017b000, count: 136) = 136 0.922 ( 0.014 ms): goa-daemon/2061 write(fd: 1, buf: 0x7fbeb017b000, count: 140) = 140 5006.525 ( 0.029 ms): goa-daemon/2061 write(fd: 1, buf: 0x7fbeb017b000, count: 136) = 136 5007.235 ( 0.023 ms): goa-daemon/2061 write(fd: 1, buf: 0x7fbeb017b000, count: 140) = 140 5177.646 ( 0.018 ms): rtkit-daemon/782 write(fd: 5, buf: 0x7f7eea70be88, count: 8) = 8 8314.497 ( 0.004 ms): gsd-locate-poi/2084 write(fd: 5, buf: 0x7fffe96af7b0, count: 8) = 8 8314.518 ( 0.002 ms): gsd-locate-poi/2084 write(fd: 5, buf: 0x7fffe96af0e0, count: 8) = 8 ^C# When this option is used the tracer pid is also filtered. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-f5qmiyy7c0uxdm21ncatpeek@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-trace.txt | 3 ++ tools/perf/builtin-trace.c | 49 ++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 7e1b1f2bb83c..d6778e66fa92 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -55,6 +55,9 @@ OPTIONS --uid=:: Record events in threads owned by uid. Name or number. +--filter-pids=:: + Filter out events for these pids and for 'trace' itself (comma separated list). + -v:: --verbose=:: Verbosity level. diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index cb33e4c8821a..60ccfd52189d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -1229,6 +1229,10 @@ struct trace { const char *last_vfs_getname; struct intlist *tid_list; struct intlist *pid_list; + struct { + size_t nr; + pid_t *entries; + } filter_pids; double duration_filter; double runtime_ms; struct { @@ -2157,8 +2161,15 @@ static int trace__run(struct trace *trace, int argc, const char **argv) * workload was, and in that case we will fill in the thread_map when * we fork the workload in perf_evlist__prepare_workload. */ - if (evlist->threads->map[0] == -1) - perf_evlist__set_filter_pid(evlist, getpid()); + if (trace->filter_pids.nr > 0) + err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); + else if (evlist->threads->map[0] == -1) + err = perf_evlist__set_filter_pid(evlist, getpid()); + + if (err < 0) { + printf("err=%d,%s\n", -err, strerror(-err)); + exit(1); + } err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false); if (err < 0) @@ -2491,6 +2502,38 @@ static int trace__set_duration(const struct option *opt, const char *str, return 0; } +static int trace__set_filter_pids(const struct option *opt, const char *str, + int unset __maybe_unused) +{ + int ret = -1; + size_t i; + struct trace *trace = opt->value; + /* + * FIXME: introduce a intarray class, plain parse csv and create a + * { int nr, int entries[] } struct... + */ + struct intlist *list = intlist__new(str); + + if (list == NULL) + return -1; + + i = trace->filter_pids.nr = intlist__nr_entries(list) + 1; + trace->filter_pids.entries = calloc(i, sizeof(pid_t)); + + if (trace->filter_pids.entries == NULL) + goto out; + + trace->filter_pids.entries[0] = getpid(); + + for (i = 1; i < trace->filter_pids.nr; ++i) + trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i; + + intlist__delete(list); + ret = 0; +out: + return ret; +} + static int trace__open_output(struct trace *trace, const char *filename) { struct stat st; @@ -2581,6 +2624,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) "trace events on existing process id"), OPT_STRING('t', "tid", &trace.opts.target.tid, "tid", "trace events on existing thread id"), + OPT_CALLBACK(0, "filter-pids", &trace, "float", + "show only events with duration > N.M ms", trace__set_filter_pids), OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide, "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu", From 77c92582a52308868b6ef30a7e551eaceb0fc246 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 11:49:10 -0800 Subject: [PATCH 06/21] perf trace: Add man page entry for --event Forgot to do it when adding the feature. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-mx152b6x9cgknhw91vsyjlnd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-trace.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index d6778e66fa92..ba03fd5d1a54 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt @@ -118,6 +118,9 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. --syscalls:: Trace system calls. This options is enabled by default. +--event:: + Trace other events, see 'perf list' for a complete list. + PAGEFAULTS ---------- From ddbb1b131062d020085577db700c3e816a227901 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 21 Feb 2015 12:10:29 -0800 Subject: [PATCH 07/21] perf trace: Separate routine that handles an event from the one that reads it Because we need to use ordered_events in some cases, so we will need to first have them in a queue, order that queue, and then process the event. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-cmkw9zgoh0z4r218957ftp1a@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 58 ++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 60ccfd52189d..fbdfb338bc38 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2092,10 +2092,39 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, return 0; } +static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) +{ + const u32 type = event->header.type; + struct perf_evsel *evsel; + + if (!trace->full_time && trace->base_time == 0) + trace->base_time = sample->time; + + if (type != PERF_RECORD_SAMPLE) { + trace__process_event(trace, trace->host, event, sample); + return; + } + + evsel = perf_evlist__id2evsel(trace->evlist, sample->id); + if (evsel == NULL) { + fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id); + return; + } + + if (evsel->attr.type == PERF_TYPE_TRACEPOINT && + sample->raw_data == NULL) { + fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", + perf_evsel__name(evsel), sample->tid, + sample->cpu, sample->raw_size); + } else { + tracepoint_handler handler = evsel->handler; + handler(trace, evsel, event, sample); + } +} + static int trace__run(struct trace *trace, int argc, const char **argv) { struct perf_evlist *evlist = trace->evlist; - struct perf_evsel *evsel; int err = -1, i; unsigned long before; const bool forks = argc > 0; @@ -2190,8 +2219,6 @@ again: union perf_event *event; while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { - const u32 type = event->header.type; - tracepoint_handler handler; struct perf_sample sample; ++trace->nr_events; @@ -2202,30 +2229,7 @@ again: goto next_event; } - if (!trace->full_time && trace->base_time == 0) - trace->base_time = sample.time; - - if (type != PERF_RECORD_SAMPLE) { - trace__process_event(trace, trace->host, event, &sample); - continue; - } - - evsel = perf_evlist__id2evsel(evlist, sample.id); - if (evsel == NULL) { - fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); - goto next_event; - } - - if (evsel->attr.type == PERF_TYPE_TRACEPOINT && - sample.raw_data == NULL) { - fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", - perf_evsel__name(evsel), sample.tid, - sample.cpu, sample.raw_size); - goto next_event; - } - - handler = evsel->handler; - handler(trace, evsel, event, &sample); + trace__handle_event(trace, event, &sample); next_event: perf_evlist__mmap_consume(evlist, i); From 54245fdc357613633954bfd38cffb71cb9def067 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 14 Feb 2015 14:26:15 -0300 Subject: [PATCH 08/21] perf session: Remove wrappers to machines__find Start to untangle session from delivering samples, as there are tools that want to use ordered_events and don't use perf_session at all. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-rn4pk3pjxd78sgzrkn19tktp@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 504b7e664e6c..fac08e1f6330 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -797,8 +797,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, sample_read__printf(sample, evsel->attr.read_format); } -static struct machine * - perf_session__find_machine_for_cpumode(struct perf_session *session, +static struct machine *machines__find_for_cpumode(struct machines *machines, union perf_event *event, struct perf_sample *sample) { @@ -816,14 +815,13 @@ static struct machine * else pid = sample->pid; - machine = perf_session__find_machine(session, pid); + machine = machines__find(machines, pid); if (!machine) - machine = perf_session__findnew_machine(session, - DEFAULT_GUEST_KERNEL_ID); + machine = machines__find(machines, DEFAULT_GUEST_KERNEL_ID); return machine; } - return &session->machines.host; + return &machines->host; } static int deliver_sample_value(struct perf_session *session, @@ -907,8 +905,7 @@ int perf_session__deliver_event(struct perf_session *session, evsel = perf_evlist__id2evsel(session->evlist, sample->id); - machine = perf_session__find_machine_for_cpumode(session, event, - sample); + machine = machines__find_for_cpumode(&session->machines, event, sample); switch (event->header.type) { case PERF_RECORD_SAMPLE: From 75be989a7a18e9666efd92b846ee48bed79e8086 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 14 Feb 2015 14:50:11 -0300 Subject: [PATCH 09/21] perf evlist: Adopt events_stats from perf_session For tools that don't deal with perf.data files, thus do not need to use perf_session. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-kglq67gvauq9tak02a4se00r@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 6 ++--- tools/perf/builtin-top.c | 4 +-- tools/perf/util/evlist.h | 1 + tools/perf/util/session.c | 54 +++++++++++++++++++------------------- tools/perf/util/session.h | 1 - 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 891c3930080e..7ce296618717 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1473,9 +1473,9 @@ static int perf_sched__read_events(struct perf_sched *sched, goto out_delete; } - sched->nr_events = session->stats.nr_events[0]; - sched->nr_lost_events = session->stats.total_lost; - sched->nr_lost_chunks = session->stats.nr_events[PERF_RECORD_LOST]; + sched->nr_events = session->evlist->stats.nr_events[0]; + sched->nr_lost_events = session->evlist->stats.total_lost; + sched->nr_lost_chunks = session->evlist->stats.nr_events[PERF_RECORD_LOST]; } if (psession) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c4c7eac69de4..5fb8723c7128 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -716,7 +716,7 @@ static void perf_event__process_sample(struct perf_tool *tool, if (!machine) { pr_err("%u unprocessable samples recorded.\r", - top->session->stats.nr_unprocessable_samples++); + top->session->evlist->stats.nr_unprocessable_samples++); return; } @@ -856,7 +856,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) hists__inc_nr_events(evsel__hists(evsel), event->header.type); machine__process_event(machine, event, &sample); } else - ++session->stats.nr_unknown_events; + ++session->evlist->stats.nr_unknown_events; next_event: perf_evlist__mmap_consume(top->evlist, idx); } diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index c19ff45c9ad5..d4768a30f884 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -51,6 +51,7 @@ struct perf_evlist { struct thread_map *threads; struct cpu_map *cpus; struct perf_evsel *selected; + struct events_stats stats; }; struct perf_evsel_str_handler { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index fac08e1f6330..06ef1c35a65a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -537,7 +537,7 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event, pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", oe->last_flush_type); - s->stats.nr_unordered_events++; + s->evlist->stats.nr_unordered_events++; } new = ordered_events__new(oe, timestamp, event); @@ -841,7 +841,7 @@ static int deliver_sample_value(struct perf_session *session, } if (!sid || sid->evsel == NULL) { - ++session->stats.nr_unknown_id; + ++session->evlist->stats.nr_unknown_id; return 0; } @@ -911,11 +911,11 @@ int perf_session__deliver_event(struct perf_session *session, case PERF_RECORD_SAMPLE: dump_sample(evsel, event, sample); if (evsel == NULL) { - ++session->stats.nr_unknown_id; + ++session->evlist->stats.nr_unknown_id; return 0; } if (machine == NULL) { - ++session->stats.nr_unprocessable_samples; + ++session->evlist->stats.nr_unprocessable_samples; return 0; } return perf_session__deliver_sample(session, tool, event, @@ -932,7 +932,7 @@ int perf_session__deliver_event(struct perf_session *session, return tool->exit(tool, event, sample, machine); case PERF_RECORD_LOST: if (tool->lost == perf_event__process_lost) - session->stats.total_lost += event->lost.lost; + session->evlist->stats.total_lost += event->lost.lost; return tool->lost(tool, event, sample, machine); case PERF_RECORD_READ: return tool->read(tool, event, sample, evsel, machine); @@ -941,7 +941,7 @@ int perf_session__deliver_event(struct perf_session *session, case PERF_RECORD_UNTHROTTLE: return tool->unthrottle(tool, event, sample, machine); default: - ++session->stats.nr_unknown_events; + ++session->evlist->stats.nr_unknown_events; return -1; } } @@ -991,7 +991,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, struct perf_sample *sample, struct perf_tool *tool) { - events_stats__inc(&session->stats, event->header.type); + events_stats__inc(&session->evlist->stats, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, tool, 0); @@ -1077,7 +1077,7 @@ static s64 perf_session__process_event(struct perf_session *session, if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; - events_stats__inc(&session->stats, event->header.type); + events_stats__inc(&session->evlist->stats, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, tool, file_offset); @@ -1129,43 +1129,43 @@ static void perf_session__warn_about_errors(const struct perf_session *session, const struct perf_tool *tool) { if (tool->lost == perf_event__process_lost && - session->stats.nr_events[PERF_RECORD_LOST] != 0) { + session->evlist->stats.nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", - session->stats.nr_events[0], - session->stats.nr_events[PERF_RECORD_LOST]); + session->evlist->stats.nr_events[0], + session->evlist->stats.nr_events[PERF_RECORD_LOST]); } - if (session->stats.nr_unknown_events != 0) { + if (session->evlist->stats.nr_unknown_events != 0) { ui__warning("Found %u unknown events!\n\n" "Is this an older tool processing a perf.data " "file generated by a more recent tool?\n\n" "If that is not the case, consider " "reporting to linux-kernel@vger.kernel.org.\n\n", - session->stats.nr_unknown_events); + session->evlist->stats.nr_unknown_events); } - if (session->stats.nr_unknown_id != 0) { + if (session->evlist->stats.nr_unknown_id != 0) { ui__warning("%u samples with id not present in the header\n", - session->stats.nr_unknown_id); + session->evlist->stats.nr_unknown_id); } - if (session->stats.nr_invalid_chains != 0) { - ui__warning("Found invalid callchains!\n\n" - "%u out of %u events were discarded for this reason.\n\n" - "Consider reporting to linux-kernel@vger.kernel.org.\n\n", - session->stats.nr_invalid_chains, - session->stats.nr_events[PERF_RECORD_SAMPLE]); - } + if (session->evlist->stats.nr_invalid_chains != 0) { + ui__warning("Found invalid callchains!\n\n" + "%u out of %u events were discarded for this reason.\n\n" + "Consider reporting to linux-kernel@vger.kernel.org.\n\n", + session->evlist->stats.nr_invalid_chains, + session->evlist->stats.nr_events[PERF_RECORD_SAMPLE]); + } - if (session->stats.nr_unprocessable_samples != 0) { + if (session->evlist->stats.nr_unprocessable_samples != 0) { ui__warning("%u unprocessable samples recorded.\n" "Do you have a KVM guest running and not using 'perf kvm'?\n", - session->stats.nr_unprocessable_samples); + session->evlist->stats.nr_unprocessable_samples); } - if (session->stats.nr_unordered_events != 0) - ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events); + if (session->evlist->stats.nr_unordered_events != 0) + ui__warning("%u out of order events recorded.\n", session->evlist->stats.nr_unordered_events); } volatile int session_done; @@ -1485,7 +1485,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) { size_t ret = fprintf(fp, "Aggregated stats:\n"); - ret += events_stats__fprintf(&session->stats, fp); + ret += events_stats__fprintf(&session->evlist->stats, fp); return ret; } diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 6d663dc76404..fe859f379ca7 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -20,7 +20,6 @@ struct perf_session { struct machines machines; struct perf_evlist *evlist; struct trace_event tevent; - struct events_stats stats; bool repipe; bool one_mmap; void *one_mmap_addr; From ccda068f96138734eb40e9202ea9562566b43c12 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 14 Feb 2015 14:57:13 -0300 Subject: [PATCH 10/21] perf session: Remove perf_session from warn_errors signature Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pxxm1liohog3d6i826x8sud8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 06ef1c35a65a..34dd749dc390 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1125,47 +1125,47 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se return thread; } -static void perf_session__warn_about_errors(const struct perf_session *session, - const struct perf_tool *tool) +static void perf_tool__warn_about_errors(const struct perf_tool *tool, + const struct events_stats *stats) { if (tool->lost == perf_event__process_lost && - session->evlist->stats.nr_events[PERF_RECORD_LOST] != 0) { + stats->nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", - session->evlist->stats.nr_events[0], - session->evlist->stats.nr_events[PERF_RECORD_LOST]); + stats->nr_events[0], + stats->nr_events[PERF_RECORD_LOST]); } - if (session->evlist->stats.nr_unknown_events != 0) { + if (stats->nr_unknown_events != 0) { ui__warning("Found %u unknown events!\n\n" "Is this an older tool processing a perf.data " "file generated by a more recent tool?\n\n" "If that is not the case, consider " "reporting to linux-kernel@vger.kernel.org.\n\n", - session->evlist->stats.nr_unknown_events); + stats->nr_unknown_events); } - if (session->evlist->stats.nr_unknown_id != 0) { + if (stats->nr_unknown_id != 0) { ui__warning("%u samples with id not present in the header\n", - session->evlist->stats.nr_unknown_id); + stats->nr_unknown_id); } - if (session->evlist->stats.nr_invalid_chains != 0) { + if (stats->nr_invalid_chains != 0) { ui__warning("Found invalid callchains!\n\n" "%u out of %u events were discarded for this reason.\n\n" "Consider reporting to linux-kernel@vger.kernel.org.\n\n", - session->evlist->stats.nr_invalid_chains, - session->evlist->stats.nr_events[PERF_RECORD_SAMPLE]); + stats->nr_invalid_chains, + stats->nr_events[PERF_RECORD_SAMPLE]); } - if (session->evlist->stats.nr_unprocessable_samples != 0) { + if (stats->nr_unprocessable_samples != 0) { ui__warning("%u unprocessable samples recorded.\n" "Do you have a KVM guest running and not using 'perf kvm'?\n", - session->evlist->stats.nr_unprocessable_samples); + stats->nr_unprocessable_samples); } - if (session->evlist->stats.nr_unordered_events != 0) - ui__warning("%u out of order events recorded.\n", session->evlist->stats.nr_unordered_events); + if (stats->nr_unordered_events != 0) + ui__warning("%u out of order events recorded.\n", stats->nr_unordered_events); } volatile int session_done; @@ -1255,7 +1255,7 @@ done: err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); out_err: free(buf); - perf_session__warn_about_errors(session, tool); + perf_tool__warn_about_errors(tool, &session->evlist->stats); ordered_events__free(&session->ordered_events); return err; } @@ -1400,7 +1400,7 @@ out: err = ordered_events__flush(session, tool, OE_FLUSH__FINAL); out_err: ui_progress__finish(); - perf_session__warn_about_errors(session, tool); + perf_tool__warn_about_errors(tool, &session->evlist->stats); ordered_events__free(&session->ordered_events); session->one_mmap = false; return err; From 313e53b08e99b1dacf9ea2b0fbe97890db1ea95f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 14 Feb 2015 15:05:28 -0300 Subject: [PATCH 11/21] perf session: Remove perf_session from some deliver event routines Further untangling perf_session from plain event delivery routines. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-cvz8e6pwyogs4w14582iis9w@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 34dd749dc390..0133d01d51bd 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -824,16 +824,15 @@ static struct machine *machines__find_for_cpumode(struct machines *machines, return &machines->host; } -static int deliver_sample_value(struct perf_session *session, +static int deliver_sample_value(struct perf_evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct sample_read_value *v, struct machine *machine) { - struct perf_sample_id *sid; + struct perf_sample_id *sid = perf_evlist__id2sid(evlist, v->id); - sid = perf_evlist__id2sid(session->evlist, v->id); if (sid) { sample->id = v->id; sample->period = v->value - sid->period; @@ -841,14 +840,14 @@ static int deliver_sample_value(struct perf_session *session, } if (!sid || sid->evsel == NULL) { - ++session->evlist->stats.nr_unknown_id; + ++evlist->stats.nr_unknown_id; return 0; } return tool->sample(tool, event, sample, sid->evsel, machine); } -static int deliver_sample_group(struct perf_session *session, +static int deliver_sample_group(struct perf_evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -858,7 +857,7 @@ static int deliver_sample_group(struct perf_session *session, u64 i; for (i = 0; i < sample->read.group.nr; i++) { - ret = deliver_sample_value(session, tool, event, sample, + ret = deliver_sample_value(evlist, tool, event, sample, &sample->read.group.values[i], machine); if (ret) @@ -869,7 +868,7 @@ static int deliver_sample_group(struct perf_session *session, } static int -perf_session__deliver_sample(struct perf_session *session, + perf_evlist__deliver_sample(struct perf_evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -886,10 +885,10 @@ perf_session__deliver_sample(struct perf_session *session, /* For PERF_SAMPLE_READ we have either single or group mode. */ if (read_format & PERF_FORMAT_GROUP) - return deliver_sample_group(session, tool, event, sample, + return deliver_sample_group(evlist, tool, event, sample, machine); else - return deliver_sample_value(session, tool, event, sample, + return deliver_sample_value(evlist, tool, event, sample, &sample->read.one, machine); } @@ -898,12 +897,13 @@ int perf_session__deliver_event(struct perf_session *session, struct perf_sample *sample, struct perf_tool *tool, u64 file_offset) { + struct perf_evlist *evlist = session->evlist; struct perf_evsel *evsel; struct machine *machine; dump_event(session, event, file_offset, sample); - evsel = perf_evlist__id2evsel(session->evlist, sample->id); + evsel = perf_evlist__id2evsel(evlist, sample->id); machine = machines__find_for_cpumode(&session->machines, event, sample); @@ -911,15 +911,14 @@ int perf_session__deliver_event(struct perf_session *session, case PERF_RECORD_SAMPLE: dump_sample(evsel, event, sample); if (evsel == NULL) { - ++session->evlist->stats.nr_unknown_id; + ++evlist->stats.nr_unknown_id; return 0; } if (machine == NULL) { - ++session->evlist->stats.nr_unprocessable_samples; + ++evlist->stats.nr_unprocessable_samples; return 0; } - return perf_session__deliver_sample(session, tool, event, - sample, evsel, machine); + return perf_evlist__deliver_sample(evlist, tool, event, sample, evsel, machine); case PERF_RECORD_MMAP: return tool->mmap(tool, event, sample, machine); case PERF_RECORD_MMAP2: @@ -932,7 +931,7 @@ int perf_session__deliver_event(struct perf_session *session, return tool->exit(tool, event, sample, machine); case PERF_RECORD_LOST: if (tool->lost == perf_event__process_lost) - session->evlist->stats.total_lost += event->lost.lost; + evlist->stats.total_lost += event->lost.lost; return tool->lost(tool, event, sample, machine); case PERF_RECORD_READ: return tool->read(tool, event, sample, evsel, machine); @@ -941,7 +940,7 @@ int perf_session__deliver_event(struct perf_session *session, case PERF_RECORD_UNTHROTTLE: return tool->unthrottle(tool, event, sample, machine); default: - ++session->evlist->stats.nr_unknown_events; + ++evlist->stats.nr_unknown_events; return -1; } } @@ -1068,16 +1067,17 @@ static s64 perf_session__process_event(struct perf_session *session, struct perf_tool *tool, u64 file_offset) { + struct perf_evlist *evlist = session->evlist; struct perf_sample sample; int ret; if (session->header.needs_swap) - event_swap(event, perf_evlist__sample_id_all(session->evlist)); + event_swap(event, perf_evlist__sample_id_all(evlist)); if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; - events_stats__inc(&session->evlist->stats, event->header.type); + events_stats__inc(&evlist->stats, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) return perf_session__process_user_event(session, event, tool, file_offset); @@ -1085,7 +1085,7 @@ static s64 perf_session__process_event(struct perf_session *session, /* * For all kernel events we get the sample data */ - ret = perf_evlist__parse_sample(session->evlist, event, &sample); + ret = perf_evlist__parse_sample(evlist, event, &sample); if (ret) return ret; From 9fa8727aa4d98d35ca50ef9cd8a50c6468af921d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 14 Feb 2015 15:08:51 -0300 Subject: [PATCH 12/21] perf session: Remove perf_session from dump_event All it wants is session->evlist. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-6w9663gka3jb1j1rfxxd5jcq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0133d01d51bd..e4f166981ff0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -688,14 +688,14 @@ static void stack_user__printf(struct stack_dump *dump) dump->size, dump->offset); } -static void perf_session__print_tstamp(struct perf_session *session, +static void perf_evlist__print_tstamp(struct perf_evlist *evlist, union perf_event *event, struct perf_sample *sample) { - u64 sample_type = __perf_evlist__combined_sample_type(session->evlist); + u64 sample_type = __perf_evlist__combined_sample_type(evlist); if (event->header.type != PERF_RECORD_SAMPLE && - !perf_evlist__sample_id_all(session->evlist)) { + !perf_evlist__sample_id_all(evlist)) { fputs("-1 -1 ", stdout); return; } @@ -737,7 +737,7 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format) sample->read.one.id, sample->read.one.value); } -static void dump_event(struct perf_session *session, union perf_event *event, +static void dump_event(struct perf_evlist *evlist, union perf_event *event, u64 file_offset, struct perf_sample *sample) { if (!dump_trace) @@ -749,7 +749,7 @@ static void dump_event(struct perf_session *session, union perf_event *event, trace_event(event); if (sample) - perf_session__print_tstamp(session, event, sample); + perf_evlist__print_tstamp(evlist, event, sample); printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, event->header.size, perf_event__name(event->header.type)); @@ -901,7 +901,7 @@ int perf_session__deliver_event(struct perf_session *session, struct perf_evsel *evsel; struct machine *machine; - dump_event(session, event, file_offset, sample); + dump_event(evlist, event, file_offset, sample); evsel = perf_evlist__id2evsel(evlist, sample->id); @@ -953,7 +953,7 @@ static s64 perf_session__process_user_event(struct perf_session *session, int fd = perf_data_file__fd(session->file); int err; - dump_event(session, event, file_offset, NULL); + dump_event(session->evlist, event, file_offset, NULL); /* These events are processed right away */ switch (event->header.type) { From 280836812f5f821d26393268010f211160874810 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 22 Feb 2015 13:52:47 -0800 Subject: [PATCH 13/21] perf ordered_events: Stop using tool->ordered_events To figure out if ordered_events are being used when doing a flush operation, it is enough to check if there were in fact some events queued, i.e. look at oe->nr_events. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-1c5r404vy766kt5nflv88uag@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/ordered-events.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index fd4be94125fb..077ddd25189f 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -166,7 +166,7 @@ static int __ordered_events__flush(struct perf_session *s, struct ui_progress prog; int ret; - if (!tool->ordered_events || !limit) + if (!limit) return 0; if (show_progress) @@ -216,6 +216,9 @@ int ordered_events__flush(struct perf_session *s, struct perf_tool *tool, }; int err; + if (oe->nr_events == 0) + return 0; + switch (how) { case OE_FLUSH__FINAL: oe->next_flush = ULLONG_MAX; From 07c1a0dadfce976e9877c55ce5212dd14753c91d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Feb 2015 15:34:23 -0300 Subject: [PATCH 14/21] perf tools: Introduce dump_stack signal helper To use in stdio based tools, like 'trace'. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-79kjmerlw6d88csyx1afzwvn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/util.c | 7 +++++++ tools/perf/util/util.h | 1 + 2 files changed, 8 insertions(+) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 92db3f156b63..4ee6d0d4c993 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -269,6 +269,13 @@ void dump_stack(void) void dump_stack(void) {} #endif +void sighandler_dump_stack(int sig) +{ + psignal(sig, "perf"); + dump_stack(); + exit(sig); +} + void get_term_dimensions(struct winsize *ws) { char *s = getenv("LINES"); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 73c2f8e557ab..fbd598afc606 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -277,6 +277,7 @@ char *ltrim(char *s); char *rtrim(char *s); void dump_stack(void); +void sighandler_dump_stack(int sig); extern unsigned int page_size; extern int cacheline_size; From 4d08cb80ef5199258c01a3444fd29d94a36a0343 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Feb 2015 15:35:55 -0300 Subject: [PATCH 15/21] perf trace: Dump stack on segfaults [root@ssdandy ~]# perf trace --filter-pids 16348 0.000 ( 0.000 ms): tuned/1027 ... [continued]: select()) = 0 Timeout 793.770 ( 0.000 ms): lsmd/895 ... [continued]: select()) = 0 Timeout 793.775 (793.724 ms): tuned/1027 select(tvp: 0x7f7655556e50) ... perf: Segmentation fault Obtained 15 stack frames. perf(dump_stack+0x2e) [0x4ed330] perf(sighandler_dump_stack+0x2e) [0x4ed40f] /lib64/libc.so.6(+0x35640) [0x7fa2d5b69640] perf() [0x4c2d35] perf(machine__findnew_thread+0x39) [0x4c2ed6] perf() [0x454a4d] perf() [0x455f87] perf() [0x456556] perf(cmd_trace+0xa7e) [0x4580af] perf() [0x4867bd] perf() [0x486a1c] perf() [0x486b68] perf(main+0x23b) [0x486ec9] /lib64/libc.so.6(__libc_start_main+0xf5) [0x7fa2d5b55af5] perf() [0x41bd91] [ root@ssdandy ~]# Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-v38cbxcnm2yf5qn9u4y4n9ab@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index fbdfb338bc38..5cd8497445fe 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2660,6 +2660,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) int err; char bf[BUFSIZ]; + signal(SIGSEGV, sighandler_dump_stack); + signal(SIGFPE, sighandler_dump_stack); + trace.evlist = perf_evlist__new(); if (trace.evlist == NULL) return -ENOMEM; From 506740654db4fa5b6e1229147cee3cf8c7e07eca Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 24 Feb 2015 17:20:31 -0300 Subject: [PATCH 16/21] perf tools: Print the thread's tid on PERF_RECORD_COMM events when -D is asked Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Don Zickus Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-fmto8ft6jrtwz09dxn5d4z8w@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6c6d044e959a..9e806d855b04 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -615,7 +615,7 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) else s = ""; - return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid); + return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); } int perf_event__process_comm(struct perf_tool *tool __maybe_unused, From 85c273d2b6569706762cf400079ca0699e007d81 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 24 Feb 2015 15:13:40 -0800 Subject: [PATCH 17/21] perf record: Support recording running/enabled time Add an option to perf record to record running/enabled time for read events, similar to what stat does. This is useful to understand multiplexing problems. Right now the report support is not great, but at least report -D already supports it. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1424819620-16043-1-git-send-email-andi@firstfloor.org [ Fixed the Documentation entry to match the OPT_BOOLEAN one ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 3 +++ tools/perf/builtin-record.c | 2 ++ tools/perf/perf.h | 1 + tools/perf/util/evsel.c | 6 ++++++ 4 files changed, 12 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 1c7e50f62b1f..cae75c11120f 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -241,6 +241,9 @@ Capture machine state (registers) at interrupt, i.e., on counter overflows for each sample. List of captured registers depends on the architecture. This option is off by default. +--running-time:: +Record running and enabled time for read events (:S) + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index d0d02a811ecd..4fdad06d37db 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -839,6 +839,8 @@ struct option __record_options[] = { "use per-thread mmaps"), OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs, "Sample machine registers on interrupt"), + OPT_BOOLEAN(0, "running-time", &record.opts.running_time, + "Record running/enabled time of read (:S) events"), OPT_END() }; diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 1dabb8553499..1caa70a4a9e1 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -53,6 +53,7 @@ struct record_opts { bool sample_time; bool period; bool sample_intr_regs; + bool running_time; unsigned int freq; unsigned int mmap_pages; unsigned int user_freq; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f93e5208c762..bb4eff28869e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -734,6 +734,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) if (opts->sample_transaction) perf_evsel__set_sample_bit(evsel, TRANSACTION); + if (opts->running_time) { + evsel->attr.read_format |= + PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING; + } + /* * XXX see the function comment above * From 53d0a57343949b2af9b27229db534b98e5a0c4d0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 20 Feb 2015 23:16:58 +0100 Subject: [PATCH 18/21] perf tools: Add feature check for libbabeltrace Adding feature check for babeltrace library [1], which will be used for perf data file CTF [2] conversion in following patches. The babeltrace library is now automatically detected as standard feature. It's possible to specify LIBBABELTRACE_DIR make variable to specify location of installed libbabeltrace, like: $ make LIBBABELTRACE_DIR=/opt/libbabeltrace/ BUILD: Doing 'make -j4' parallel build Auto-detecting system features: ... dwarf: [ on ] ... glibc: [ on ] ... gtk2: [ on ] ... libaudit: [ on ] ... libbfd: [ on ] ... libelf: [ on ] ... libnuma: [ on ] ... libperl: [ on ] ... libpython: [ on ] ... libslang: [ on ] ... libunwind: [ on ] ... libbabeltrace: [ on ] ... libdw-dwarf-unwind: [ on ] ... zlib: [ on ] ... DWARF post unwind library: libunwind NOTE The installation of the [1] to to used by above make: $ git clone git://git.efficios.com/babeltrace.git $ cd babeltrace $ vim README $ ./bootstrap $ ./configure --prefix=/opt/libbabeltrace $ make prefix=/opt/libbabeltrace $ sudo make install prefix=/opt/libbabeltrace Please make sure that the /opt/libbabeltrace/lib directory is in your LD_LIBRARY_PATH: $ export LD_LIBRARY_PATH=/opt/libbabeltrace/lib [1] babeltrace - http://www.efficios.com/babeltrace [2] Common Trace Format - http://www.efficios.com/ctf Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Reviewed-by: David Ahern Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Cc: Wang Nan Link: http://lkml.kernel.org/r/1424470628-5969-2-git-send-email-jolsa@kernel.org Signed-off-by: Sebastian Andrzej Siewior [ Added missing babeltrace build instructions ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 4 +++- tools/perf/config/Makefile | 24 +++++++++++++++++++ tools/perf/config/feature-checks/Makefile | 8 +++++-- tools/perf/config/feature-checks/test-all.c | 5 ++++ .../feature-checks/test-libbabeltrace.c | 8 +++++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tools/perf/config/feature-checks/test-libbabeltrace.c diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index efc5158738f4..ec4c063ed9f3 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -68,7 +68,9 @@ include config/utilities.mak # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode # # Define NO_ZLIB if you do not want to support compressed kernel modules - +# +# Define NO_LIBBABELTRACE if you do not want libbabeltrace support +# for CTF data format. ifeq ($(srctree),) srctree := $(patsubst %/,%,$(dir $(shell pwd))) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index b97a7b903a23..6f129b0a9c64 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -96,6 +96,17 @@ ifndef NO_LIBELF FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind := $(LIBDW_LDFLAGS) -ldw endif +ifndef NO_LIBBABELTRACE + # for linking with debug library, run like: + # make DEBUG=1 LIBBABELTRACE_DIR=/opt/libbabeltrace/ + ifdef LIBBABELTRACE_DIR + LIBBABELTRACE_CFLAGS := -I$(LIBBABELTRACE_DIR)/include + LIBBABELTRACE_LDFLAGS := -L$(LIBBABELTRACE_DIR)/lib + endif + FEATURE_CHECK_CFLAGS-libbabeltrace := $(LIBBABELTRACE_CFLAGS) + FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf +endif + # include ARCH specific config -include $(src-perf)/arch/$(ARCH)/Makefile @@ -216,6 +227,7 @@ CORE_FEATURE_TESTS = \ stackprotector-all \ timerfd \ libdw-dwarf-unwind \ + libbabeltrace \ zlib LIB_FEATURE_TESTS = \ @@ -231,6 +243,7 @@ LIB_FEATURE_TESTS = \ libslang \ libunwind \ libdw-dwarf-unwind \ + libbabeltrace \ zlib VF_FEATURE_TESTS = \ @@ -692,6 +705,17 @@ else NO_PERF_READ_VDSOX32 := 1 endif +ifndef NO_LIBBABELTRACE + ifeq ($(feature-libbabeltrace), 0) + msg := $(warning No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-devel/libbabeltrace-ctf-dev); + NO_LIBBABELTRACE := 1 + else + CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) + LDFLAGS += $(LIBBABELTRACE_LDFLAGS) + EXTLIBS += -lbabeltrace-ctf + endif +endif + # Among the variables below, these: # perfexecdir # template_dir diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index b32ff3372514..70c9aebe9da3 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -29,6 +29,7 @@ FILES= \ test-stackprotector-all.bin \ test-timerfd.bin \ test-libdw-dwarf-unwind.bin \ + test-libbabeltrace.bin \ test-compile-32.bin \ test-compile-x32.bin \ test-zlib.bin @@ -43,7 +44,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS) ############################### test-all.bin: - $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz + $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -lbabeltrace test-hello.bin: $(BUILD) @@ -133,7 +134,10 @@ test-timerfd.bin: $(BUILD) test-libdw-dwarf-unwind.bin: - $(BUILD) + $(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind) + +test-libbabeltrace.bin: + $(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace) test-sync-compare-and-swap.bin: $(BUILD) -Werror diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c index 6d4d09323922..1ffc3da5ca10 100644 --- a/tools/perf/config/feature-checks/test-all.c +++ b/tools/perf/config/feature-checks/test-all.c @@ -101,6 +101,10 @@ # include "test-pthread_attr_setaffinity_np.c" #undef main +#define main main_test_libbabeltrace +# include "test-libbabeltrace.c" +#undef main + int main(int argc, char *argv[]) { main_test_libpython(); @@ -126,6 +130,7 @@ int main(int argc, char *argv[]) main_test_sync_compare_and_swap(argc, argv); main_test_zlib(); main_test_pthread_attr_setaffinity_np(); + main_test_libbabeltrace(); return 0; } diff --git a/tools/perf/config/feature-checks/test-libbabeltrace.c b/tools/perf/config/feature-checks/test-libbabeltrace.c new file mode 100644 index 000000000000..3b7dd68a4d52 --- /dev/null +++ b/tools/perf/config/feature-checks/test-libbabeltrace.c @@ -0,0 +1,8 @@ + +#include + +int main(void) +{ + bt_ctf_stream_class_get_packet_context_type((void *) 0); + return 0; +} From 2245bf1410d2d719f3bfce729b07ab83fe6142f7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 20 Feb 2015 23:16:59 +0100 Subject: [PATCH 19/21] perf tools: Add new 'perf data' command Adding new 'perf data' command to provide operations over data files. The 'perf data convert' sub command is coming in following patch, but there's possibility for other useful commands like 'perf data ls' (to display perf data file in directory in ls style). Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Reviewed-by: David Ahern Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Cc: Wang Nan Link: http://lkml.kernel.org/r/1424470628-5969-3-git-send-email-jolsa@kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Build | 1 + tools/perf/Documentation/perf-data.txt | 15 ++++++ tools/perf/builtin-data.c | 75 ++++++++++++++++++++++++++ tools/perf/builtin.h | 1 + tools/perf/command-list.txt | 1 + tools/perf/perf.c | 1 + 6 files changed, 94 insertions(+) create mode 100644 tools/perf/Documentation/perf-data.txt create mode 100644 tools/perf/builtin-data.c diff --git a/tools/perf/Build b/tools/perf/Build index 976e03849f6d..b77370ef7005 100644 --- a/tools/perf/Build +++ b/tools/perf/Build @@ -18,6 +18,7 @@ perf-y += builtin-lock.o perf-y += builtin-kvm.o perf-y += builtin-inject.o perf-y += builtin-mem.o +perf-y += builtin-data.o perf-$(CONFIG_AUDIT) += builtin-trace.o perf-$(CONFIG_LIBELF) += builtin-probe.o diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt new file mode 100644 index 000000000000..b8c83947715c --- /dev/null +++ b/tools/perf/Documentation/perf-data.txt @@ -0,0 +1,15 @@ +perf-data(1) +============== + +NAME +---- +perf-data - Data file related processing + +SYNOPSIS +-------- +[verse] +'perf data' [] []", + +DESCRIPTION +----------- +Data file related processing. diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c new file mode 100644 index 000000000000..1eee97d020fa --- /dev/null +++ b/tools/perf/builtin-data.c @@ -0,0 +1,75 @@ +#include +#include "builtin.h" +#include "perf.h" +#include "debug.h" +#include "parse-options.h" + +typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); + +struct data_cmd { + const char *name; + const char *summary; + data_cmd_fn_t fn; +}; + +static struct data_cmd data_cmds[]; + +#define for_each_cmd(cmd) \ + for (cmd = data_cmds; cmd && cmd->name; cmd++) + +static const struct option data_options[] = { + OPT_END() +}; + +static const char * const data_usage[] = { + "perf data [] []", + NULL +}; + +static void print_usage(void) +{ + struct data_cmd *cmd; + + printf("Usage:\n"); + printf("\t%s\n\n", data_usage[0]); + printf("\tAvailable commands:\n"); + + for_each_cmd(cmd) { + printf("\t %s\t- %s\n", cmd->name, cmd->summary); + } + + printf("\n"); +} + +static struct data_cmd data_cmds[] = { + { NULL }, +}; + +int cmd_data(int argc, const char **argv, const char *prefix) +{ + struct data_cmd *cmd; + const char *cmdstr; + + /* No command specified. */ + if (argc < 2) + goto usage; + + argc = parse_options(argc, argv, data_options, data_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + if (argc < 1) + goto usage; + + cmdstr = argv[0]; + + for_each_cmd(cmd) { + if (strcmp(cmd->name, cmdstr)) + continue; + + return cmd->fn(argc, argv, prefix); + } + + pr_err("Unknown command: %s\n", cmdstr); +usage: + print_usage(); + return -1; +} diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index b210d62907e4..3688ad29085f 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h @@ -37,6 +37,7 @@ extern int cmd_test(int argc, const char **argv, const char *prefix); extern int cmd_trace(int argc, const char **argv, const char *prefix); extern int cmd_inject(int argc, const char **argv, const char *prefix); extern int cmd_mem(int argc, const char **argv, const char *prefix); +extern int cmd_data(int argc, const char **argv, const char *prefix); extern int find_scripts(char **scripts_array, char **scripts_path_array); #endif diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 0906fc401c52..00fcaf8a5b8d 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt @@ -7,6 +7,7 @@ perf-archive mainporcelain common perf-bench mainporcelain common perf-buildid-cache mainporcelain common perf-buildid-list mainporcelain common +perf-data mainporcelain common perf-diff mainporcelain common perf-evlist mainporcelain common perf-inject mainporcelain common diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 3700a7faca6c..f3c66b81c6be 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -62,6 +62,7 @@ static struct cmd_struct commands[] = { #endif { "inject", cmd_inject, 0 }, { "mem", cmd_mem, 0 }, + { "data", cmd_data, 0 }, }; struct pager_config { From edbe9817aeb540aa1494aa20276a2bfc7f4ab816 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 20 Feb 2015 23:17:00 +0100 Subject: [PATCH 20/21] perf data: Add perf data to CTF conversion support Adding 'perf data convert' to convert perf data file into different format. This patch adds support for CTF format conversion. To convert perf.data into CTF run: $ perf data convert --to-ctf=./ctf-data/ [ perf data convert: Converted 'perf.data' into CTF data './ctf-data/' ] [ perf data convert: Converted and wrote 11.268 MB (100230 samples) ] The command will create CTF metadata out of perf.data file (or one specified via -i option) and then convert all sample events into single CTF stream. Each sample_type bit is translated into separated CTF event field apart from following exceptions: PERF_SAMPLE_RAW - added in next patch PERF_SAMPLE_READ - TODO PERF_SAMPLE_CALLCHAIN - TODO PERF_SAMPLE_BRANCH_STACK - TODO PERF_SAMPLE_REGS_USER - TODO PERF_SAMPLE_STACK_USER - TODO $ perf --debug=data-convert=2 data convert ... The converted CTF data could be analyzed by CTF tools, like babletrace or tracecompass [1]. $ babeltrace ./ctf-data/ [03:19:13.962125533] (+?.?????????) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 1 } [03:19:13.962130001] (+0.000004468) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 1 } [03:19:13.962131936] (+0.000001935) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 8 } [03:19:13.962133732] (+0.000001796) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 114 } [03:19:13.962135557] (+0.000001825) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 2087 } [03:19:13.962137627] (+0.000002070) cycles: { }, { ip = 0xFFFFFFFF81361938, tid = 20714, pid = 20714, period = 37582 } [03:19:13.962161091] (+0.000023464) cycles: { }, { ip = 0xFFFFFFFF8124218F, tid = 20714, pid = 20714, period = 600246 } [03:19:13.962517569] (+0.000356478) cycles: { }, { ip = 0xFFFFFFFF811A75DB, tid = 20714, pid = 20714, period = 1325731 } [03:19:13.969518008] (+0.007000439) cycles: { }, { ip = 0x34080917B2, tid = 20714, pid = 20714, period = 1144298 } The following members to the ctf-environment were decided to be added to distinguish and specify perf CTF data: - domain It says "kernel" because it contains a kernel trace (not to be confused with a user space like lttng-ust does) - tracer_name It says perf. This can be used to distinguish between lttng and perf CTF based trace. - version The kernel version from stream. In addition to release, this is what it looks like on a Debian kernel: release = "3.14-1-amd64"; version = "3.14.0"; [1] http://projects.eclipse.org/projects/tools.tracecompass Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Reviewed-by: David Ahern Tested-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Tom Zanussi Cc: Wang Nan Link: http://lkml.kernel.org/r/1424470628-5969-4-git-send-email-jolsa@kernel.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-data.txt | 25 + tools/perf/Documentation/perf.txt | 7 +- tools/perf/builtin-data.c | 44 ++ tools/perf/config/Makefile | 1 + tools/perf/util/Build | 2 + tools/perf/util/data-convert-bt.c | 612 +++++++++++++++++++++++++ tools/perf/util/data-convert-bt.h | 8 + tools/perf/util/debug.c | 2 + tools/perf/util/debug.h | 1 + 9 files changed, 701 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/data-convert-bt.c create mode 100644 tools/perf/util/data-convert-bt.h diff --git a/tools/perf/Documentation/perf-data.txt b/tools/perf/Documentation/perf-data.txt index b8c83947715c..be8fa1a0a97e 100644 --- a/tools/perf/Documentation/perf-data.txt +++ b/tools/perf/Documentation/perf-data.txt @@ -13,3 +13,28 @@ SYNOPSIS DESCRIPTION ----------- Data file related processing. + +COMMANDS +-------- +convert:: + Converts perf data file into another format (only CTF [1] format is support by now). + It's possible to set data-convert debug variable to get debug messages from conversion, + like: + perf --debug data-convert data convert ... + +OPTIONS for 'convert' +--------------------- +--to-ctf:: + Triggers the CTF conversion, specify the path of CTF data directory. + +-i:: + Specify input perf data file path. + +-v:: +--verbose:: + Be more verbose (show counter open errors, etc). + +SEE ALSO +-------- +linkperf:perf[1] +[1] Common Trace Format - http://www.efficios.com/ctf diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 1e8e400b4493..2b131776363e 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt @@ -13,11 +13,16 @@ SYNOPSIS OPTIONS ------- --debug:: - Setup debug variable (just verbose for now) in value + Setup debug variable (see list below) in value range (0, 10). Use like: --debug verbose # sets verbose = 1 --debug verbose=2 # sets verbose = 2 + List of debug variables allowed to set: + verbose - general debug messages + ordered-events - ordered events object debug messages + data-convert - data convert command debug messages + --buildid-dir:: Setup buildid cache directory. It has higher priority than buildid.dir config file option. diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c index 1eee97d020fa..9705ba7e4c16 100644 --- a/tools/perf/builtin-data.c +++ b/tools/perf/builtin-data.c @@ -3,6 +3,7 @@ #include "perf.h" #include "debug.h" #include "parse-options.h" +#include "data-convert-bt.h" typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix); @@ -41,7 +42,50 @@ static void print_usage(void) printf("\n"); } +static const char * const data_convert_usage[] = { + "perf data convert []", + NULL +}; + +static int cmd_data_convert(int argc, const char **argv, + const char *prefix __maybe_unused) +{ + const char *to_ctf = NULL; + const struct option options[] = { + OPT_INCR('v', "verbose", &verbose, "be more verbose"), + OPT_STRING('i', "input", &input_name, "file", "input file name"), +#ifdef HAVE_LIBBABELTRACE_SUPPORT + OPT_STRING(0, "to-ctf", &to_ctf, NULL, "Convert to CTF format"), +#endif + OPT_END() + }; + +#ifndef HAVE_LIBBABELTRACE_SUPPORT + pr_err("No conversion support compiled in.\n"); + return -1; +#endif + + argc = parse_options(argc, argv, options, + data_convert_usage, 0); + if (argc) { + usage_with_options(data_convert_usage, options); + return -1; + } + + if (to_ctf) { +#ifdef HAVE_LIBBABELTRACE_SUPPORT + return bt_convert__perf2ctf(input_name, to_ctf); +#else + pr_err("The libbabeltrace support is not compiled in.\n"); + return -1; +#endif + } + + return 0; +} + static struct data_cmd data_cmds[] = { + { "convert", "converts data file between formats", cmd_data_convert }, { NULL }, }; diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 6f129b0a9c64..c3570b5f3bf3 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -713,6 +713,7 @@ ifndef NO_LIBBABELTRACE CFLAGS += -DHAVE_LIBBABELTRACE_SUPPORT $(LIBBABELTRACE_CFLAGS) LDFLAGS += $(LIBBABELTRACE_LDFLAGS) EXTLIBS += -lbabeltrace-ctf + $(call detected,CONFIG_LIBBABELTRACE) endif endif diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 32f9327b1a97..a2c8047d25f7 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -88,6 +88,8 @@ libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o +libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o + libperf-y += scripting-engines/ libperf-$(CONFIG_PERF_REGS) += perf_regs.o diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c new file mode 100644 index 000000000000..ff4826c1745f --- /dev/null +++ b/tools/perf/util/data-convert-bt.c @@ -0,0 +1,612 @@ +/* + * CTF writing support via babeltrace. + * + * Copyright (C) 2014, Jiri Olsa + * Copyright (C) 2014, Sebastian Andrzej Siewior + * + * Released under the GPL v2. (and only v2, not any later version) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "asm/bug.h" +#include "data-convert-bt.h" +#include "session.h" +#include "util.h" +#include "debug.h" +#include "tool.h" +#include "evlist.h" +#include "evsel.h" +#include "machine.h" + +#define pr_N(n, fmt, ...) \ + eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) + +#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) +#define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__) + +#define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__) + +struct evsel_priv { + struct bt_ctf_event_class *event_class; +}; + +struct ctf_writer { + /* writer primitives */ + struct bt_ctf_writer *writer; + struct bt_ctf_stream *stream; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_clock *clock; + + /* data types */ + union { + struct { + struct bt_ctf_field_type *s64; + struct bt_ctf_field_type *u64; + struct bt_ctf_field_type *s32; + struct bt_ctf_field_type *u32; + struct bt_ctf_field_type *string; + struct bt_ctf_field_type *u64_hex; + }; + struct bt_ctf_field_type *array[6]; + } data; +}; + +struct convert { + struct perf_tool tool; + struct ctf_writer writer; + + u64 events_size; + u64 events_count; +}; + +static int value_set(struct bt_ctf_field_type *type, + struct bt_ctf_event *event, + const char *name, u64 val) +{ + struct bt_ctf_field *field; + bool sign = bt_ctf_field_type_integer_get_signed(type); + int ret; + + field = bt_ctf_field_create(type); + if (!field) { + pr_err("failed to create a field %s\n", name); + return -1; + } + + if (sign) { + ret = bt_ctf_field_signed_integer_set_value(field, val); + if (ret) { + pr_err("failed to set field value %s\n", name); + goto err; + } + } else { + ret = bt_ctf_field_unsigned_integer_set_value(field, val); + if (ret) { + pr_err("failed to set field value %s\n", name); + goto err; + } + } + + ret = bt_ctf_event_set_payload(event, name, field); + if (ret) { + pr_err("failed to set payload %s\n", name); + goto err; + } + + pr2(" SET [%s = %" PRIu64 "]\n", name, val); + +err: + bt_ctf_field_put(field); + return ret; +} + +#define __FUNC_VALUE_SET(_name, _val_type) \ +static __maybe_unused int value_set_##_name(struct ctf_writer *cw, \ + struct bt_ctf_event *event, \ + const char *name, \ + _val_type val) \ +{ \ + struct bt_ctf_field_type *type = cw->data._name; \ + return value_set(type, event, name, (u64) val); \ +} + +#define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name) + +FUNC_VALUE_SET(s32) +FUNC_VALUE_SET(u32) +FUNC_VALUE_SET(s64) +FUNC_VALUE_SET(u64) +__FUNC_VALUE_SET(u64_hex, u64) + +static int add_generic_values(struct ctf_writer *cw, + struct bt_ctf_event *event, + struct perf_evsel *evsel, + struct perf_sample *sample) +{ + u64 type = evsel->attr.sample_type; + int ret; + + /* + * missing: + * PERF_SAMPLE_TIME - not needed as we have it in + * ctf event header + * PERF_SAMPLE_READ - TODO + * PERF_SAMPLE_CALLCHAIN - TODO + * PERF_SAMPLE_RAW - tracepoint fields are handled separately + * PERF_SAMPLE_BRANCH_STACK - TODO + * PERF_SAMPLE_REGS_USER - TODO + * PERF_SAMPLE_STACK_USER - TODO + */ + + if (type & PERF_SAMPLE_IP) { + ret = value_set_u64_hex(cw, event, "ip", sample->ip); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_TID) { + ret = value_set_s32(cw, event, "tid", sample->tid); + if (ret) + return -1; + + ret = value_set_s32(cw, event, "pid", sample->pid); + if (ret) + return -1; + } + + if ((type & PERF_SAMPLE_ID) || + (type & PERF_SAMPLE_IDENTIFIER)) { + ret = value_set_u64(cw, event, "id", sample->id); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_STREAM_ID) { + ret = value_set_u64(cw, event, "stream_id", sample->stream_id); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_CPU) { + ret = value_set_u32(cw, event, "cpu", sample->cpu); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_PERIOD) { + ret = value_set_u64(cw, event, "period", sample->period); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_WEIGHT) { + ret = value_set_u64(cw, event, "weight", sample->weight); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_DATA_SRC) { + ret = value_set_u64(cw, event, "data_src", sample->data_src); + if (ret) + return -1; + } + + if (type & PERF_SAMPLE_TRANSACTION) { + ret = value_set_u64(cw, event, "transaction", sample->transaction); + if (ret) + return -1; + } + + return 0; +} + +static int process_sample_event(struct perf_tool *tool, + union perf_event *_event __maybe_unused, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine __maybe_unused) +{ + struct convert *c = container_of(tool, struct convert, tool); + struct evsel_priv *priv = evsel->priv; + struct ctf_writer *cw = &c->writer; + struct bt_ctf_event_class *event_class; + struct bt_ctf_event *event; + int ret; + + if (WARN_ONCE(!priv, "Failed to setup all events.\n")) + return 0; + + event_class = priv->event_class; + + /* update stats */ + c->events_count++; + c->events_size += _event->header.size; + + pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count); + + event = bt_ctf_event_create(event_class); + if (!event) { + pr_err("Failed to create an CTF event\n"); + return -1; + } + + bt_ctf_clock_set_time(cw->clock, sample->time); + + ret = add_generic_values(cw, event, evsel, sample); + if (ret) + return -1; + + bt_ctf_stream_append_event(cw->stream, event); + bt_ctf_event_put(event); + return 0; +} + +static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, + struct bt_ctf_event_class *event_class) +{ + u64 type = evsel->attr.sample_type; + + /* + * missing: + * PERF_SAMPLE_TIME - not needed as we have it in + * ctf event header + * PERF_SAMPLE_READ - TODO + * PERF_SAMPLE_CALLCHAIN - TODO + * PERF_SAMPLE_RAW - tracepoint fields are handled separately + * PERF_SAMPLE_BRANCH_STACK - TODO + * PERF_SAMPLE_REGS_USER - TODO + * PERF_SAMPLE_STACK_USER - TODO + */ + +#define ADD_FIELD(cl, t, n) \ + do { \ + pr2(" field '%s'\n", n); \ + if (bt_ctf_event_class_add_field(cl, t, n)) { \ + pr_err("Failed to add field '%s;\n", n); \ + return -1; \ + } \ + } while (0) + + if (type & PERF_SAMPLE_IP) + ADD_FIELD(event_class, cw->data.u64_hex, "ip"); + + if (type & PERF_SAMPLE_TID) { + ADD_FIELD(event_class, cw->data.s32, "tid"); + ADD_FIELD(event_class, cw->data.s32, "pid"); + } + + if ((type & PERF_SAMPLE_ID) || + (type & PERF_SAMPLE_IDENTIFIER)) + ADD_FIELD(event_class, cw->data.u64, "id"); + + if (type & PERF_SAMPLE_STREAM_ID) + ADD_FIELD(event_class, cw->data.u64, "stream_id"); + + if (type & PERF_SAMPLE_CPU) + ADD_FIELD(event_class, cw->data.u32, "cpu"); + + if (type & PERF_SAMPLE_PERIOD) + ADD_FIELD(event_class, cw->data.u64, "period"); + + if (type & PERF_SAMPLE_WEIGHT) + ADD_FIELD(event_class, cw->data.u64, "weight"); + + if (type & PERF_SAMPLE_DATA_SRC) + ADD_FIELD(event_class, cw->data.u64, "data_src"); + + if (type & PERF_SAMPLE_TRANSACTION) + ADD_FIELD(event_class, cw->data.u64, "transaction"); + +#undef ADD_FIELD + return 0; +} + +static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) +{ + struct bt_ctf_event_class *event_class; + struct evsel_priv *priv; + const char *name = perf_evsel__name(evsel); + int ret; + + pr("Adding event '%s' (type %d)\n", name, evsel->attr.type); + + event_class = bt_ctf_event_class_create(name); + if (!event_class) + return -1; + + ret = add_generic_types(cw, evsel, event_class); + if (ret) + goto err; + + ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); + if (ret) { + pr("Failed to add event class into stream.\n"); + goto err; + } + + priv = malloc(sizeof(*priv)); + if (!priv) + goto err; + + priv->event_class = event_class; + evsel->priv = priv; + return 0; + +err: + bt_ctf_event_class_put(event_class); + pr_err("Failed to add event '%s'.\n", name); + return -1; +} + +static int setup_events(struct ctf_writer *cw, struct perf_session *session) +{ + struct perf_evlist *evlist = session->evlist; + struct perf_evsel *evsel; + int ret; + + evlist__for_each(evlist, evsel) { + ret = add_event(cw, evsel); + if (ret) + return ret; + } + return 0; +} + +static int ctf_writer__setup_env(struct ctf_writer *cw, + struct perf_session *session) +{ + struct perf_header *header = &session->header; + struct bt_ctf_writer *writer = cw->writer; + +#define ADD(__n, __v) \ +do { \ + if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \ + return -1; \ +} while (0) + + ADD("host", header->env.hostname); + ADD("sysname", "Linux"); + ADD("release", header->env.os_release); + ADD("version", header->env.version); + ADD("machine", header->env.arch); + ADD("domain", "kernel"); + ADD("tracer_name", "perf"); + +#undef ADD + return 0; +} + +static int ctf_writer__setup_clock(struct ctf_writer *cw) +{ + struct bt_ctf_clock *clock = cw->clock; + + bt_ctf_clock_set_description(clock, "perf clock"); + +#define SET(__n, __v) \ +do { \ + if (bt_ctf_clock_set_##__n(clock, __v)) \ + return -1; \ +} while (0) + + SET(frequency, 1000000000); + SET(offset_s, 0); + SET(offset, 0); + SET(precision, 10); + SET(is_absolute, 0); + +#undef SET + return 0; +} + +static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex) +{ + struct bt_ctf_field_type *type; + + type = bt_ctf_field_type_integer_create(size); + if (!type) + return NULL; + + if (sign && + bt_ctf_field_type_integer_set_signed(type, 1)) + goto err; + + if (hex && + bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL)) + goto err; + + pr2("Created type: INTEGER %d-bit %ssigned %s\n", + size, sign ? "un" : "", hex ? "hex" : ""); + return type; + +err: + bt_ctf_field_type_put(type); + return NULL; +} + +static void ctf_writer__cleanup_data(struct ctf_writer *cw) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(cw->data.array); i++) + bt_ctf_field_type_put(cw->data.array[i]); +} + +static int ctf_writer__init_data(struct ctf_writer *cw) +{ +#define CREATE_INT_TYPE(type, size, sign, hex) \ +do { \ + (type) = create_int_type(size, sign, hex); \ + if (!(type)) \ + goto err; \ +} while (0) + + CREATE_INT_TYPE(cw->data.s64, 64, true, false); + CREATE_INT_TYPE(cw->data.u64, 64, false, false); + CREATE_INT_TYPE(cw->data.s32, 32, true, false); + CREATE_INT_TYPE(cw->data.u32, 32, false, false); + CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); + + cw->data.string = bt_ctf_field_type_string_create(); + if (cw->data.string) + return 0; + +err: + ctf_writer__cleanup_data(cw); + pr_err("Failed to create data types.\n"); + return -1; +} + +static void ctf_writer__cleanup(struct ctf_writer *cw) +{ + ctf_writer__cleanup_data(cw); + + bt_ctf_clock_put(cw->clock); + bt_ctf_stream_put(cw->stream); + bt_ctf_stream_class_put(cw->stream_class); + bt_ctf_writer_put(cw->writer); + + /* and NULL all the pointers */ + memset(cw, 0, sizeof(*cw)); +} + +static int ctf_writer__init(struct ctf_writer *cw, const char *path) +{ + struct bt_ctf_writer *writer; + struct bt_ctf_stream_class *stream_class; + struct bt_ctf_stream *stream; + struct bt_ctf_clock *clock; + + /* CTF writer */ + writer = bt_ctf_writer_create(path); + if (!writer) + goto err; + + cw->writer = writer; + + /* CTF clock */ + clock = bt_ctf_clock_create("perf_clock"); + if (!clock) { + pr("Failed to create CTF clock.\n"); + goto err_cleanup; + } + + cw->clock = clock; + + if (ctf_writer__setup_clock(cw)) { + pr("Failed to setup CTF clock.\n"); + goto err_cleanup; + } + + /* CTF stream class */ + stream_class = bt_ctf_stream_class_create("perf_stream"); + if (!stream_class) { + pr("Failed to create CTF stream class.\n"); + goto err_cleanup; + } + + cw->stream_class = stream_class; + + /* CTF clock stream setup */ + if (bt_ctf_stream_class_set_clock(stream_class, clock)) { + pr("Failed to assign CTF clock to stream class.\n"); + goto err_cleanup; + } + + if (ctf_writer__init_data(cw)) + goto err_cleanup; + + /* CTF stream instance */ + stream = bt_ctf_writer_create_stream(writer, stream_class); + if (!stream) { + pr("Failed to create CTF stream.\n"); + goto err_cleanup; + } + + cw->stream = stream; + + /* CTF clock writer setup */ + if (bt_ctf_writer_add_clock(writer, clock)) { + pr("Failed to assign CTF clock to writer.\n"); + goto err_cleanup; + } + + return 0; + +err_cleanup: + ctf_writer__cleanup(cw); +err: + pr_err("Failed to setup CTF writer.\n"); + return -1; +} + +int bt_convert__perf2ctf(const char *input, const char *path) +{ + struct perf_session *session; + struct perf_data_file file = { + .path = input, + .mode = PERF_DATA_MODE_READ, + }; + struct convert c = { + .tool = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .mmap2 = perf_event__process_mmap2, + .comm = perf_event__process_comm, + .exit = perf_event__process_exit, + .fork = perf_event__process_fork, + .lost = perf_event__process_lost, + .tracing_data = perf_event__process_tracing_data, + .build_id = perf_event__process_build_id, + .ordered_events = true, + .ordering_requires_timestamps = true, + }, + }; + struct ctf_writer *cw = &c.writer; + int err = -1; + + /* CTF writer */ + if (ctf_writer__init(cw, path)) + return -1; + + /* perf.data session */ + session = perf_session__new(&file, 0, NULL); + if (!session) + goto free_writer; + + /* CTF writer env/clock setup */ + if (ctf_writer__setup_env(cw, session)) + goto free_session; + + /* CTF events setup */ + if (setup_events(cw, session)) + goto free_session; + + err = perf_session__process_events(session, &c.tool); + if (!err) + err = bt_ctf_stream_flush(cw->stream); + + fprintf(stderr, + "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", + file.path, path); + + fprintf(stderr, + "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n", + (double) c.events_size / 1024.0 / 1024.0, + c.events_count); + + /* its all good */ +free_session: + perf_session__delete(session); + +free_writer: + ctf_writer__cleanup(cw); + return err; +} diff --git a/tools/perf/util/data-convert-bt.h b/tools/perf/util/data-convert-bt.h new file mode 100644 index 000000000000..dda30c5d0792 --- /dev/null +++ b/tools/perf/util/data-convert-bt.h @@ -0,0 +1,8 @@ +#ifndef __DATA_CONVERT_BT_H +#define __DATA_CONVERT_BT_H +#ifdef HAVE_LIBBABELTRACE_SUPPORT + +int bt_convert__perf2ctf(const char *input_name, const char *to_ctf); + +#endif /* HAVE_LIBBABELTRACE_SUPPORT */ +#endif /* __DATA_CONVERT_BT_H */ diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index ad60b2f20258..2da5581ec74d 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -20,6 +20,7 @@ int verbose; bool dump_trace = false, quiet = false; int debug_ordered_events; static int redirect_to_stderr; +int debug_data_convert; static int _eprintf(int level, int var, const char *fmt, va_list args) { @@ -147,6 +148,7 @@ static struct debug_variable { { .name = "verbose", .ptr = &verbose }, { .name = "ordered-events", .ptr = &debug_ordered_events}, { .name = "stderr", .ptr = &redirect_to_stderr}, + { .name = "data-convert", .ptr = &debug_data_convert }, { .name = NULL, } }; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index be264d6f3b30..caac2fdc6105 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -12,6 +12,7 @@ extern int verbose; extern bool quiet, dump_trace; extern int debug_ordered_events; +extern int debug_data_convert; #ifndef pr_fmt #define pr_fmt(fmt) fmt From 54cf776a9c5c2e6a91de31954bba4d3bad6c657c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 20 Feb 2015 23:17:01 +0100 Subject: [PATCH 21/21] perf data: Add a 'perf' prefix to the generic fields Some of the tracers bring their own id or pid fields and we can end up having two of them. This patch adds a "perf_" prefix to the 'generic' fields so we avoid a clash of the member names. The change is visible in the babeltrace output: Before: $ babeltrace ./ctf-data/ [03:19:13.962131936] (+0.000001935) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 8 } [03:19:13.962133732] (+0.000001796) cycles: { }, { ip = 0xFFFFFFFF8105443A, tid = 20714, pid = 20714, period = 114 } ... Now: $ babeltrace ./ctf-data/ [03:19:13.962131936] (+0.000001935) cycles: { }, { perf_ip = 0xFFFFFFFF8105443A, perf_tid = 20714, perf_pid = 20714, perf_period = 8 } [03:19:13.962133732] (+0.000001796) cycles: { }, { perf_ip = 0xFFFFFFFF8105443A, perf_tid = 20714, perf_pid = 20714, perf_period = 114 } ... Signed-off-by: Sebastian Andrzej Siewior Acked-by: Namhyung Kim Reviewed-by: David Ahern Tested-by: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jeremie Galarneau Cc: Jiri Olsa Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Tom Zanussi Cc: Wang Nan Link: http://lkml.kernel.org/r/1424470628-5969-5-git-send-email-jolsa@kernel.org Signed-off-by: Jiri Olsa Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/data-convert-bt.c | 42 ++++++++++++++++--------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index ff4826c1745f..e372e03ff480 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -147,60 +147,62 @@ static int add_generic_values(struct ctf_writer *cw, */ if (type & PERF_SAMPLE_IP) { - ret = value_set_u64_hex(cw, event, "ip", sample->ip); + ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip); if (ret) return -1; } if (type & PERF_SAMPLE_TID) { - ret = value_set_s32(cw, event, "tid", sample->tid); + ret = value_set_s32(cw, event, "perf_tid", sample->tid); if (ret) return -1; - ret = value_set_s32(cw, event, "pid", sample->pid); + ret = value_set_s32(cw, event, "perf_pid", sample->pid); if (ret) return -1; } if ((type & PERF_SAMPLE_ID) || (type & PERF_SAMPLE_IDENTIFIER)) { - ret = value_set_u64(cw, event, "id", sample->id); + ret = value_set_u64(cw, event, "perf_id", sample->id); if (ret) return -1; } if (type & PERF_SAMPLE_STREAM_ID) { - ret = value_set_u64(cw, event, "stream_id", sample->stream_id); + ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id); if (ret) return -1; } if (type & PERF_SAMPLE_CPU) { - ret = value_set_u32(cw, event, "cpu", sample->cpu); + ret = value_set_u32(cw, event, "perf_cpu", sample->cpu); if (ret) return -1; } if (type & PERF_SAMPLE_PERIOD) { - ret = value_set_u64(cw, event, "period", sample->period); + ret = value_set_u64(cw, event, "perf_period", sample->period); if (ret) return -1; } if (type & PERF_SAMPLE_WEIGHT) { - ret = value_set_u64(cw, event, "weight", sample->weight); + ret = value_set_u64(cw, event, "perf_weight", sample->weight); if (ret) return -1; } if (type & PERF_SAMPLE_DATA_SRC) { - ret = value_set_u64(cw, event, "data_src", sample->data_src); + ret = value_set_u64(cw, event, "perf_data_src", + sample->data_src); if (ret) return -1; } if (type & PERF_SAMPLE_TRANSACTION) { - ret = value_set_u64(cw, event, "transaction", sample->transaction); + ret = value_set_u64(cw, event, "perf_transaction", + sample->transaction); if (ret) return -1; } @@ -276,34 +278,34 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, } while (0) if (type & PERF_SAMPLE_IP) - ADD_FIELD(event_class, cw->data.u64_hex, "ip"); + ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip"); if (type & PERF_SAMPLE_TID) { - ADD_FIELD(event_class, cw->data.s32, "tid"); - ADD_FIELD(event_class, cw->data.s32, "pid"); + ADD_FIELD(event_class, cw->data.s32, "perf_tid"); + ADD_FIELD(event_class, cw->data.s32, "perf_pid"); } if ((type & PERF_SAMPLE_ID) || (type & PERF_SAMPLE_IDENTIFIER)) - ADD_FIELD(event_class, cw->data.u64, "id"); + ADD_FIELD(event_class, cw->data.u64, "perf_id"); if (type & PERF_SAMPLE_STREAM_ID) - ADD_FIELD(event_class, cw->data.u64, "stream_id"); + ADD_FIELD(event_class, cw->data.u64, "perf_stream_id"); if (type & PERF_SAMPLE_CPU) - ADD_FIELD(event_class, cw->data.u32, "cpu"); + ADD_FIELD(event_class, cw->data.u32, "perf_cpu"); if (type & PERF_SAMPLE_PERIOD) - ADD_FIELD(event_class, cw->data.u64, "period"); + ADD_FIELD(event_class, cw->data.u64, "perf_period"); if (type & PERF_SAMPLE_WEIGHT) - ADD_FIELD(event_class, cw->data.u64, "weight"); + ADD_FIELD(event_class, cw->data.u64, "perf_weight"); if (type & PERF_SAMPLE_DATA_SRC) - ADD_FIELD(event_class, cw->data.u64, "data_src"); + ADD_FIELD(event_class, cw->data.u64, "perf_data_src"); if (type & PERF_SAMPLE_TRANSACTION) - ADD_FIELD(event_class, cw->data.u64, "transaction"); + ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); #undef ADD_FIELD return 0;