1209 lines · 30.5 KB · C
RawDownload
/* * 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>#include <stdbool.h>#include <errno.h>#include <linux/bitmap.h> #include "../../perf.h"#include "../debug.h"#include "../callchain.h"#include "../evsel.h"#include "../util.h"#include "../event.h"#include "../thread.h"#include "../comm.h"#include "../machine.h"#include "../db-export.h"#include "../thread-stack.h"#include "../trace-event.h"#include "../machine.h" PyMODINIT_FUNC initperf_trace_context(void); #define TRACE_EVENT_TYPE_MAX				\	((1 << (sizeof(unsigned short) * 8)) - 1) static DECLARE_BITMAP(events_defined, TRACE_EVENT_TYPE_MAX); #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; 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		*branch_type_handler;	PyObject		*sample_handler;	PyObject		*call_path_handler;	PyObject		*call_return_handler;	bool			db_export_mode;}; static struct tables tables_global; static void handler_call_die(const char *handler_name) NORETURN;static void handler_call_die(const char *handler_name){	PyErr_Print();	Py_FatalError("problem in Python trace event handler");	// Py_FatalError does not return	// but we have to make the compiler happy	abort();} /* * 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);} 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);} 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";	PyObject *t;	unsigned long long value;	unsigned n = 0; 	if (field_type == PRINT_SYMBOL)		handler_name = "define_symbolic_value"; 	t = PyTuple_New(4);	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)); 	try_call_object(handler_name, t); 	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";	PyObject *t;	unsigned n = 0; 	if (field_type == PRINT_SYMBOL)		handler_name = "define_symbolic_field"; 	if (field_type == PRINT_FLAGS)		t = PyTuple_New(3);	else		t = PyTuple_New(2);	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)); 	try_call_object(handler_name, t); 	Py_DECREF(t);} static void define_event_symbols(struct event_format *event,				 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:		free(cur_field_name);		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;	case PRINT_HEX:		define_event_symbols(event, ev_name, args->hex.field);		define_event_symbols(event, ev_name, args->hex.size);		break;	case PRINT_INT_ARRAY:		define_event_symbols(event, ev_name, args->int_array.field);		define_event_symbols(event, ev_name, args->int_array.count);		define_event_symbols(event, ev_name, args->int_array.el_size);		break;	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:		/* gcc warns for these? */	case PRINT_BSTRING:	case PRINT_DYNAMIC_ARRAY:	case PRINT_FUNC:	case PRINT_BITMASK:		/* we should warn... */		return;	} 	if (args->next)		define_event_symbols(event, ev_name, args->next);} static PyObject *get_field_numeric_entry(struct event_format *event,		struct format_field *field, void *data){	bool is_array = field->flags & FIELD_IS_ARRAY;	PyObject *obj, *list = NULL;	unsigned long long val;	unsigned int item_size, n_items, i; 	if (is_array) {		list = PyList_New(field->arraylen);		item_size = field->size / field->arraylen;		n_items = field->arraylen;	} else {		item_size = field->size;		n_items = 1;	} 	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;	return obj;}  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; 	if (thread__resolve_callchain(al->thread, evsel,				      sample, NULL, NULL,				      PERF_MAX_STACK_DEPTH) != 0) {		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;}  static void python_process_tracepoint(struct perf_sample *sample,				      struct perf_evsel *evsel,				      struct addr_location *al){	struct event_format *event = evsel->tp_format;	PyObject *handler, *context, *t, *obj, *callchain;	PyObject *dict = NULL;	static char handler_name[256];	struct format_field *field;	unsigned long s, ns;	unsigned n = 0;	int pid;	int cpu = sample->cpu;	void *data = sample->raw_data;	unsigned long long nsecs = sample->time;	const char *comm = thread__comm_str(al->thread); 	t = PyTuple_New(MAX_FIELDS);	if (!t)		Py_FatalError("couldn't create Python tuple"); 	if (!event)		die("ug! no event found for type %d", (int)evsel->attr.config); 	pid = raw_field_value(event, "common_pid", data); 	sprintf(handler_name, "%s__%s", event->system, event->name); 	if (!test_and_set_bit(event->id, events_defined))		define_event_symbols(event, handler_name, event->print_fmt.args); 	handler = get_handler(handler_name);	if (!handler) {		dict = PyDict_New();		if (!dict)			Py_FatalError("couldn't create Python dict");	}	s = nsecs / NSECS_PER_SEC;	ns = nsecs - s * NSECS_PER_SEC; 	scripting_context->event_data = data;	scripting_context->pevent = evsel->tp_format->pevent; 	context = PyCObject_FromVoidPtr(scripting_context, NULL); 	PyTuple_SetItem(t, n++, PyString_FromString(handler_name));	PyTuple_SetItem(t, n++, context); 	/* ip unwinding */	callchain = python_process_callchain(sample, evsel, al); 	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));		PyTuple_SetItem(t, n++, callchain);	} else {		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));		pydict_set_item_string_decref(dict, "common_callchain", callchain);	}	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;			obj = PyString_FromString((char *)data + offset);		} else { /* FIELD_IS_NUMERIC */			obj = get_field_numeric_entry(event, field, data);		}		if (handler)			PyTuple_SetItem(t, n++, obj);		else			pydict_set_item_string_decref(dict, field->name, obj); 	} 	if (!handler)		PyTuple_SetItem(t, n++, dict); 	if (_PyTuple_Resize(&t, n) == -1)		Py_FatalError("error resizing Python tuple"); 	if (handler) {		call_object(handler, t, handler_name);	} else {		try_call_object("trace_unhandled", t);		Py_DECREF(dict);	} 	Py_DECREF(t);} 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

Lines 1–500 of 1209.