lkml.org 
[lkml]   [2009]   [Oct]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC][PATCH 6/9] perf trace: Add scripting op for generating empty event handling scripts
Date
To give script writers an easy starting point for writing scripts,
scripting language support for a particular language can implement a
generate_event_handlers() scripting op that will output an empty (or
near-empty) set of handlers in the supported language for all the
events contained in a give perf.data trace file.

This patch adds the generate_event_handlers() scripting op and also
adds a Perl implementation that creates a ready-to-run Perl script
that can be passed to perf trace for generic event printing. Scripts
generated by this implementation print out all the fields for each
event (and will detect and generate the proper scripting code for
'flag' and 'symbolic' fields), and will additionally generate handlers
for the special 'trace_unhandled', 'trace_begin' and 'trace_end'
handlers. Script authors can simply remove the printing code to
implement their own custom event handling.

Signed-off-by: Tom Zanussi <tzanussi@gmail.com>
---
tools/perf/builtin-trace.c | 23 +++++++-
tools/perf/util/trace-event-perl.c | 114 ++++++++++++++++++++++++++++++++++++
tools/perf/util/trace-event.h | 1 +
3 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 74aec38..b151e77 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -30,6 +30,7 @@ static u64 sample_type;
static char const *script_name;

static int do_perl;
+static int generate_handlers;

static int default_start_script(const char *script __attribute((unused)))
{
@@ -41,10 +42,16 @@ static int default_stop_script(void)
return 0;
}

+static int default_generate_event_handlers(const char *outfile __attribute ((unused)))
+{
+ return 0;
+}
+
static struct trace_scripting_operations default_scripting_ops = {
.start_script = default_start_script,
.stop_script = default_stop_script,
.process_event = print_event,
+ .generate_event_handlers = default_generate_event_handlers,
};

static struct trace_scripting_operations *scripting_ops;
@@ -263,6 +270,8 @@ static const struct option options[] = {
"be more verbose (show symbol address, etc)"),
OPT_BOOLEAN('p', "perl", &do_perl,
"send output to a Perl script"),
+ OPT_BOOLEAN('g', "generate-event-handlers", &generate_handlers,
+ "generate empty event handlers for scripting languages"),
OPT_STRING('s', "script", &script_name, "file",
"script file name"),
OPT_END()
@@ -270,11 +279,14 @@ static const struct option options[] = {

static int setup_scripting(const char *script)
{
+ if (do_perl && generate_handlers)
+ goto setup;
+
if ((do_perl && !script) || (script && !do_perl))
usage_with_options(annotate_usage, options);

scripting_ops = &default_scripting_ops;
-
+setup:
if (do_perl) {
scripting_ops = setup_perl_scripting();
if (!scripting_ops)
@@ -312,9 +324,16 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
if (err)
goto out;

+ if (generate_handlers) {
+ trace_report();
+ err = scripting_ops->generate_event_handlers("perf-trace.pl");
+ goto out;
+ }
+
if (script_name) {
err = scripting_ops->start_script(script_name);
- goto out;
+ if (err)
+ goto out;
}

err = __cmd_trace();
diff --git a/tools/perf/util/trace-event-perl.c b/tools/perf/util/trace-event-perl.c
index 1264e14..657b87a 100644
--- a/tools/perf/util/trace-event-perl.c
+++ b/tools/perf/util/trace-event-perl.c
@@ -356,10 +356,124 @@ static int perl_stop_script(void)
return 0;
}

+static int perl_generate_event_handlers(const char *outfile)
+{
+ struct event *event = NULL;
+ struct format_field *f;
+ int not_first;
+ FILE *ofp;
+
+ ofp = fopen(outfile, "w");
+ if (ofp == NULL) {
+ fprintf(stderr, "couldn't open %s\n", outfile);
+ return -1;
+ }
+
+ fprintf(ofp, "# perf trace event handlers, "
+ "generated by perf trace -p -g\n\n");
+
+ fprintf(ofp, "# The common_* event handler fields are the most useful "
+ "fields common to\n");
+
+ fprintf(ofp, "# all events. They don't necessarily correspond to "
+ "the 'common_*' fields\n");
+
+ fprintf(ofp, "# in the status files. Those fields not available as "
+ "handler params can\n");
+
+ fprintf(ofp, "# be retrieved via script functions of the form "
+ "get_common_*().\n\n");
+
+ fprintf(ofp, "use lib \"$ENV{'PERF_EXEC_PATH'}/scripts/perl/"
+ "Perf-Trace-Util/lib\";\n");
+
+ fprintf(ofp, "use lib \"./Perf-Trace-Util/lib\";\n");
+ fprintf(ofp, "use Perf::Trace::Core;\n");
+ fprintf(ofp, "use Perf::Trace::Util;\n\n");
+
+ fprintf(ofp, "sub trace_begin\n{\n # optional\n}\n\n");
+ fprintf(ofp, "sub trace_end\n{\n # optional\n}\n\n");
+
+ while ((event = trace_find_next_event(event))) {
+ fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
+ fprintf(ofp, " my (");
+
+ fprintf(ofp, "$event_name, ");
+ fprintf(ofp, "$common_cpu, ");
+ fprintf(ofp, "$common_secs, ");
+ fprintf(ofp, "$common_nsecs, ");
+ fprintf(ofp, "$common_pid, ");
+ fprintf(ofp, "$common_comm,\n ");
+
+ not_first = 0;
+
+ for (f = event->format.fields; f; f = f->next) {
+ if (not_first++)
+ fprintf(ofp, ", ");
+
+ fprintf(ofp, "$%s", f->name);
+ }
+ fprintf(ofp, ") = @_;\n\n");
+
+ fprintf(ofp, " print_header($event_name, $common_cpu, "
+ "$common_secs, $common_nsecs, $common_pid, "
+ "$common_comm);\n\n");
+
+ fprintf(ofp, " printf(\"");
+
+ not_first = 0;
+
+ for (f = event->format.fields; f; f = f->next) {
+ if (not_first++)
+ fprintf(ofp, ", ");
+
+ fprintf(ofp, "%s=", f->name);
+ if (f->flags & FIELD_IS_STRING)
+ fprintf(ofp, "%%s");
+ else if (f->flags & FIELD_IS_SIGNED)
+ fprintf(ofp, "%%d");
+ else
+ fprintf(ofp, "%%u");
+ }
+
+ fprintf(ofp, "\\n\", ");
+
+ not_first = 0;
+
+ for (f = event->format.fields; f; f = f->next) {
+ if (not_first++)
+ fprintf(ofp, ", ");
+
+ fprintf(ofp, "$%s", f->name);
+ }
+
+ fprintf(ofp, ");\n");
+ fprintf(ofp, "}\n\n");
+ }
+
+ fprintf(ofp, "sub trace_unhandled\n{\n my ($event_name, "
+ "$common_cpu, $common_secs, $common_nsecs, $common_pid, "
+ "$common_comm) = @_;\n\n");
+
+ fprintf(ofp, " print_header($event_name, $common_cpu, "
+ "$common_secs, $common_nsecs, $common_pid, "
+ "$common_comm);\n}\n\n");
+
+ fprintf(ofp, "sub print_header\n{\n"
+ " my ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n"
+ " printf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \", "
+ "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}");
+
+ fclose(ofp);
+
+ return 0;
+}
+
struct trace_scripting_operations perl_scripting_ops = {
.start_script = perl_start_script,
.stop_script = perl_stop_script,
.process_event = perl_process_event,
+ .generate_event_handlers = perl_generate_event_handlers,
};

#ifdef NO_LIBPERL
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index f812a8e..582e0eb 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -255,6 +255,7 @@ struct trace_scripting_operations {
int (*stop_script) (void);
void (*process_event) (int cpu, void *data, int size,
unsigned long long nsecs, char *comm);
+ int (*generate_event_handlers) (const char *outfile);
};

extern struct trace_scripting_operations perl_scripting_ops;
--
1.6.4.GIT


\
 
 \ /
  Last update: 2009-10-06 08:19    [from the cache]
©2003-2011 Jasper Spaans. Advertise on this site