aha/tools/perf/util/trace-event.h
Tom Zanussi 956ffd027b perf trace: Add scripting ops
Adds an interface, scripting_ops, that when implemented for a
particular scripting language enables built-in support for trace
stream processing using that language.

The interface is designed to enable full-fledged language
interpreters to be embedded inside the perf executable and
thereby make the full capabilities of the supported languages
available for trace processing.

See below for details on the interface.

This patch also adds a couple command-line options to 'perf
trace':

The -s option option is used to specify the script to be run.
Script names that can be used with -s take the form:

[language spec:]scriptname[.ext]

Scripting languages register a set of 'language specs' that can
be used to specify scripts for the registered languages.  The
specs can be used either as prefixes or extensions.

If [language spec:] is used, the script is taken as a script of
the matching language regardless of any extension it might have.
 If [language spec:] is not used, [.ext] is used to look up the
language it corresponds to.  Language specs are case
insensitive.

e.g. Perl scripts can be specified in the following ways:

Perl:scriptname
pl:scriptname.py # extension ignored
PL:scriptname
scriptname.pl
scriptname.perl

The -g [language spec] option gives users an easy starting point
for writing scripts in the specified language.  Scripting
support for a particular language can implement a
generate_script() scripting op that outputs an empty (or
near-empty) set of handlers for all the events contained in a
given perf.data trace file - this option gives users a direct
way to access that.

Adding support for a scripting language
---------------------------------------

The main thing that needs to be done do add support for a new
language is to implement the scripting_ops interface:

It consists of the following four functions:

    start_script()
    stop_script()
    process_event()
    generate_script()

start_script() is called before any events are processed, and is
meant to give the scripting language support an opportunity to
set things up to receive events e.g. create and initialize an
instance of a language interpreter.

stop_script() is called after all events are processed, and is
meant to give the scripting language support an opportunity to
clean up e.g. destroy the interpreter instance, etc.

process_event() is called once for each event and takes as its
main parameter a pointer to the binary trace event record to be
processed. The implementation is responsible for picking out the
binary fields from the event record and sending them to the
script handler function associated with that event e.g. a
function derived from the event name it's meant to handle e.g.
'sched::sched_switch()'.  The 'format' information for trace
events can be used to parse the binary data and map it into a
form usable by a given scripting language; see the Perl
implemention in subsequent patches for one possible way to
leverage the existing trace format parsing code in perf and map
that info into specific scripting language types.

generate_script() should generate a ready-to-run script for the
current set of events in the trace, preferably with bodies that
print out every field for each event.  Again, look at the Perl
implementation for clues as to how that can be done.  This is an
optional, but very useful op.

Support for a given language should also add a language-specific
setup function and call it from setup_scripting().  The
language-specific setup function associates the the scripting
ops for that language with one or more 'language specifiers'
(see below) using script_spec_register().  When a script name is
specified on the command line, the scripting ops associated with
the specified language are used to instantiate and use the
appropriate interpreter to process the trace stream.

In general, it should be relatively easy to add support for a
new language, especially if the language implementation supports
an interface allowing an interpreter to be 'embedded' inside
another program (in this case the containing program will be
'perf trace'). If so, it should be relatively straightforward to
translate trace events into invocations of user-defined script
functions where e.g. the function name corresponds to the event
type and the function parameters correspond to the event fields.
 The event and field type information exported by the event
tracing infrastructure (via the event 'format' files) should be
enough to parse and send any piece of trace data to the user
script.  The easiest way to see how this can be done would be to
look at the Perl implementation contained in
perf/util/trace-event-perl.c/.h.

There are a couple of other things that aren't covered by the
scripting_ops or setup interface and are technically optional,
but should be implemented if possible.  One of these is support
for 'flag' and 'symbolic' fields e.g. being able to use more
human-readable values such as 'GFP_KERNEL' or
HI/BLOCK_IOPOLL/TASKLET in place of raw flag values.  See the
Perl implementation to see how this can be done. The other thing
is support for 'calling back' into the perf executable to access
e.g. uncommon fields not passed by default into handler
functions, or any metadata the implementation might want to make
available to users via the language interface.  Again, see the
Perl implementation for examples.

Signed-off-by: Tom Zanussi <tzanussi@gmail.com>
Cc: fweisbec@gmail.com
Cc: rostedt@goodmis.org
Cc: anton@samba.org
Cc: hch@infradead.org
LKML-Reference: <1259133352-23685-2-git-send-email-tzanussi@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
2009-11-28 10:04:24 +01:00

273 lines
5.4 KiB
C

#ifndef __PERF_TRACE_EVENTS_H
#define __PERF_TRACE_EVENTS_H
#include "parse-events.h"
#define __unused __attribute__((unused))
#ifndef PAGE_MASK
#define PAGE_MASK (page_size - 1)
#endif
enum {
RINGBUF_TYPE_PADDING = 29,
RINGBUF_TYPE_TIME_EXTEND = 30,
RINGBUF_TYPE_TIME_STAMP = 31,
};
#ifndef TS_SHIFT
#define TS_SHIFT 27
#endif
#define NSECS_PER_SEC 1000000000ULL
#define NSECS_PER_USEC 1000ULL
enum format_flags {
FIELD_IS_ARRAY = 1,
FIELD_IS_POINTER = 2,
FIELD_IS_SIGNED = 4,
FIELD_IS_STRING = 8,
FIELD_IS_DYNAMIC = 16,
};
struct format_field {
struct format_field *next;
char *type;
char *name;
int offset;
int size;
unsigned long flags;
};
struct format {
int nr_common;
int nr_fields;
struct format_field *common_fields;
struct format_field *fields;
};
struct print_arg_atom {
char *atom;
};
struct print_arg_string {
char *string;
int offset;
};
struct print_arg_field {
char *name;
struct format_field *field;
};
struct print_flag_sym {
struct print_flag_sym *next;
char *value;
char *str;
};
struct print_arg_typecast {
char *type;
struct print_arg *item;
};
struct print_arg_flags {
struct print_arg *field;
char *delim;
struct print_flag_sym *flags;
};
struct print_arg_symbol {
struct print_arg *field;
struct print_flag_sym *symbols;
};
struct print_arg;
struct print_arg_op {
char *op;
int prio;
struct print_arg *left;
struct print_arg *right;
};
struct print_arg_func {
char *name;
struct print_arg *args;
};
enum print_arg_type {
PRINT_NULL,
PRINT_ATOM,
PRINT_FIELD,
PRINT_FLAGS,
PRINT_SYMBOL,
PRINT_TYPE,
PRINT_STRING,
PRINT_OP,
};
struct print_arg {
struct print_arg *next;
enum print_arg_type type;
union {
struct print_arg_atom atom;
struct print_arg_field field;
struct print_arg_typecast typecast;
struct print_arg_flags flags;
struct print_arg_symbol symbol;
struct print_arg_func func;
struct print_arg_string string;
struct print_arg_op op;
};
};
struct print_fmt {
char *format;
struct print_arg *args;
};
struct event {
struct event *next;
char *name;
int id;
int flags;
struct format format;
struct print_fmt print_fmt;
char *system;
};
enum {
EVENT_FL_ISFTRACE = 0x01,
EVENT_FL_ISPRINT = 0x02,
EVENT_FL_ISBPRINT = 0x04,
EVENT_FL_ISFUNC = 0x08,
EVENT_FL_ISFUNCENT = 0x10,
EVENT_FL_ISFUNCRET = 0x20,
EVENT_FL_FAILED = 0x80000000
};
struct record {
unsigned long long ts;
int size;
void *data;
};
struct record *trace_peek_data(int cpu);
struct record *trace_read_data(int cpu);
void parse_set_info(int nr_cpus, int long_sz);
void trace_report(int fd);
void *malloc_or_die(unsigned int size);
void parse_cmdlines(char *file, int size);
void parse_proc_kallsyms(char *file, unsigned int size);
void parse_ftrace_printk(char *file, unsigned int size);
void print_funcs(void);
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);
extern int file_bigendian;
extern int host_bigendian;
int bigendian(void);
static inline unsigned short __data2host2(unsigned short data)
{
unsigned short swap;
if (host_bigendian == file_bigendian)
return data;
swap = ((data & 0xffULL) << 8) |
((data & (0xffULL << 8)) >> 8);
return swap;
}
static inline unsigned int __data2host4(unsigned int data)
{
unsigned int swap;
if (host_bigendian == file_bigendian)
return data;
swap = ((data & 0xffULL) << 24) |
((data & (0xffULL << 8)) << 8) |
((data & (0xffULL << 16)) >> 8) |
((data & (0xffULL << 24)) >> 24);
return swap;
}
static inline unsigned long long __data2host8(unsigned long long data)
{
unsigned long long swap;
if (host_bigendian == file_bigendian)
return data;
swap = ((data & 0xffULL) << 56) |
((data & (0xffULL << 8)) << 40) |
((data & (0xffULL << 16)) << 24) |
((data & (0xffULL << 24)) << 8) |
((data & (0xffULL << 32)) >> 8) |
((data & (0xffULL << 40)) >> 24) |
((data & (0xffULL << 48)) >> 40) |
((data & (0xffULL << 56)) >> 56);
return swap;
}
#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
extern int header_page_ts_offset;
extern int header_page_ts_size;
extern int header_page_size_offset;
extern int header_page_size_size;
extern int header_page_data_offset;
extern int header_page_data_size;
extern int latency_format;
int parse_header_page(char *buf, unsigned long size);
int trace_parse_common_type(void *data);
struct event *trace_find_event(int id);
unsigned long long
raw_field_value(struct event *event, const char *name, void *data);
void *raw_field_ptr(struct event *event, const char *name, void *data);
int read_tracing_data(int fd, struct perf_event_attr *pattrs, int nb_events);
/* taken from kernel/trace/trace.h */
enum trace_flag_type {
TRACE_FLAG_IRQS_OFF = 0x01,
TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
TRACE_FLAG_NEED_RESCHED = 0x04,
TRACE_FLAG_HARDIRQ = 0x08,
TRACE_FLAG_SOFTIRQ = 0x10,
};
struct scripting_ops {
const char *name;
int (*start_script) (const char *);
int (*stop_script) (void);
void (*process_event) (int cpu, void *data, int size,
unsigned long long nsecs, char *comm);
int (*generate_script) (const char *outfile);
};
int script_spec_register(const char *spec, struct scripting_ops *ops);
#endif /* __PERF_TRACE_EVENTS_H */