Pulling this part of the time-of-day series since the functionality is
independent.
David Ahern (3):
perf script: change process_event prototype
perf script: prepare to handle more than tracepoint events
perf script: dump software events and samples from hardware-based
profiling
tools/perf/Documentation/perf-script.txt | 19 +++
tools/perf/builtin-script.c | 118 ++++++++++++++-----
.../util/scripting-engines/trace-event-python.c | 20 +++-
tools/perf/util/session.c | 113 +++++++++++++++++++
tools/perf/util/session.h | 6 +
tools/perf/util/trace-event-parse.c | 4 +-
tools/perf/util/trace-event-scripting.c | 8 +-
tools/perf/util/trace-event.h | 10 +-
8 files changed, 253 insertions(+), 45 deletions(-)
--
1.7.4
Line format follows tracepoints precedent:
comm-pid [cpu] secs.usecs: event: IP symbol dso
Example:
perf record -v -ga -e cs -c 1 -- sleep 5
perf script
(Line lengths wrapped):
sshd-794 [000] 2572.863440: context-switches: ffffffff810355de \
perf_event_task_sched_out ([kernel.kallsyms])
sshd-794 [000] 2572.863440: context-switches: ffffffff81382b01 \
schedule ([kernel.kallsyms])
sshd-794 [000] 2572.863440: context-switches: ffffffff8138380a \
schedule_hrtimeout_range_clock ([kernel.kallsyms])
sshd-794 [000] 2572.863440: context-switches: ffffffff813838e6 \
schedule_hrtimeout_range ([kernel.kallsyms])
sshd-794 [000] 2572.863440: context-switches: ffffffff8110c55d \
poll_schedule_timeout ([kernel.kallsyms])
sshd-794 [000] 2572.863440: context-switches: ffffffff8110cd84 \
do_select ([kernel.kallsyms])
or 'perf script -G'
swapper-0 [001] 2572.863188: context-switches: ffffffff810355de ...
sshd-794 [000] 2572.863440: context-switches: ffffffff810355de ...
kworker/0:1-10 [000] 2572.863451: context-switches: ffffffff810355de ...
Signed-off-by: David Ahern <[email protected]>
---
tools/perf/Documentation/perf-script.txt | 19 +++++
tools/perf/builtin-script.c | 32 +++++++++
tools/perf/util/session.c | 113 ++++++++++++++++++++++++++++++
tools/perf/util/session.h | 6 ++
4 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 29ad942..99db652 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -112,6 +112,25 @@ OPTIONS
--debug-mode::
Do various checks like samples ordering and lost events.
+-k::
+--vmlinux=<file>::
+ vmlinux pathname
+
+--kallsyms=<file>::
+ kallsyms pathname
+
+--symfs=<directory>::
+ Look for files with symbols relative to this directory.
+
+-U::
+--show-unresolved::
+ Display all addresses including unresolved to a symbol.
+
+-G::
+--hide-call-graph::
+ Do not display call chain.
+
+--
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index f59d482..f1cad74b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -19,6 +19,8 @@ static bool debug_mode;
static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
+static bool show_unresolved;
+static bool no_callchain;
static void process_event(union perf_event *event,
struct perf_sample *sample,
@@ -57,6 +59,11 @@ static void process_event(union perf_event *event,
print_tracepoint_event(sample->cpu, sample->raw_data,
sample->raw_size, sample->time,
thread->comm);
+ } else if ((attr->type == PERF_TYPE_SOFTWARE) ||
+ ((attr->type == PERF_TYPE_HARDWARE) &&
+ (attr->config == PERF_COUNT_HW_CPU_CYCLES))) {
+ perf_session__print_sample(event, sample, session, attr,
+ show_unresolved);
} else {
evname = __event_name(attr->type, attr->config);
if (verbose)
@@ -130,7 +137,10 @@ static int process_sample_event(union perf_event *event,
static struct perf_event_ops event_ops = {
.sample = process_sample_event,
+ .mmap = perf_event__process_mmap,
.comm = perf_event__process_comm,
+ .exit = perf_event__process_task,
+ .fork = perf_event__process_task,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
@@ -620,6 +630,16 @@ static const struct option options[] = {
"input file name"),
OPT_BOOLEAN('d', "debug-mode", &debug_mode,
"do various checks like samples ordering and lost events"),
+ OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
+ "file", "vmlinux pathname"),
+ OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
+ "file", "kallsyms pathname"),
+ OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
+ "Do not display call chain"),
+ OPT_BOOLEAN('U', "show-unresolved", &show_unresolved,
+ "Display all entries including unresolved to a symbol"),
+ OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
+ "Look for files with symbols relative to this directory"),
OPT_END()
};
@@ -763,6 +783,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
exit(-1);
}
+ if (no_callchain)
+ symbol_conf.use_callchain = false;
+
+ else {
+ symbol_conf.use_callchain = true;
+ if (callchain_register_param(&callchain_param) < 0) {
+ error("Can't register callchain params\n");
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
if (rec_script_path)
script_path = rec_script_path;
if (rep_script_path)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index a3a871f..a6c3a56 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -10,6 +10,7 @@
#include "session.h"
#include "sort.h"
#include "util.h"
+#include "trace-event.h"
static int perf_session__open(struct perf_session *self, bool force)
{
@@ -1137,3 +1138,115 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
size_t ret = machine__fprintf_dsos_buildid(&self->host_machine, fp, with_hits);
return ret + machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
}
+
+static inline void print_one_symbol(const char *comm, pid_t pid,
+ u32 cpu, u64 secs, u64 usecs, const char *evname,
+ u64 addr, const char *symname, const char *dsoname)
+{
+ printf("%16s-%-5d ", comm, pid);
+
+ if (cpu != (u32) -1)
+ printf("[%03d]", cpu);
+
+ printf(" %5lu.%06lu: %s: ", secs, usecs, evname);
+
+ printf("%16" PRIx64 " %s (%s)\n",
+ addr, symname, dsoname);
+
+ return;
+}
+
+void perf_session__print_sample(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session,
+ struct perf_event_attr *attr,
+ bool show_unresolved)
+{
+ struct callchain_cursor_node *node, *prev;
+ struct addr_location al;
+ const char *evname = NULL;
+ const char *comm;
+ const char *symname, *dsoname;
+ u32 cpu = -1;
+ u64 secs = 0, usecs = 0;
+
+ if (perf_event__preprocess_sample(event, session, &al, sample,
+ NULL) < 0) {
+ error("problem processing %d event, skipping it.\n",
+ event->header.type);
+ return;
+ }
+
+ if (session->sample_type & PERF_SAMPLE_TIME) {
+ u64 nsecs = sample->time;
+ secs = nsecs / NSECS_PER_SEC;
+ nsecs -= secs * NSECS_PER_SEC;
+ usecs = nsecs / NSECS_PER_USEC;
+ }
+
+ evname = __event_name(attr->type, attr->config);
+ if (!evname)
+ evname = "(unknown)";
+
+ comm = al.thread->comm_set ? al.thread->comm : "-";
+
+ if (attr->sample_type & PERF_SAMPLE_CPU)
+ cpu = sample->cpu;
+
+ if (symbol_conf.use_callchain && sample->callchain) {
+
+ if (perf_session__resolve_callchain(session, al.thread,
+ sample->callchain, NULL) != 0) {
+ if (verbose)
+ error("Failed to resolve callchain. Skipping\n");
+ return;
+ }
+
+ node = session->callchain_cursor.first;
+ if (!node)
+ return;
+
+ while (node) {
+ if (node->sym && node->sym->name)
+ symname = node->sym->name;
+ else if (show_unresolved)
+ symname = "";
+ else
+ goto next;
+
+ if (node->map && node->map->dso && node->map->dso->name)
+ dsoname = node->map->dso->name;
+ else if (show_unresolved)
+ dsoname = "";
+ else
+ goto next;
+
+ print_one_symbol(comm, al.thread->pid, cpu, secs, usecs,
+ evname, node->ip, symname, dsoname);
+
+next:
+ prev = node;
+ node = node->next;
+ }
+ /* put a spacer between samples when callchains are dumped */
+ printf("\n");
+
+ } else {
+ if (al.sym && al.sym->name)
+ symname = al.sym->name;
+ else if (show_unresolved)
+ symname = "";
+ else
+ return;
+
+ if (al.map && al.map->dso && al.map->dso->name)
+ dsoname = al.map->dso->name;
+ else if (show_unresolved)
+ dsoname = "";
+ else
+ return;
+
+ print_one_symbol(comm, al.thread->pid, cpu, secs, usecs,
+ evname, al.addr, symname, dsoname);
+ }
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 977b3a1..3827048 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -165,4 +165,10 @@ static inline int perf_session__parse_sample(struct perf_session *session,
session->sample_id_all, sample);
}
+void perf_session__print_sample(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session,
+ struct perf_event_attr *attr,
+ bool show_unresolved);
+
#endif /* __PERF_SESSION_H */
--
1.7.4
Signed-off-by: David Ahern <[email protected]>
---
tools/perf/builtin-script.c | 74 +++++++++++++++++++++-------------
tools/perf/util/trace-event-parse.c | 4 +-
tools/perf/util/trace-event.h | 4 +-
3 files changed, 50 insertions(+), 32 deletions(-)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 0bee150..f59d482 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -24,21 +24,45 @@ static void process_event(union perf_event *event,
struct perf_sample *sample,
struct perf_session *session)
{
- struct thread *thread = perf_session__findnew(session, event->ip.pid);
-
- if (thread == NULL) {
- pr_debug("problem processing %d event, skipping it.\n",
- event->header.type);
- return;
+ struct perf_event_attr *attr;
+ struct thread *thread;
+ const char *evname = NULL;
+ static bool check_raw = true;
+
+ attr = perf_header__find_attr(sample->id, &session->header);
+ if (!attr) {
+ pr_debug("No attributes found for sample id %" PRId64 ". "
+ "skipping it.\n", sample->id);
}
- /*
- * FIXME: better resolve from pid from the struct trace_entry
- * field, although it should be the same than this perf
- * event pid
- */
- print_event(sample->cpu, sample->raw_data, sample->raw_size,
- sample->time, thread->comm);
+ if (attr->type == PERF_TYPE_TRACEPOINT) {
+ if (check_raw) {
+ if (!perf_session__has_traces(session, "record -R"))
+ return;
+ check_raw = false;
+ }
+
+ thread = perf_session__findnew(session, event->ip.pid);
+ if (thread == NULL) {
+ pr_debug("problem processing %d event, skipping it.\n",
+ event->header.type);
+ return;
+ }
+
+ /*
+ * FIXME: better resolve from pid from the struct trace_entry
+ * field, although it should be the same than this perf
+ * event pid
+ */
+ print_tracepoint_event(sample->cpu, sample->raw_data,
+ sample->raw_size, sample->time,
+ thread->comm);
+ } else {
+ evname = __event_name(attr->type, attr->config);
+ if (verbose)
+ warning("support for event %s not implemented. skipping\n",
+ evname ? evname : "(unknown)");
+ }
}
static int default_start_script(const char *script __unused,
@@ -88,19 +112,17 @@ static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
struct perf_session *session)
{
- if (session->sample_type & PERF_SAMPLE_RAW) {
- if (debug_mode) {
- if (sample->time < last_timestamp) {
- pr_err("Samples misordered, previous: %" PRIu64
- " this: %" PRIu64 "\n", last_timestamp,
- sample->time);
- nr_unordered++;
- }
- last_timestamp = sample->time;
- return 0;
+ if (debug_mode) {
+ if (sample->time < last_timestamp) {
+ pr_err("Samples misordered, previous: %" PRIu64
+ " this: %" PRIu64 "\n", last_timestamp,
+ sample->time);
+ nr_unordered++;
}
- scripting_ops->process_event(event, sample, session);
+ last_timestamp = sample->time;
+ return 0;
}
+ scripting_ops->process_event(event, sample, session);
session->hists.stats.total_period += sample->period;
return 0;
@@ -778,10 +800,6 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
if (session == NULL)
return -ENOMEM;
- if (strcmp(input_name, "-") &&
- !perf_session__has_traces(session, "record -R"))
- return -EINVAL;
-
if (generate_script_lang) {
struct stat perf_stat;
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index d8e622d..efe1628 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -2988,8 +2988,8 @@ pretty_print_func_graph(void *data, int size, struct event *event,
printf("\n");
}
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
- char *comm)
+void print_tracepoint_event(int cpu, void *data, int size,
+ unsigned long long nsecs, char *comm)
{
struct event *event;
unsigned long secs;
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 632b87b1..cafabf3 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -177,8 +177,8 @@ void print_printk(void);
int parse_ftrace_file(char *buf, unsigned long size);
int parse_event_file(char *buf, unsigned long size, char *sys);
-void print_event(int cpu, void *data, int size, unsigned long long nsecs,
- char *comm);
+void print_tracepoint_event(int cpu, void *data, int size,
+ unsigned long long nsecs, char *comm);
extern int file_bigendian;
extern int host_bigendian;
--
1.7.4
Prepare for handling of samples for any event type.
Signed-off-by: David Ahern <[email protected]>
---
tools/perf/builtin-script.c | 40 +++++++++++--------
.../util/scripting-engines/trace-event-python.c | 20 ++++++++-
tools/perf/util/trace-event-scripting.c | 8 +--
tools/perf/util/trace-event.h | 6 ++-
4 files changed, 47 insertions(+), 27 deletions(-)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 5f40df6..0bee150 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -20,6 +20,27 @@ static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
+static void process_event(union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session)
+{
+ struct thread *thread = perf_session__findnew(session, event->ip.pid);
+
+ if (thread == NULL) {
+ pr_debug("problem processing %d event, skipping it.\n",
+ event->header.type);
+ return;
+ }
+
+ /*
+ * FIXME: better resolve from pid from the struct trace_entry
+ * field, although it should be the same than this perf
+ * event pid
+ */
+ print_event(sample->cpu, sample->raw_data, sample->raw_size,
+ sample->time, thread->comm);
+}
+
static int default_start_script(const char *script __unused,
int argc __unused,
const char **argv __unused)
@@ -40,7 +61,7 @@ static int default_generate_script(const char *outfile __unused)
static struct scripting_ops default_scripting_ops = {
.start_script = default_start_script,
.stop_script = default_stop_script,
- .process_event = print_event,
+ .process_event = process_event,
.generate_script = default_generate_script,
};
@@ -67,14 +88,6 @@ static int process_sample_event(union perf_event *event,
struct perf_sample *sample,
struct perf_session *session)
{
- struct thread *thread = perf_session__findnew(session, event->ip.pid);
-
- if (thread == NULL) {
- pr_debug("problem processing %d event, skipping it.\n",
- event->header.type);
- return -1;
- }
-
if (session->sample_type & PERF_SAMPLE_RAW) {
if (debug_mode) {
if (sample->time < last_timestamp) {
@@ -86,14 +99,7 @@ static int process_sample_event(union perf_event *event,
last_timestamp = sample->time;
return 0;
}
- /*
- * FIXME: better resolve from pid from the struct trace_entry
- * field, although it should be the same than this perf
- * event pid
- */
- scripting_ops->process_event(sample->cpu, sample->raw_data,
- sample->raw_size,
- sample->time, thread->comm);
+ scripting_ops->process_event(event, sample, session);
}
session->hists.stats.total_period += sample->period;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 2040b85..5b03fb6 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -204,9 +204,9 @@ static inline struct event *find_cache_event(int type)
return event;
}
-static void python_process_event(int cpu, void *data,
- int size __unused,
- unsigned long long nsecs, char *comm)
+static void python_process_event(union perf_event *pevent,
+ struct perf_sample *sample,
+ struct perf_session *session)
{
PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
static char handler_name[256];
@@ -218,6 +218,20 @@ static void python_process_event(int cpu, void *data,
int type;
int pid;
+ int cpu = sample->cpu;
+ void *data = sample->raw_data;
+ unsigned long long nsecs = sample->time;
+ char *comm;
+ struct thread *thread;
+
+ thread = perf_session__findnew(session, pevent->ip.pid);
+ if (thread == NULL) {
+ pr_debug("problem processing %d event, skipping it.\n",
+ pevent->header.type);
+ return;
+ }
+ comm = thread->comm;
+
t = PyTuple_New(MAX_FIELDS);
if (!t)
Py_FatalError("couldn't create Python tuple");
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c
index f7af2fc..91f1b33 100644
--- a/tools/perf/util/trace-event-scripting.c
+++ b/tools/perf/util/trace-event-scripting.c
@@ -36,11 +36,9 @@ static int stop_script_unsupported(void)
return 0;
}
-static void process_event_unsupported(int cpu __unused,
- void *data __unused,
- int size __unused,
- unsigned long long nsecs __unused,
- char *comm __unused)
+static void process_event_unsupported(union perf_event *event __unused,
+ struct perf_sample *sample __unused,
+ struct perf_session *session __unused)
{
}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b5f12ca..632b87b1 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -3,6 +3,7 @@
#include <stdbool.h>
#include "parse-events.h"
+#include "session.h"
#define __unused __attribute__((unused))
@@ -278,8 +279,9 @@ struct scripting_ops {
const char *name;
int (*start_script) (const char *script, int argc, const char **argv);
int (*stop_script) (void);
- void (*process_event) (int cpu, void *data, int size,
- unsigned long long nsecs, char *comm);
+ void (*process_event) (union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_session *session);
int (*generate_script) (const char *outfile);
};
--
1.7.4
On Wed, Mar 02, 2011 at 10:29:18AM -0700, David Ahern wrote:
> Prepare for handling of samples for any event type.
>
> Signed-off-by: David Ahern <[email protected]>
> ---
> tools/perf/builtin-script.c | 40 +++++++++++--------
> .../util/scripting-engines/trace-event-python.c | 20 ++++++++-
What about Perl?
> tools/perf/util/trace-event-scripting.c | 8 +--
> tools/perf/util/trace-event.h | 6 ++-
> 4 files changed, 47 insertions(+), 27 deletions(-)
>
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index 5f40df6..0bee150 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -20,6 +20,27 @@ static u64 last_timestamp;
> static u64 nr_unordered;
> extern const struct option record_options[];
>
> +static void process_event(union perf_event *event,
> + struct perf_sample *sample,
> + struct perf_session *session)
> +{
> + struct thread *thread = perf_session__findnew(session, event->ip.pid);
> +
> + if (thread == NULL) {
> + pr_debug("problem processing %d event, skipping it.\n",
> + event->header.type);
> + return;
> + }
Seems the thread is needed by any endpoints. It would be better to resolve
it from process_sample_event and pass it to the process_event() handler.
> +
> + /*
> + * FIXME: better resolve from pid from the struct trace_entry
> + * field, although it should be the same than this perf
> + * event pid
> + */
> + print_event(sample->cpu, sample->raw_data, sample->raw_size,
> + sample->time, thread->comm);
> +}
[...]
> diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
> index 2040b85..5b03fb6 100644
> --- a/tools/perf/util/scripting-engines/trace-event-python.c
> +++ b/tools/perf/util/scripting-engines/trace-event-python.c
> @@ -204,9 +204,9 @@ static inline struct event *find_cache_event(int type)
> return event;
> }
>
> -static void python_process_event(int cpu, void *data,
> - int size __unused,
> - unsigned long long nsecs, char *comm)
> +static void python_process_event(union perf_event *pevent,
> + struct perf_sample *sample,
> + struct perf_session *session)
> {
> PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
> static char handler_name[256];
> @@ -218,6 +218,20 @@ static void python_process_event(int cpu, void *data,
> int type;
> int pid;
Please avoid such blank line in the middle of local vars declaration.
> + int cpu = sample->cpu;
> + void *data = sample->raw_data;
> + unsigned long long nsecs = sample->time;
> + char *comm;
> + struct thread *thread;
> +
> + thread = perf_session__findnew(session, pevent->ip.pid);
> + if (thread == NULL) {
> + pr_debug("problem processing %d event, skipping it.\n",
> + pevent->header.type);
> + return;
> + }
> + comm = thread->comm;
> +
On Wed, Mar 02, 2011 at 10:29:20AM -0700, David Ahern wrote:
> @@ -763,6 +783,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
> exit(-1);
> }
>
> + if (no_callchain)
> + symbol_conf.use_callchain = false;
> +
> + else {
> + symbol_conf.use_callchain = true;
> + if (callchain_register_param(&callchain_param) < 0) {
That call doesn't seem needed. Register callchain params is only useful
for later callchain sorting.
> + error("Can't register callchain params\n");
> + err = -EINVAL;
> + goto out;
> + }
> + }
> +
> if (rec_script_path)
> script_path = rec_script_path;
> if (rep_script_path)
[...]
> +void perf_session__print_sample(union perf_event *event,
> + struct perf_sample *sample,
> + struct perf_session *session,
> + struct perf_event_attr *attr,
> + bool show_unresolved)
> +{
> + struct callchain_cursor_node *node, *prev;
> + struct addr_location al;
> + const char *evname = NULL;
> + const char *comm;
> + const char *symname, *dsoname;
> + u32 cpu = -1;
> + u64 secs = 0, usecs = 0;
> +
> + if (perf_event__preprocess_sample(event, session, &al, sample,
> + NULL) < 0) {
> + error("problem processing %d event, skipping it.\n",
> + event->header.type);
> + return;
> + }
> +
> + if (session->sample_type & PERF_SAMPLE_TIME) {
> + u64 nsecs = sample->time;
> + secs = nsecs / NSECS_PER_SEC;
> + nsecs -= secs * NSECS_PER_SEC;
> + usecs = nsecs / NSECS_PER_USEC;
> + }
> +
> + evname = __event_name(attr->type, attr->config);
> + if (!evname)
> + evname = "(unknown)";
> +
> + comm = al.thread->comm_set ? al.thread->comm : "-";
> +
> + if (attr->sample_type & PERF_SAMPLE_CPU)
> + cpu = sample->cpu;
> +
> + if (symbol_conf.use_callchain && sample->callchain) {
> +
> + if (perf_session__resolve_callchain(session, al.thread,
> + sample->callchain, NULL) != 0) {
> + if (verbose)
> + error("Failed to resolve callchain. Skipping\n");
> + return;
> + }
> +
> + node = session->callchain_cursor.first;
> + if (!node)
> + return;
> +
> + while (node) {
> + if (node->sym && node->sym->name)
> + symname = node->sym->name;
> + else if (show_unresolved)
> + symname = "";
> + else
> + goto next;
> +
> + if (node->map && node->map->dso && node->map->dso->name)
> + dsoname = node->map->dso->name;
> + else if (show_unresolved)
> + dsoname = "";
> + else
> + goto next;
> +
> + print_one_symbol(comm, al.thread->pid, cpu, secs, usecs,
> + evname, node->ip, symname, dsoname);
> +
> +next:
> + prev = node;
> + node = node->next;
Hmm, that's a wrong way of walking through callchains. In fact it's not
a classical list. node->next can be a ghost entry from a previous callchain
that we kept cached in order to optimize allocations.
You need the accessors callchain_cursor_current() and callchain_cursor_advance().
On 03/02/2011 07:40 PM, Frederic Weisbecker wrote:
> On Wed, Mar 02, 2011 at 10:29:18AM -0700, David Ahern wrote:
>> Prepare for handling of samples for any event type.
>>
>> Signed-off-by: David Ahern <[email protected]>
>> ---
>> tools/perf/builtin-script.c | 40 +++++++++++--------
>> .../util/scripting-engines/trace-event-python.c | 20 ++++++++-
>
> What about Perl?
Oversight. Stumbled onto it yesterday afternoon. I have the perl module
installed now, so builds will get it too from now on.
>
>> tools/perf/util/trace-event-scripting.c | 8 +--
>> tools/perf/util/trace-event.h | 6 ++-
>> 4 files changed, 47 insertions(+), 27 deletions(-)
>>
>> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
>> index 5f40df6..0bee150 100644
>> --- a/tools/perf/builtin-script.c
>> +++ b/tools/perf/builtin-script.c
>> @@ -20,6 +20,27 @@ static u64 last_timestamp;
>> static u64 nr_unordered;
>> extern const struct option record_options[];
>>
>> +static void process_event(union perf_event *event,
>> + struct perf_sample *sample,
>> + struct perf_session *session)
>> +{
>> + struct thread *thread = perf_session__findnew(session, event->ip.pid);
>> +
>> + if (thread == NULL) {
>> + pr_debug("problem processing %d event, skipping it.\n",
>> + event->header.type);
>> + return;
>> + }
>
> Seems the thread is needed by any endpoints. It would be better to resolve
> it from process_sample_event and pass it to the process_event() handler.
tracepoints yes; S/W samples no. If you want it I'll add it.
>
>> +
>> + /*
>> + * FIXME: better resolve from pid from the struct trace_entry
>> + * field, although it should be the same than this perf
>> + * event pid
>> + */
>> + print_event(sample->cpu, sample->raw_data, sample->raw_size,
>> + sample->time, thread->comm);
>> +}
> [...]
>> diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
>> index 2040b85..5b03fb6 100644
>> --- a/tools/perf/util/scripting-engines/trace-event-python.c
>> +++ b/tools/perf/util/scripting-engines/trace-event-python.c
>> @@ -204,9 +204,9 @@ static inline struct event *find_cache_event(int type)
>> return event;
>> }
>>
>> -static void python_process_event(int cpu, void *data,
>> - int size __unused,
>> - unsigned long long nsecs, char *comm)
>> +static void python_process_event(union perf_event *pevent,
>> + struct perf_sample *sample,
>> + struct perf_session *session)
>> {
>> PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
>> static char handler_name[256];
>> @@ -218,6 +218,20 @@ static void python_process_event(int cpu, void *data,
>> int type;
>> int pid;
>
> Please avoid such blank line in the middle of local vars declaration.
ok.
David
>
>> + int cpu = sample->cpu;
>> + void *data = sample->raw_data;
>> + unsigned long long nsecs = sample->time;
>> + char *comm;
>> + struct thread *thread;
>> +
>> + thread = perf_session__findnew(session, pevent->ip.pid);
>> + if (thread == NULL) {
>> + pr_debug("problem processing %d event, skipping it.\n",
>> + pevent->header.type);
>> + return;
>> + }
>> + comm = thread->comm;
>> +
On 03/02/2011 08:05 PM, Frederic Weisbecker wrote:
> On Wed, Mar 02, 2011 at 10:29:20AM -0700, David Ahern wrote:
>> @@ -763,6 +783,18 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
>> exit(-1);
>> }
>>
>> + if (no_callchain)
>> + symbol_conf.use_callchain = false;
>> +
>> + else {
>> + symbol_conf.use_callchain = true;
>> + if (callchain_register_param(&callchain_param) < 0) {
>
> That call doesn't seem needed. Register callchain params is only useful
> for later callchain sorting.
ok. I see that now. I'll remove.
>
>> + error("Can't register callchain params\n");
>> + err = -EINVAL;
>> + goto out;
>> + }
>> + }
>> +
>> if (rec_script_path)
>> script_path = rec_script_path;
>> if (rep_script_path)
> [...]
>> +void perf_session__print_sample(union perf_event *event,
>> + struct perf_sample *sample,
>> + struct perf_session *session,
>> + struct perf_event_attr *attr,
>> + bool show_unresolved)
>> +{
>> + struct callchain_cursor_node *node, *prev;
>> + struct addr_location al;
>> + const char *evname = NULL;
>> + const char *comm;
>> + const char *symname, *dsoname;
>> + u32 cpu = -1;
>> + u64 secs = 0, usecs = 0;
>> +
>> + if (perf_event__preprocess_sample(event, session, &al, sample,
>> + NULL) < 0) {
>> + error("problem processing %d event, skipping it.\n",
>> + event->header.type);
>> + return;
>> + }
>> +
>> + if (session->sample_type & PERF_SAMPLE_TIME) {
>> + u64 nsecs = sample->time;
>> + secs = nsecs / NSECS_PER_SEC;
>> + nsecs -= secs * NSECS_PER_SEC;
>> + usecs = nsecs / NSECS_PER_USEC;
>> + }
>> +
>> + evname = __event_name(attr->type, attr->config);
>> + if (!evname)
>> + evname = "(unknown)";
>> +
>> + comm = al.thread->comm_set ? al.thread->comm : "-";
>> +
>> + if (attr->sample_type & PERF_SAMPLE_CPU)
>> + cpu = sample->cpu;
>> +
>> + if (symbol_conf.use_callchain && sample->callchain) {
>> +
>> + if (perf_session__resolve_callchain(session, al.thread,
>> + sample->callchain, NULL) != 0) {
>> + if (verbose)
>> + error("Failed to resolve callchain. Skipping\n");
>> + return;
>> + }
>> +
>> + node = session->callchain_cursor.first;
>> + if (!node)
>> + return;
>> +
>> + while (node) {
>> + if (node->sym && node->sym->name)
>> + symname = node->sym->name;
>> + else if (show_unresolved)
>> + symname = "";
>> + else
>> + goto next;
>> +
>> + if (node->map && node->map->dso && node->map->dso->name)
>> + dsoname = node->map->dso->name;
>> + else if (show_unresolved)
>> + dsoname = "";
>> + else
>> + goto next;
>> +
>> + print_one_symbol(comm, al.thread->pid, cpu, secs, usecs,
>> + evname, node->ip, symname, dsoname);
>> +
>> +next:
>> + prev = node;
>> + node = node->next;
>
> Hmm, that's a wrong way of walking through callchains. In fact it's not
> a classical list. node->next can be a ghost entry from a previous callchain
> that we kept cached in order to optimize allocations.
>
> You need the accessors callchain_cursor_current() and callchain_cursor_advance().
Ok. I'll look at perf-report's callchain_append again.
David
On Thu, Mar 03, 2011 at 07:11:38AM -0700, David Ahern wrote:
>
>
> On 03/02/2011 07:40 PM, Frederic Weisbecker wrote:
> > Seems the thread is needed by any endpoints. It would be better to resolve
> > it from process_sample_event and pass it to the process_event() handler.
>
> tracepoints yes; S/W samples no. If you want it I'll add it.
Hmm, yeah that looks more sensible, the majority of users seem to need it.
Thanks.
On Thu, Mar 03, 2011 at 07:20:10AM -0700, David Ahern wrote:
> On 03/02/2011 08:05 PM, Frederic Weisbecker wrote:
> > Hmm, that's a wrong way of walking through callchains. In fact it's not
> > a classical list. node->next can be a ghost entry from a previous callchain
> > that we kept cached in order to optimize allocations.
> >
> > You need the accessors callchain_cursor_current() and callchain_cursor_advance().
>
> Ok. I'll look at perf-report's callchain_append again.
Yeah callchain_append() is too much a generic name for something actually
rather specific. In fact callchain_append() adds a callchain, already
resolved, to a histogram in order to produce that statistical tree in the end
that you can have with perf report.
But you don't need those statistical tree of callchains, it's only used
by perf report for now. Instead you rather need to treat every callchains
individually and print each of them.
So you don't even need callchain_append(). All you need in the end is
to use perf_session__resolve_callchain() that resolves the raw struct ip_callchain
(only made of raw ips) into a cursor (list of ips resolved into symbols and so) and
walk through the cursor with the two accessors.
Ah I forgot, you first need to use callchain_cursor_commit() in order to initialize
the position in the cursor.
So:
1) Resolve with perf_session__resolve_callchain()
2) commit with callchain_cursor_commit()
3) iterate with callchain_cursor_current(), callchain_cursor_advance()
Thanks.
On 03/03/11 10:19, Frederic Weisbecker wrote:
> On Thu, Mar 03, 2011 at 07:20:10AM -0700, David Ahern wrote:
>> On 03/02/2011 08:05 PM, Frederic Weisbecker wrote:
>>> Hmm, that's a wrong way of walking through callchains. In fact it's not
>>> a classical list. node->next can be a ghost entry from a previous callchain
>>> that we kept cached in order to optimize allocations.
>>>
>>> You need the accessors callchain_cursor_current() and callchain_cursor_advance().
>>
>> Ok. I'll look at perf-report's callchain_append again.
>
> Yeah callchain_append() is too much a generic name for something actually
> rather specific. In fact callchain_append() adds a callchain, already
> resolved, to a histogram in order to produce that statistical tree in the end
> that you can have with perf report.
>
> But you don't need those statistical tree of callchains, it's only used
> by perf report for now. Instead you rather need to treat every callchains
> individually and print each of them.
>
> So you don't even need callchain_append(). All you need in the end is
Right, just using that as an example of how callchains are handled.
> to use perf_session__resolve_callchain() that resolves the raw struct ip_callchain
> (only made of raw ips) into a cursor (list of ips resolved into symbols and so) and
> walk through the cursor with the two accessors.
>
> Ah I forgot, you first need to use callchain_cursor_commit() in order to initialize
> the position in the cursor.
>
> So:
>
> 1) Resolve with perf_session__resolve_callchain()
> 2) commit with callchain_cursor_commit()
> 3) iterate with callchain_cursor_current(), callchain_cursor_advance()
yes, I figured out the missing commit, and I changed the loop to:
while (1) {
node = callchain_cursor_current(cursor);
if (!node)
break;
... (print chain)
callchain_cursor_advance(cursor);
}
Thanks for the comments.
What about the python and perl engines? Right now they are tracepoint
specific. I do not have a sufficient background in either to expand to
other sample types.
David
>
> Thanks.
On Thu, Mar 03, 2011 at 10:30:15AM -0700, David Ahern wrote:
> On 03/03/11 10:19, Frederic Weisbecker wrote:
> > to use perf_session__resolve_callchain() that resolves the raw struct ip_callchain
> > (only made of raw ips) into a cursor (list of ips resolved into symbols and so) and
> > walk through the cursor with the two accessors.
> >
> > Ah I forgot, you first need to use callchain_cursor_commit() in order to initialize
> > the position in the cursor.
> >
> > So:
> >
> > 1) Resolve with perf_session__resolve_callchain()
> > 2) commit with callchain_cursor_commit()
> > 3) iterate with callchain_cursor_current(), callchain_cursor_advance()
>
> yes, I figured out the missing commit, and I changed the loop to:
> while (1) {
> node = callchain_cursor_current(cursor);
> if (!node)
> break;
>
> ... (print chain)
>
> callchain_cursor_advance(cursor);
> }
Yep.
>
> Thanks for the comments.
>
> What about the python and perl engines? Right now they are tracepoint
> specific. I do not have a sufficient background in either to expand to
> other sample types.
Not a problem, the new parameters layout paves the way to make it later feasible
if someone is interested.