2010-01-27 02:27:57 -06:00
/*
* trace - event - python . Feed trace events to an embedded Python interpreter .
*
* Copyright ( C ) 2010 Tom Zanussi < tzanussi @ gmail . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <Python.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2014-10-23 13:45:14 +03:00
# include <stdbool.h>
2010-01-27 02:27:57 -06:00
# include <errno.h>
# include "../../perf.h"
2014-07-14 23:46:48 +02:00
# include "../debug.h"
2014-10-09 16:12:24 -03:00
# include "../callchain.h"
2012-08-07 09:58:03 -03:00
# include "../evsel.h"
2010-01-27 02:27:57 -06:00
# include "../util.h"
2011-11-28 07:56:39 -02:00
# include "../event.h"
# include "../thread.h"
2014-10-23 13:45:14 +03:00
# include "../comm.h"
# include "../machine.h"
# include "../db-export.h"
2010-01-27 02:27:57 -06:00
# include "../trace-event.h"
2014-07-10 13:50:51 +02:00
# include "../machine.h"
2010-01-27 02:27:57 -06:00
PyMODINIT_FUNC initperf_trace_context ( void ) ;
# define FTRACE_MAX_EVENT \
( ( 1 < < ( sizeof ( unsigned short ) * 8 ) ) - 1 )
2012-04-06 00:47:56 +02:00
struct event_format * events [ FTRACE_MAX_EVENT ] ;
2010-01-27 02:27:57 -06:00
# define MAX_FIELDS 64
# define N_COMMON_FIELDS 7
extern struct scripting_context * scripting_context ;
static char * cur_field_name ;
static int zero_flag_atom ;
static PyObject * main_module , * main_dict ;
2014-10-23 13:45:14 +03:00
struct tables {
struct db_export dbe ;
PyObject * evsel_handler ;
PyObject * machine_handler ;
PyObject * thread_handler ;
PyObject * comm_handler ;
PyObject * comm_thread_handler ;
PyObject * dso_handler ;
PyObject * symbol_handler ;
PyObject * sample_handler ;
bool db_export_mode ;
} ;
static struct tables tables_global ;
2014-07-09 16:16:31 +02:00
static void handler_call_die ( const char * handler_name ) NORETURN ;
2010-01-27 02:27:57 -06:00
static void handler_call_die ( const char * handler_name )
{
PyErr_Print ( ) ;
Py_FatalError ( " problem in Python trace event handler " ) ;
2014-07-09 16:16:31 +02:00
// Py_FatalError does not return
// but we have to make the compiler happy
abort ( ) ;
2010-01-27 02:27:57 -06:00
}
2013-10-24 10:10:51 -03:00
/*
* Insert val into into the dictionary and decrement the reference counter .
* This is necessary for dictionaries since PyDict_SetItemString ( ) does not
* steal a reference , as opposed to PyTuple_SetItem ( ) .
*/
static void pydict_set_item_string_decref ( PyObject * dict , const char * key , PyObject * val )
{
PyDict_SetItemString ( dict , key , val ) ;
Py_DECREF ( val ) ;
}
2014-07-31 09:01:01 +03:00
static PyObject * get_handler ( const char * handler_name )
{
PyObject * handler ;
handler = PyDict_GetItemString ( main_dict , handler_name ) ;
if ( handler & & ! PyCallable_Check ( handler ) )
return NULL ;
return handler ;
}
static void call_object ( PyObject * handler , PyObject * args , const char * die_msg )
{
PyObject * retval ;
retval = PyObject_CallObject ( handler , args ) ;
if ( retval = = NULL )
handler_call_die ( die_msg ) ;
Py_DECREF ( retval ) ;
}
static void try_call_object ( const char * handler_name , PyObject * args )
{
PyObject * handler ;
handler = get_handler ( handler_name ) ;
if ( handler )
call_object ( handler , args , handler_name ) ;
}
2010-01-27 02:27:57 -06:00
static void define_value ( enum print_arg_type field_type ,
const char * ev_name ,
const char * field_name ,
const char * field_value ,
const char * field_str )
{
const char * handler_name = " define_flag_value " ;
2014-07-31 09:01:01 +03:00
PyObject * t ;
2010-01-27 02:27:57 -06:00
unsigned long long value ;
unsigned n = 0 ;
if ( field_type = = PRINT_SYMBOL )
handler_name = " define_symbolic_value " ;
2010-02-22 01:12:59 -06:00
t = PyTuple_New ( 4 ) ;
2010-01-27 02:27:57 -06:00
if ( ! t )
Py_FatalError ( " couldn't create Python tuple " ) ;
value = eval_flag ( field_value ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( ev_name ) ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( field_name ) ) ;
PyTuple_SetItem ( t , n + + , PyInt_FromLong ( value ) ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( field_str ) ) ;
2014-07-31 09:01:01 +03:00
try_call_object ( handler_name , t ) ;
2010-01-27 02:27:57 -06:00
Py_DECREF ( t ) ;
}
static void define_values ( enum print_arg_type field_type ,
struct print_flag_sym * field ,
const char * ev_name ,
const char * field_name )
{
define_value ( field_type , ev_name , field_name , field - > value ,
field - > str ) ;
if ( field - > next )
define_values ( field_type , field - > next , ev_name , field_name ) ;
}
static void define_field ( enum print_arg_type field_type ,
const char * ev_name ,
const char * field_name ,
const char * delim )
{
const char * handler_name = " define_flag_field " ;
2014-07-31 09:01:01 +03:00
PyObject * t ;
2010-01-27 02:27:57 -06:00
unsigned n = 0 ;
if ( field_type = = PRINT_SYMBOL )
handler_name = " define_symbolic_field " ;
2010-02-22 01:12:59 -06:00
if ( field_type = = PRINT_FLAGS )
t = PyTuple_New ( 3 ) ;
else
t = PyTuple_New ( 2 ) ;
2010-01-27 02:27:57 -06:00
if ( ! t )
Py_FatalError ( " couldn't create Python tuple " ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( ev_name ) ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( field_name ) ) ;
if ( field_type = = PRINT_FLAGS )
PyTuple_SetItem ( t , n + + , PyString_FromString ( delim ) ) ;
2014-07-31 09:01:01 +03:00
try_call_object ( handler_name , t ) ;
2010-01-27 02:27:57 -06:00
Py_DECREF ( t ) ;
}
2012-04-06 00:47:56 +02:00
static void define_event_symbols ( struct event_format * event ,
2010-01-27 02:27:57 -06:00
const char * ev_name ,
struct print_arg * args )
{
switch ( args - > type ) {
case PRINT_NULL :
break ;
case PRINT_ATOM :
define_value ( PRINT_FLAGS , ev_name , cur_field_name , " 0 " ,
args - > atom . atom ) ;
zero_flag_atom = 0 ;
break ;
case PRINT_FIELD :
2013-12-26 15:54:57 -03:00
free ( cur_field_name ) ;
2010-01-27 02:27:57 -06:00
cur_field_name = strdup ( args - > field . name ) ;
break ;
case PRINT_FLAGS :
define_event_symbols ( event , ev_name , args - > flags . field ) ;
define_field ( PRINT_FLAGS , ev_name , cur_field_name ,
args - > flags . delim ) ;
define_values ( PRINT_FLAGS , args - > flags . flags , ev_name ,
cur_field_name ) ;
break ;
case PRINT_SYMBOL :
define_event_symbols ( event , ev_name , args - > symbol . field ) ;
define_field ( PRINT_SYMBOL , ev_name , cur_field_name , NULL ) ;
define_values ( PRINT_SYMBOL , args - > symbol . symbols , ev_name ,
cur_field_name ) ;
break ;
2012-06-27 09:41:41 +09:00
case PRINT_HEX :
define_event_symbols ( event , ev_name , args - > hex . field ) ;
define_event_symbols ( event , ev_name , args - > hex . size ) ;
break ;
2010-01-27 02:27:57 -06:00
case PRINT_STRING :
break ;
case PRINT_TYPE :
define_event_symbols ( event , ev_name , args - > typecast . item ) ;
break ;
case PRINT_OP :
if ( strcmp ( args - > op . op , " : " ) = = 0 )
zero_flag_atom = 1 ;
define_event_symbols ( event , ev_name , args - > op . left ) ;
define_event_symbols ( event , ev_name , args - > op . right ) ;
break ;
default :
2012-04-06 00:47:56 +02:00
/* gcc warns for these? */
case PRINT_BSTRING :
case PRINT_DYNAMIC_ARRAY :
case PRINT_FUNC :
2014-06-02 23:20:16 -04:00
case PRINT_BITMASK :
2010-01-27 02:27:57 -06:00
/* we should warn... */
return ;
}
if ( args - > next )
define_event_symbols ( event , ev_name , args - > next ) ;
}
2012-08-07 09:58:03 -03:00
static inline struct event_format * find_cache_event ( struct perf_evsel * evsel )
2010-01-27 02:27:57 -06:00
{
static char ev_name [ 256 ] ;
2012-04-06 00:47:56 +02:00
struct event_format * event ;
2012-08-07 09:58:03 -03:00
int type = evsel - > attr . config ;
2010-01-27 02:27:57 -06:00
2012-08-07 09:58:03 -03:00
/*
* XXX : Do we really need to cache this since now we have evsel - > tp_format
* cached already ? Need to re - read this " cache " routine that as well calls
* define_event_symbols ( ) : - \
*/
2010-01-27 02:27:57 -06:00
if ( events [ type ] )
return events [ type ] ;
2012-08-07 09:58:03 -03:00
events [ type ] = event = evsel - > tp_format ;
2010-01-27 02:27:57 -06:00
if ( ! event )
return NULL ;
sprintf ( ev_name , " %s__%s " , event - > system , event - > name ) ;
define_event_symbols ( event , ev_name , event - > print_fmt . args ) ;
return event ;
}
2014-05-27 18:14:33 +02:00
static PyObject * get_field_numeric_entry ( struct event_format * event ,
struct format_field * field , void * data )
{
2014-05-27 18:14:34 +02:00
bool is_array = field - > flags & FIELD_IS_ARRAY ;
PyObject * obj , * list = NULL ;
2014-05-27 18:14:33 +02:00
unsigned long long val ;
2014-05-27 18:14:34 +02:00
unsigned int item_size , n_items , i ;
2014-05-27 18:14:33 +02:00
2014-05-27 18:14:34 +02:00
if ( is_array ) {
list = PyList_New ( field - > arraylen ) ;
item_size = field - > size / field - > arraylen ;
n_items = field - > arraylen ;
2014-05-27 18:14:33 +02:00
} else {
2014-05-27 18:14:34 +02:00
item_size = field - > size ;
n_items = 1 ;
2014-05-27 18:14:33 +02:00
}
2014-05-27 18:14:34 +02:00
for ( i = 0 ; i < n_items ; i + + ) {
val = read_size ( event , data + field - > offset + i * item_size ,
item_size ) ;
if ( field - > flags & FIELD_IS_SIGNED ) {
if ( ( long long ) val > = LONG_MIN & &
( long long ) val < = LONG_MAX )
obj = PyInt_FromLong ( val ) ;
else
obj = PyLong_FromLongLong ( val ) ;
} else {
if ( val < = LONG_MAX )
obj = PyInt_FromLong ( val ) ;
else
obj = PyLong_FromUnsignedLongLong ( val ) ;
}
if ( is_array )
PyList_SET_ITEM ( list , i , obj ) ;
}
if ( is_array )
obj = list ;
2014-05-27 18:14:33 +02:00
return obj ;
}
2014-07-10 13:50:51 +02:00
static PyObject * python_process_callchain ( struct perf_sample * sample ,
struct perf_evsel * evsel ,
struct addr_location * al )
{
PyObject * pylist ;
pylist = PyList_New ( 0 ) ;
if ( ! pylist )
Py_FatalError ( " couldn't create Python list " ) ;
if ( ! symbol_conf . use_callchain | | ! sample - > callchain )
goto exit ;
2014-10-23 15:26:17 -03:00
if ( thread__resolve_callchain ( al - > thread , evsel ,
sample , NULL , NULL ,
PERF_MAX_STACK_DEPTH ) ! = 0 ) {
2014-07-10 13:50:51 +02:00
pr_err ( " Failed to resolve callchain. Skipping \n " ) ;
goto exit ;
}
callchain_cursor_commit ( & callchain_cursor ) ;
while ( 1 ) {
PyObject * pyelem ;
struct callchain_cursor_node * node ;
node = callchain_cursor_current ( & callchain_cursor ) ;
if ( ! node )
break ;
pyelem = PyDict_New ( ) ;
if ( ! pyelem )
Py_FatalError ( " couldn't create Python dictionary " ) ;
pydict_set_item_string_decref ( pyelem , " ip " ,
PyLong_FromUnsignedLongLong ( node - > ip ) ) ;
if ( node - > sym ) {
PyObject * pysym = PyDict_New ( ) ;
if ( ! pysym )
Py_FatalError ( " couldn't create Python dictionary " ) ;
pydict_set_item_string_decref ( pysym , " start " ,
PyLong_FromUnsignedLongLong ( node - > sym - > start ) ) ;
pydict_set_item_string_decref ( pysym , " end " ,
PyLong_FromUnsignedLongLong ( node - > sym - > end ) ) ;
pydict_set_item_string_decref ( pysym , " binding " ,
PyInt_FromLong ( node - > sym - > binding ) ) ;
pydict_set_item_string_decref ( pysym , " name " ,
PyString_FromStringAndSize ( node - > sym - > name ,
node - > sym - > namelen ) ) ;
pydict_set_item_string_decref ( pyelem , " sym " , pysym ) ;
}
if ( node - > map ) {
struct map * map = node - > map ;
const char * dsoname = " [unknown] " ;
if ( map & & map - > dso & & ( map - > dso - > name | | map - > dso - > long_name ) ) {
if ( symbol_conf . show_kernel_path & & map - > dso - > long_name )
dsoname = map - > dso - > long_name ;
else if ( map - > dso - > name )
dsoname = map - > dso - > name ;
}
pydict_set_item_string_decref ( pyelem , " dso " ,
PyString_FromString ( dsoname ) ) ;
}
callchain_cursor_advance ( & callchain_cursor ) ;
PyList_Append ( pylist , pyelem ) ;
Py_DECREF ( pyelem ) ;
}
exit :
return pylist ;
}
2013-12-19 16:34:52 -03:00
static void python_process_tracepoint ( struct perf_sample * sample ,
struct perf_evsel * evsel ,
struct thread * thread ,
struct addr_location * al )
2010-01-27 02:27:57 -06:00
{
2014-07-31 09:01:01 +03:00
PyObject * handler , * context , * t , * obj , * callchain ;
2014-07-10 13:50:51 +02:00
PyObject * dict = NULL ;
2010-01-27 02:27:57 -06:00
static char handler_name [ 256 ] ;
struct format_field * field ;
unsigned long s , ns ;
2012-04-06 00:47:56 +02:00
struct event_format * event ;
2010-01-27 02:27:57 -06:00
unsigned n = 0 ;
int pid ;
2011-03-09 22:23:23 -07:00
int cpu = sample - > cpu ;
void * data = sample - > raw_data ;
unsigned long long nsecs = sample - > time ;
2013-09-11 14:46:56 +02:00
const char * comm = thread__comm_str ( thread ) ;
2010-01-27 02:27:57 -06:00
t = PyTuple_New ( MAX_FIELDS ) ;
if ( ! t )
Py_FatalError ( " couldn't create Python tuple " ) ;
2012-08-07 09:58:03 -03:00
event = find_cache_event ( evsel ) ;
2010-01-27 02:27:57 -06:00
if ( ! event )
2012-08-07 09:58:03 -03:00
die ( " ug! no event found for type %d " , ( int ) evsel - > attr . config ) ;
2010-01-27 02:27:57 -06:00
2012-08-07 23:50:21 -03:00
pid = raw_field_value ( event , " common_pid " , data ) ;
2010-01-27 02:27:57 -06:00
sprintf ( handler_name , " %s__%s " , event - > system , event - > name ) ;
2014-07-31 09:01:01 +03:00
handler = get_handler ( handler_name ) ;
2010-05-31 23:12:09 +02:00
if ( ! handler ) {
dict = PyDict_New ( ) ;
if ( ! dict )
Py_FatalError ( " couldn't create Python dict " ) ;
}
2010-01-27 02:27:57 -06:00
s = nsecs / NSECS_PER_SEC ;
ns = nsecs - s * NSECS_PER_SEC ;
scripting_context - > event_data = data ;
2013-01-18 13:51:27 -06:00
scripting_context - > pevent = evsel - > tp_format - > pevent ;
2010-01-27 02:27:57 -06:00
context = PyCObject_FromVoidPtr ( scripting_context , NULL ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( handler_name ) ) ;
2011-01-24 11:13:04 -05:00
PyTuple_SetItem ( t , n + + , context ) ;
2010-01-27 02:27:57 -06:00
2014-07-10 13:50:51 +02:00
/* ip unwinding */
callchain = python_process_callchain ( sample , evsel , al ) ;
2010-05-31 23:12:09 +02:00
if ( handler ) {
PyTuple_SetItem ( t , n + + , PyInt_FromLong ( cpu ) ) ;
PyTuple_SetItem ( t , n + + , PyInt_FromLong ( s ) ) ;
PyTuple_SetItem ( t , n + + , PyInt_FromLong ( ns ) ) ;
PyTuple_SetItem ( t , n + + , PyInt_FromLong ( pid ) ) ;
PyTuple_SetItem ( t , n + + , PyString_FromString ( comm ) ) ;
2014-07-10 13:50:51 +02:00
PyTuple_SetItem ( t , n + + , callchain ) ;
2010-05-31 23:12:09 +02:00
} else {
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " common_cpu " , PyInt_FromLong ( cpu ) ) ;
pydict_set_item_string_decref ( dict , " common_s " , PyInt_FromLong ( s ) ) ;
pydict_set_item_string_decref ( dict , " common_ns " , PyInt_FromLong ( ns ) ) ;
pydict_set_item_string_decref ( dict , " common_pid " , PyInt_FromLong ( pid ) ) ;
pydict_set_item_string_decref ( dict , " common_comm " , PyString_FromString ( comm ) ) ;
2014-07-10 13:50:51 +02:00
pydict_set_item_string_decref ( dict , " common_callchain " , callchain ) ;
2010-05-31 23:12:09 +02:00
}
2010-01-27 02:27:57 -06:00
for ( field = event - > format . fields ; field ; field = field - > next ) {
if ( field - > flags & FIELD_IS_STRING ) {
int offset ;
if ( field - > flags & FIELD_IS_DYNAMIC ) {
offset = * ( int * ) ( data + field - > offset ) ;
offset & = 0xffff ;
} else
offset = field - > offset ;
2010-04-01 23:58:25 -05:00
obj = PyString_FromString ( ( char * ) data + offset ) ;
2010-01-27 02:27:57 -06:00
} else { /* FIELD_IS_NUMERIC */
2014-05-27 18:14:33 +02:00
obj = get_field_numeric_entry ( event , field , data ) ;
2010-01-27 02:27:57 -06:00
}
2010-05-31 23:12:09 +02:00
if ( handler )
PyTuple_SetItem ( t , n + + , obj ) ;
else
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , field - > name , obj ) ;
2010-05-31 23:12:09 +02:00
2010-01-27 02:27:57 -06:00
}
2014-07-10 13:50:51 +02:00
2010-05-31 23:12:09 +02:00
if ( ! handler )
PyTuple_SetItem ( t , n + + , dict ) ;
2010-01-27 02:27:57 -06:00
if ( _PyTuple_Resize ( & t , n ) = = - 1 )
Py_FatalError ( " error resizing Python tuple " ) ;
2010-05-31 23:12:09 +02:00
if ( handler ) {
2014-07-31 09:01:01 +03:00
call_object ( handler , t , handler_name ) ;
2010-01-27 02:27:57 -06:00
} else {
2014-07-31 09:01:01 +03:00
try_call_object ( " trace_unhandled " , t ) ;
2010-05-31 23:12:09 +02:00
Py_DECREF ( dict ) ;
2010-01-27 02:27:57 -06:00
}
Py_DECREF ( t ) ;
}
2014-10-23 13:45:14 +03:00
static PyObject * tuple_new ( unsigned int sz )
{
PyObject * t ;
t = PyTuple_New ( sz ) ;
if ( ! t )
Py_FatalError ( " couldn't create Python tuple " ) ;
return t ;
}
static int tuple_set_u64 ( PyObject * t , unsigned int pos , u64 val )
{
# if BITS_PER_LONG == 64
return PyTuple_SetItem ( t , pos , PyInt_FromLong ( val ) ) ;
# endif
# if BITS_PER_LONG == 32
return PyTuple_SetItem ( t , pos , PyLong_FromLongLong ( val ) ) ;
# endif
}
static int tuple_set_s32 ( PyObject * t , unsigned int pos , s32 val )
{
return PyTuple_SetItem ( t , pos , PyInt_FromLong ( val ) ) ;
}
static int tuple_set_string ( PyObject * t , unsigned int pos , const char * s )
{
return PyTuple_SetItem ( t , pos , PyString_FromString ( s ) ) ;
}
static int python_export_evsel ( struct db_export * dbe , struct perf_evsel * evsel )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 2 ) ;
tuple_set_u64 ( t , 0 , evsel - > db_id ) ;
tuple_set_string ( t , 1 , perf_evsel__name ( evsel ) ) ;
call_object ( tables - > evsel_handler , t , " evsel_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_machine ( struct db_export * dbe ,
struct machine * machine )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 3 ) ;
tuple_set_u64 ( t , 0 , machine - > db_id ) ;
tuple_set_s32 ( t , 1 , machine - > pid ) ;
tuple_set_string ( t , 2 , machine - > root_dir ? machine - > root_dir : " " ) ;
call_object ( tables - > machine_handler , t , " machine_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_thread ( struct db_export * dbe , struct thread * thread ,
u64 main_thread_db_id , struct machine * machine )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 5 ) ;
tuple_set_u64 ( t , 0 , thread - > db_id ) ;
tuple_set_u64 ( t , 1 , machine - > db_id ) ;
tuple_set_u64 ( t , 2 , main_thread_db_id ) ;
tuple_set_s32 ( t , 3 , thread - > pid_ ) ;
tuple_set_s32 ( t , 4 , thread - > tid ) ;
call_object ( tables - > thread_handler , t , " thread_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_comm ( struct db_export * dbe , struct comm * comm )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 2 ) ;
tuple_set_u64 ( t , 0 , comm - > db_id ) ;
tuple_set_string ( t , 1 , comm__str ( comm ) ) ;
call_object ( tables - > comm_handler , t , " comm_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_comm_thread ( struct db_export * dbe , u64 db_id ,
struct comm * comm , struct thread * thread )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 3 ) ;
tuple_set_u64 ( t , 0 , db_id ) ;
tuple_set_u64 ( t , 1 , comm - > db_id ) ;
tuple_set_u64 ( t , 2 , thread - > db_id ) ;
call_object ( tables - > comm_thread_handler , t , " comm_thread_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_dso ( struct db_export * dbe , struct dso * dso ,
struct machine * machine )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
char sbuild_id [ BUILD_ID_SIZE * 2 + 1 ] ;
PyObject * t ;
build_id__sprintf ( dso - > build_id , sizeof ( dso - > build_id ) , sbuild_id ) ;
t = tuple_new ( 5 ) ;
tuple_set_u64 ( t , 0 , dso - > db_id ) ;
tuple_set_u64 ( t , 1 , machine - > db_id ) ;
tuple_set_string ( t , 2 , dso - > short_name ) ;
tuple_set_string ( t , 3 , dso - > long_name ) ;
tuple_set_string ( t , 4 , sbuild_id ) ;
call_object ( tables - > dso_handler , t , " dso_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_symbol ( struct db_export * dbe , struct symbol * sym ,
struct dso * dso )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
u64 * sym_db_id = symbol__priv ( sym ) ;
PyObject * t ;
t = tuple_new ( 6 ) ;
tuple_set_u64 ( t , 0 , * sym_db_id ) ;
tuple_set_u64 ( t , 1 , dso - > db_id ) ;
tuple_set_u64 ( t , 2 , sym - > start ) ;
tuple_set_u64 ( t , 3 , sym - > end ) ;
tuple_set_s32 ( t , 4 , sym - > binding ) ;
tuple_set_string ( t , 5 , sym - > name ) ;
call_object ( tables - > symbol_handler , t , " symbol_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
static int python_export_sample ( struct db_export * dbe ,
struct export_sample * es )
{
struct tables * tables = container_of ( dbe , struct tables , dbe ) ;
PyObject * t ;
t = tuple_new ( 19 ) ;
tuple_set_u64 ( t , 0 , es - > db_id ) ;
tuple_set_u64 ( t , 1 , es - > evsel - > db_id ) ;
tuple_set_u64 ( t , 2 , es - > al - > machine - > db_id ) ;
tuple_set_u64 ( t , 3 , es - > thread - > db_id ) ;
tuple_set_u64 ( t , 4 , es - > comm_db_id ) ;
tuple_set_u64 ( t , 5 , es - > dso_db_id ) ;
tuple_set_u64 ( t , 6 , es - > sym_db_id ) ;
tuple_set_u64 ( t , 7 , es - > offset ) ;
tuple_set_u64 ( t , 8 , es - > sample - > ip ) ;
tuple_set_u64 ( t , 9 , es - > sample - > time ) ;
tuple_set_s32 ( t , 10 , es - > sample - > cpu ) ;
tuple_set_u64 ( t , 11 , es - > addr_dso_db_id ) ;
tuple_set_u64 ( t , 12 , es - > addr_sym_db_id ) ;
tuple_set_u64 ( t , 13 , es - > addr_offset ) ;
tuple_set_u64 ( t , 14 , es - > sample - > addr ) ;
tuple_set_u64 ( t , 15 , es - > sample - > period ) ;
tuple_set_u64 ( t , 16 , es - > sample - > weight ) ;
tuple_set_u64 ( t , 17 , es - > sample - > transaction ) ;
tuple_set_u64 ( t , 18 , es - > sample - > data_src ) ;
call_object ( tables - > sample_handler , t , " sample_table " ) ;
Py_DECREF ( t ) ;
return 0 ;
}
2013-12-19 16:34:52 -03:00
static void python_process_general_event ( struct perf_sample * sample ,
2012-08-08 17:57:51 +08:00
struct perf_evsel * evsel ,
2013-07-18 16:06:15 -06:00
struct thread * thread ,
2012-08-09 13:46:13 +08:00
struct addr_location * al )
2012-08-08 17:57:51 +08:00
{
2014-07-31 09:01:01 +03:00
PyObject * handler , * t , * dict , * callchain , * dict_sample ;
2012-08-08 17:57:51 +08:00
static char handler_name [ 64 ] ;
unsigned n = 0 ;
2012-08-08 17:57:53 +08:00
/*
* Use the MAX_FIELDS to make the function expandable , though
2012-08-09 13:46:13 +08:00
* currently there is only one item for the tuple .
2012-08-08 17:57:53 +08:00
*/
2012-08-08 17:57:51 +08:00
t = PyTuple_New ( MAX_FIELDS ) ;
if ( ! t )
Py_FatalError ( " couldn't create Python tuple " ) ;
2012-08-08 17:57:53 +08:00
dict = PyDict_New ( ) ;
if ( ! dict )
Py_FatalError ( " couldn't create Python dictionary " ) ;
2014-07-10 13:50:56 +02:00
dict_sample = PyDict_New ( ) ;
if ( ! dict_sample )
Py_FatalError ( " couldn't create Python dictionary " ) ;
2012-08-08 17:57:51 +08:00
snprintf ( handler_name , sizeof ( handler_name ) , " %s " , " process_event " ) ;
2014-07-31 09:01:01 +03:00
handler = get_handler ( handler_name ) ;
if ( ! handler )
2012-08-08 17:57:51 +08:00
goto exit ;
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " ev_name " , PyString_FromString ( perf_evsel__name ( evsel ) ) ) ;
pydict_set_item_string_decref ( dict , " attr " , PyString_FromStringAndSize (
2012-08-08 17:57:53 +08:00
( const char * ) & evsel - > attr , sizeof ( evsel - > attr ) ) ) ;
2014-07-10 13:50:56 +02:00
pydict_set_item_string_decref ( dict_sample , " pid " ,
PyInt_FromLong ( sample - > pid ) ) ;
pydict_set_item_string_decref ( dict_sample , " tid " ,
PyInt_FromLong ( sample - > tid ) ) ;
pydict_set_item_string_decref ( dict_sample , " cpu " ,
PyInt_FromLong ( sample - > cpu ) ) ;
pydict_set_item_string_decref ( dict_sample , " ip " ,
PyLong_FromUnsignedLongLong ( sample - > ip ) ) ;
pydict_set_item_string_decref ( dict_sample , " time " ,
PyLong_FromUnsignedLongLong ( sample - > time ) ) ;
pydict_set_item_string_decref ( dict_sample , " period " ,
PyLong_FromUnsignedLongLong ( sample - > period ) ) ;
pydict_set_item_string_decref ( dict , " sample " , dict_sample ) ;
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " raw_buf " , PyString_FromStringAndSize (
2012-08-08 17:57:53 +08:00
( const char * ) sample - > raw_data , sample - > raw_size ) ) ;
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " comm " ,
2013-09-11 14:46:56 +02:00
PyString_FromString ( thread__comm_str ( thread ) ) ) ;
2012-08-08 17:57:53 +08:00
if ( al - > map ) {
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " dso " ,
2012-08-08 17:57:53 +08:00
PyString_FromString ( al - > map - > dso - > name ) ) ;
}
if ( al - > sym ) {
2013-10-24 10:10:51 -03:00
pydict_set_item_string_decref ( dict , " symbol " ,
2012-08-08 17:57:53 +08:00
PyString_FromString ( al - > sym - > name ) ) ;
}
2012-08-08 17:57:51 +08:00
2014-07-10 13:50:51 +02:00
/* ip unwinding */
callchain = python_process_callchain ( sample , evsel , al ) ;
pydict_set_item_string_decref ( dict , " callchain " , callchain ) ;
2012-08-08 17:57:53 +08:00
PyTuple_SetItem ( t , n + + , dict ) ;
2012-08-08 17:57:51 +08:00
if ( _PyTuple_Resize ( & t , n ) = = - 1 )
Py_FatalError ( " error resizing Python tuple " ) ;
2014-07-31 09:01:01 +03:00
call_object ( handler , t , handler_name ) ;
2012-08-08 17:57:51 +08:00
exit :
2012-08-08 17:57:53 +08:00
Py_DECREF ( dict ) ;
2012-08-08 17:57:51 +08:00
Py_DECREF ( t ) ;
}
2014-10-23 13:45:14 +03:00
static void python_process_event ( union perf_event * event ,
2012-08-08 17:57:51 +08:00
struct perf_sample * sample ,
struct perf_evsel * evsel ,
2013-07-18 16:06:15 -06:00
struct thread * thread ,
2012-08-08 17:57:52 +08:00
struct addr_location * al )
2012-08-08 17:57:51 +08:00
{
2014-10-23 13:45:14 +03:00
struct tables * tables = & tables_global ;
2012-08-08 17:57:51 +08:00
switch ( evsel - > attr . type ) {
case PERF_TYPE_TRACEPOINT :
2013-12-19 16:34:52 -03:00
python_process_tracepoint ( sample , evsel , thread , al ) ;
2012-08-08 17:57:51 +08:00
break ;
/* Reserve for future process_hw/sw/raw APIs */
default :
2014-10-23 13:45:14 +03:00
if ( tables - > db_export_mode )
db_export__sample ( & tables - > dbe , event , sample , evsel ,
thread , al ) ;
else
python_process_general_event ( sample , evsel , thread , al ) ;
2012-08-08 17:57:51 +08:00
}
}
2010-01-27 02:27:57 -06:00
static int run_start_sub ( void )
{
main_module = PyImport_AddModule ( " __main__ " ) ;
if ( main_module = = NULL )
return - 1 ;
Py_INCREF ( main_module ) ;
main_dict = PyModule_GetDict ( main_module ) ;
2014-07-31 09:01:01 +03:00
if ( main_dict = = NULL )
2010-01-27 02:27:57 -06:00
goto error ;
Py_INCREF ( main_dict ) ;
2014-07-31 09:01:01 +03:00
try_call_object ( " trace_begin " , NULL ) ;
2010-01-27 02:27:57 -06:00
2014-07-31 09:01:01 +03:00
return 0 ;
2010-01-27 02:27:57 -06:00
error :
Py_XDECREF ( main_dict ) ;
Py_XDECREF ( main_module ) ;
2014-07-31 09:01:01 +03:00
return - 1 ;
2010-01-27 02:27:57 -06:00
}
2014-10-23 13:45:14 +03:00
# define SET_TABLE_HANDLER_(name, handler_name, table_name) do { \
tables - > handler_name = get_handler ( # table_name ) ; \
if ( tables - > handler_name ) \
tables - > dbe . export_ # # name = python_export_ # # name ; \
} while ( 0 )
# define SET_TABLE_HANDLER(name) \
SET_TABLE_HANDLER_ ( name , name # # _handler , name # # _table )
static void set_table_handlers ( struct tables * tables )
{
const char * perf_db_export_mode = " perf_db_export_mode " ;
PyObject * db_export_mode ;
int ret ;
memset ( tables , 0 , sizeof ( struct tables ) ) ;
if ( db_export__init ( & tables - > dbe ) )
Py_FatalError ( " failed to initialize export " ) ;
db_export_mode = PyDict_GetItemString ( main_dict , perf_db_export_mode ) ;
if ( ! db_export_mode )
return ;
ret = PyObject_IsTrue ( db_export_mode ) ;
if ( ret = = - 1 )
handler_call_die ( perf_db_export_mode ) ;
if ( ! ret )
return ;
tables - > db_export_mode = true ;
/*
* Reserve per symbol space for symbol - > db_id via symbol__priv ( )
*/
symbol_conf . priv_size = sizeof ( u64 ) ;
SET_TABLE_HANDLER ( evsel ) ;
SET_TABLE_HANDLER ( machine ) ;
SET_TABLE_HANDLER ( thread ) ;
SET_TABLE_HANDLER ( comm ) ;
SET_TABLE_HANDLER ( comm_thread ) ;
SET_TABLE_HANDLER ( dso ) ;
SET_TABLE_HANDLER ( symbol ) ;
SET_TABLE_HANDLER ( sample ) ;
}
2010-01-27 02:27:57 -06:00
/*
* Start trace script
*/
static int python_start_script ( const char * script , int argc , const char * * argv )
{
2014-10-23 13:45:14 +03:00
struct tables * tables = & tables_global ;
2010-01-27 02:27:57 -06:00
const char * * command_line ;
char buf [ PATH_MAX ] ;
int i , err = 0 ;
FILE * fp ;
command_line = malloc ( ( argc + 1 ) * sizeof ( const char * ) ) ;
command_line [ 0 ] = script ;
for ( i = 1 ; i < argc + 1 ; i + + )
command_line [ i ] = argv [ i - 1 ] ;
Py_Initialize ( ) ;
initperf_trace_context ( ) ;
PySys_SetArgv ( argc + 1 , ( char * * ) command_line ) ;
fp = fopen ( script , " r " ) ;
if ( ! fp ) {
sprintf ( buf , " Can't open python script \" %s \" " , script ) ;
perror ( buf ) ;
err = - 1 ;
goto error ;
}
err = PyRun_SimpleFile ( fp , script ) ;
if ( err ) {
fprintf ( stderr , " Error running python script %s \n " , script ) ;
goto error ;
}
err = run_start_sub ( ) ;
if ( err ) {
fprintf ( stderr , " Error starting python script %s \n " , script ) ;
goto error ;
}
free ( command_line ) ;
2014-10-23 13:45:14 +03:00
set_table_handlers ( tables ) ;
2010-01-27 02:27:57 -06:00
return err ;
error :
Py_Finalize ( ) ;
free ( command_line ) ;
return err ;
}
2014-08-15 22:08:37 +03:00
static int python_flush_script ( void )
{
return 0 ;
}
2010-01-27 02:27:57 -06:00
/*
* Stop trace script
*/
static int python_stop_script ( void )
{
2014-10-23 13:45:14 +03:00
struct tables * tables = & tables_global ;
2014-07-31 09:01:01 +03:00
try_call_object ( " trace_end " , NULL ) ;
2010-01-27 02:27:57 -06:00
2014-10-23 13:45:14 +03:00
db_export__exit ( & tables - > dbe ) ;
2010-01-27 02:27:57 -06:00
Py_XDECREF ( main_dict ) ;
Py_XDECREF ( main_module ) ;
Py_Finalize ( ) ;
2014-07-31 09:01:01 +03:00
return 0 ;
2010-01-27 02:27:57 -06:00
}
2012-06-27 13:08:42 -03:00
static int python_generate_script ( struct pevent * pevent , const char * outfile )
2010-01-27 02:27:57 -06:00
{
2012-04-06 00:47:56 +02:00
struct event_format * event = NULL ;
2010-01-27 02:27:57 -06:00
struct format_field * f ;
char fname [ PATH_MAX ] ;
int not_first , count ;
FILE * ofp ;
sprintf ( fname , " %s.py " , outfile ) ;
ofp = fopen ( fname , " w " ) ;
if ( ofp = = NULL ) {
fprintf ( stderr , " couldn't open %s \n " , fname ) ;
return - 1 ;
}
2010-11-16 18:45:39 +01:00
fprintf ( ofp , " # perf script event handlers, "
" generated by perf script -g python \n " ) ;
2010-01-27 02:27:57 -06:00
fprintf ( ofp , " # Licensed under the terms of the GNU GPL "
" License version 2 \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 format files. Those fields not available as "
" handler params can \n " ) ;
fprintf ( ofp , " # be retrieved using Python functions of the form "
" common_*(context). \n " ) ;
fprintf ( ofp , " # See the perf-trace-python Documentation for the list "
" of available functions. \n \n " ) ;
fprintf ( ofp , " import os \n " ) ;
fprintf ( ofp , " import sys \n \n " ) ;
fprintf ( ofp , " sys.path.append(os.environ['PERF_EXEC_PATH'] + \\ \n " ) ;
fprintf ( ofp , " \t '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') \n " ) ;
fprintf ( ofp , " \n from perf_trace_context import * \n " ) ;
fprintf ( ofp , " from Core import * \n \n \n " ) ;
fprintf ( ofp , " def trace_begin(): \n " ) ;
fprintf ( ofp , " \t print \" in trace_begin \" \n \n " ) ;
fprintf ( ofp , " def trace_end(): \n " ) ;
fprintf ( ofp , " \t print \" in trace_end \" \n \n " ) ;
2012-06-27 13:08:42 -03:00
while ( ( event = trace_find_next_event ( pevent , event ) ) ) {
2010-01-27 02:27:57 -06:00
fprintf ( ofp , " def %s__%s( " , event - > system , event - > name ) ;
fprintf ( ofp , " event_name, " ) ;
fprintf ( ofp , " context, " ) ;
fprintf ( ofp , " common_cpu, \n " ) ;
fprintf ( ofp , " \t common_secs, " ) ;
fprintf ( ofp , " common_nsecs, " ) ;
fprintf ( ofp , " common_pid, " ) ;
fprintf ( ofp , " common_comm, \n \t " ) ;
2014-07-10 13:50:51 +02:00
fprintf ( ofp , " common_callchain, " ) ;
2010-01-27 02:27:57 -06:00
not_first = 0 ;
count = 0 ;
for ( f = event - > format . fields ; f ; f = f - > next ) {
if ( not_first + + )
fprintf ( ofp , " , " ) ;
if ( + + count % 5 = = 0 )
fprintf ( ofp , " \n \t " ) ;
fprintf ( ofp , " %s " , f - > name ) ;
}
fprintf ( ofp , " ): \n " ) ;
fprintf ( ofp , " \t \t print_header(event_name, common_cpu, "
" common_secs, common_nsecs, \n \t \t \t "
" common_pid, common_comm) \n \n " ) ;
fprintf ( ofp , " \t \t print \" " ) ;
not_first = 0 ;
count = 0 ;
for ( f = event - > format . fields ; f ; f = f - > next ) {
if ( not_first + + )
fprintf ( ofp , " , " ) ;
if ( count & & count % 3 = = 0 ) {
fprintf ( ofp , " \" \\ \n \t \t \" " ) ;
}
count + + ;
fprintf ( ofp , " %s= " , f - > name ) ;
if ( f - > flags & FIELD_IS_STRING | |
f - > flags & FIELD_IS_FLAG | |
2014-05-29 13:44:55 +09:00
f - > flags & FIELD_IS_ARRAY | |
2010-01-27 02:27:57 -06:00
f - > flags & FIELD_IS_SYMBOLIC )
fprintf ( ofp , " %%s " ) ;
else if ( f - > flags & FIELD_IS_SIGNED )
fprintf ( ofp , " %%d " ) ;
else
fprintf ( ofp , " %%u " ) ;
}
2014-07-10 13:50:51 +02:00
fprintf ( ofp , " \" %% \\ \n \t \t ( " ) ;
2010-01-27 02:27:57 -06:00
not_first = 0 ;
count = 0 ;
for ( f = event - > format . fields ; f ; f = f - > next ) {
if ( not_first + + )
fprintf ( ofp , " , " ) ;
if ( + + count % 5 = = 0 )
fprintf ( ofp , " \n \t \t " ) ;
if ( f - > flags & FIELD_IS_FLAG ) {
if ( ( count - 1 ) % 5 ! = 0 ) {
fprintf ( ofp , " \n \t \t " ) ;
count = 4 ;
}
fprintf ( ofp , " flag_str( \" " ) ;
fprintf ( ofp , " %s__%s \" , " , event - > system ,
event - > name ) ;
fprintf ( ofp , " \" %s \" , %s) " , f - > name ,
f - > name ) ;
} else if ( f - > flags & FIELD_IS_SYMBOLIC ) {
if ( ( count - 1 ) % 5 ! = 0 ) {
fprintf ( ofp , " \n \t \t " ) ;
count = 4 ;
}
fprintf ( ofp , " symbol_str( \" " ) ;
fprintf ( ofp , " %s__%s \" , " , event - > system ,
event - > name ) ;
fprintf ( ofp , " \" %s \" , %s) " , f - > name ,
f - > name ) ;
} else
fprintf ( ofp , " %s " , f - > name ) ;
}
2014-07-10 13:50:51 +02:00
fprintf ( ofp , " ) \n \n " ) ;
fprintf ( ofp , " \t \t for node in common_callchain: " ) ;
fprintf ( ofp , " \n \t \t \t if 'sym' in node: " ) ;
fprintf ( ofp , " \n \t \t \t \t print \" \\ t[%%x] %%s \" %% (node['ip'], node['sym']['name']) " ) ;
fprintf ( ofp , " \n \t \t \t else: " ) ;
fprintf ( ofp , " \n \t \t \t \t print \" \t [%%x] \" %% (node['ip']) \n \n " ) ;
fprintf ( ofp , " \t \t print \" \\ n \" \n \n " ) ;
2010-01-27 02:27:57 -06:00
}
fprintf ( ofp , " def trace_unhandled(event_name, context, "
2010-05-31 23:12:09 +02:00
" event_fields_dict): \n " ) ;
2010-01-27 02:27:57 -06:00
2010-05-31 23:12:09 +02:00
fprintf ( ofp , " \t \t print ' '.join(['%%s=%%s'%%(k,str(v)) "
" for k,v in sorted(event_fields_dict.items())]) \n \n " ) ;
2010-01-27 02:27:57 -06:00
fprintf ( ofp , " def print_header( "
" event_name, cpu, secs, nsecs, pid, comm): \n "
" \t print \" %%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\ \n \t "
" (event_name, cpu, secs, nsecs, pid, comm), \n " ) ;
fclose ( ofp ) ;
fprintf ( stderr , " generated Python script: %s \n " , fname ) ;
return 0 ;
}
struct scripting_ops python_scripting_ops = {
. name = " Python " ,
. start_script = python_start_script ,
2014-08-15 22:08:37 +03:00
. flush_script = python_flush_script ,
2010-01-27 02:27:57 -06:00
. stop_script = python_stop_script ,
. process_event = python_process_event ,
. generate_script = python_generate_script ,
} ;