2224 lines · 58.8 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 <inttypes.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <errno.h>#include <linux/bitmap.h>#include <linux/compiler.h>#include <linux/time64.h>#ifdef HAVE_LIBTRACEEVENT#include <event-parse.h>#endif #include "../build-id.h"#include "../counts.h"#include "../debug.h"#include "../dso.h"#include "../callchain.h"#include "../env.h"#include "../evsel.h"#include "../event.h"#include "../thread.h"#include "../comm.h"#include "../machine.h"#include "../mem-info.h"#include "../db-export.h"#include "../thread-stack.h"#include "../trace-event.h"#include "../call-path.h"#include "dwarf-regs.h"#include "map.h"#include "symbol.h"#include "thread_map.h"#include "print_binary.h"#include "stat.h"#include "mem-events.h"#include "util/perf_regs.h" #define _PyUnicode_FromString(arg) \  PyUnicode_FromString(arg)#define _PyUnicode_FromStringAndSize(arg1, arg2) \  PyUnicode_FromStringAndSize((arg1), (arg2))#define _PyBytes_FromStringAndSize(arg1, arg2) \  PyBytes_FromStringAndSize((arg1), (arg2))#define _PyLong_FromLong(arg) \  PyLong_FromLong(arg)#define _PyLong_AsLong(arg) \  PyLong_AsLong(arg)#define _PyCapsule_New(arg1, arg2, arg3) \  PyCapsule_New((arg1), (arg2), (arg3)) PyMODINIT_FUNC PyInit_perf_trace_context(void); #ifdef HAVE_LIBTRACEEVENT#define TRACE_EVENT_TYPE_MAX				\	((1 << (sizeof(unsigned short) * 8)) - 1) #define N_COMMON_FIELDS	7 static char *cur_field_name;static int zero_flag_atom;#endif #define MAX_FIELDS	64 extern struct scripting_context *scripting_context; 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;	PyObject		*synth_handler;	PyObject		*context_switch_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 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);} #ifdef HAVE_LIBTRACEEVENTstatic int get_argument_count(PyObject *handler){	int arg_count = 0; 	PyObject *code_obj = code_obj = PyObject_GetAttrString(handler, "__code__");	PyErr_Clear();	if (code_obj) {		PyObject *arg_count_obj = PyObject_GetAttrString(code_obj,			"co_argcount");		if (arg_count_obj) {			arg_count = (int) _PyLong_AsLong(arg_count_obj);			Py_DECREF(arg_count_obj);		}		Py_DECREF(code_obj);	}	return arg_count;} static void define_value(enum tep_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 == TEP_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++, _PyUnicode_FromString(ev_name));	PyTuple_SetItem(t, n++, _PyUnicode_FromString(field_name));	PyTuple_SetItem(t, n++, _PyLong_FromLong(value));	PyTuple_SetItem(t, n++, _PyUnicode_FromString(field_str)); 	try_call_object(handler_name, t); 	Py_DECREF(t);} static void define_values(enum tep_print_arg_type field_type,			  struct tep_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 tep_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 == TEP_PRINT_SYMBOL)		handler_name = "define_symbolic_field"; 	if (field_type == TEP_PRINT_FLAGS)		t = PyTuple_New(3);	else		t = PyTuple_New(2);	if (!t)		Py_FatalError("couldn't create Python tuple"); 	PyTuple_SetItem(t, n++, _PyUnicode_FromString(ev_name));	PyTuple_SetItem(t, n++, _PyUnicode_FromString(field_name));	if (field_type == TEP_PRINT_FLAGS)		PyTuple_SetItem(t, n++, _PyUnicode_FromString(delim)); 	try_call_object(handler_name, t); 	Py_DECREF(t);} static void define_event_symbols(struct tep_event *event,				 const char *ev_name,				 struct tep_print_arg *args){	if (args == NULL)		return; 	switch (args->type) {	case TEP_PRINT_NULL:		break;	case TEP_PRINT_ATOM:		define_value(TEP_PRINT_FLAGS, ev_name, cur_field_name, "0",			     args->atom.atom);		zero_flag_atom = 0;		break;	case TEP_PRINT_FIELD:		free(cur_field_name);		cur_field_name = strdup(args->field.name);		break;	case TEP_PRINT_FLAGS:		define_event_symbols(event, ev_name, args->flags.field);		define_field(TEP_PRINT_FLAGS, ev_name, cur_field_name,			     args->flags.delim);		define_values(TEP_PRINT_FLAGS, args->flags.flags, ev_name,			      cur_field_name);		break;	case TEP_PRINT_SYMBOL:		define_event_symbols(event, ev_name, args->symbol.field);		define_field(TEP_PRINT_SYMBOL, ev_name, cur_field_name, NULL);		define_values(TEP_PRINT_SYMBOL, args->symbol.symbols, ev_name,			      cur_field_name);		break;	case TEP_PRINT_HEX:	case TEP_PRINT_HEX_STR:		define_event_symbols(event, ev_name, args->hex.field);		define_event_symbols(event, ev_name, args->hex.size);		break;	case TEP_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 TEP_PRINT_STRING:		break;	case TEP_PRINT_TYPE:		define_event_symbols(event, ev_name, args->typecast.item);		break;	case TEP_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 TEP_PRINT_BSTRING:	case TEP_PRINT_DYNAMIC_ARRAY:	case TEP_PRINT_DYNAMIC_ARRAY_LEN:	case TEP_PRINT_FUNC:	case TEP_PRINT_BITMASK:		/* we should warn... */		return;	} 	if (args->next)		define_event_symbols(event, ev_name, args->next);} static PyObject *get_field_numeric_entry(struct tep_event *event,		struct tep_format_field *field, void *data){	bool is_array = field->flags & TEP_FIELD_IS_ARRAY;	PyObject *obj = NULL, *list = NULL;	unsigned long long val;	unsigned int item_size, n_items, i; 	if (is_array) {		list = PyList_New(field->arraylen);		if (!list)			Py_FatalError("couldn't create Python list");		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 & TEP_FIELD_IS_SIGNED) {			if ((long long)val >= LONG_MIN &&					(long long)val <= LONG_MAX)				obj = _PyLong_FromLong(val);			else				obj = PyLong_FromLongLong(val);		} else {			if (val <= LONG_MAX)				obj = _PyLong_FromLong(val);			else				obj = PyLong_FromUnsignedLongLong(val);		}		if (is_array)			PyList_SET_ITEM(list, i, obj);	}	if (is_array)		obj = list;	return obj;}#endif static const char *get_dsoname(struct map *map){	const char *dsoname = "[unknown]";	struct dso *dso = map ? map__dso(map) : NULL; 	if (dso) {		if (symbol_conf.show_kernel_path && dso__long_name(dso))			dsoname = dso__long_name(dso);		else			dsoname = dso__name(dso);	} 	return dsoname;} static unsigned long get_offset(struct symbol *sym, struct addr_location *al){	unsigned long offset; 	if (al->addr < sym->end)		offset = al->addr - sym->start;	else		offset = al->addr - map__start(al->map) - sym->start; 	return offset;} static PyObject *python_process_callchain(struct perf_sample *sample,					 struct addr_location *al){	PyObject *pylist;	struct callchain_cursor *cursor; 	pylist = PyList_New(0);	if (!pylist)		Py_FatalError("couldn't create Python list"); 	if (!symbol_conf.use_callchain || !sample->callchain)		goto exit; 	cursor = get_tls_callchain_cursor();	if (thread__resolve_callchain(al->thread, cursor,				      sample, NULL, NULL,				      scripting_max_stack) != 0) {		pr_err("Failed to resolve callchain. Skipping\n");		goto exit;	}	callchain_cursor_commit(cursor);  	while (1) {		PyObject *pyelem;		struct callchain_cursor_node *node;		node = callchain_cursor_current(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->ms.sym) {			PyObject *pysym  = PyDict_New();			if (!pysym)				Py_FatalError("couldn't create Python dictionary");			pydict_set_item_string_decref(pysym, "start",					PyLong_FromUnsignedLongLong(node->ms.sym->start));			pydict_set_item_string_decref(pysym, "end",					PyLong_FromUnsignedLongLong(node->ms.sym->end));			pydict_set_item_string_decref(pysym, "binding",					_PyLong_FromLong(symbol__binding(node->ms.sym)));			pydict_set_item_string_decref(pysym, "name",					_PyUnicode_FromStringAndSize(node->ms.sym->name,							node->ms.sym->namelen));			pydict_set_item_string_decref(pyelem, "sym", pysym); 			if (node->ms.map) {				struct map *map = node->ms.map;				struct addr_location node_al;				unsigned long offset; 				addr_location__init(&node_al);				node_al.addr = map__map_ip(map, node->ip);				node_al.map  = map__get(map);				offset = get_offset(node->ms.sym, &node_al);				addr_location__exit(&node_al); 				pydict_set_item_string_decref(					pyelem, "sym_off",					PyLong_FromUnsignedLongLong(offset));			}			if (node->srcline && strcmp(":0", node->srcline)) {				pydict_set_item_string_decref(					pyelem, "sym_srcline",					_PyUnicode_FromString(node->srcline));			}		} 		if (node->ms.map) {			const char *dsoname = get_dsoname(node->ms.map); 			pydict_set_item_string_decref(pyelem, "dso",					_PyUnicode_FromString(dsoname));		} 		callchain_cursor_advance(cursor);		PyList_Append(pylist, pyelem);		Py_DECREF(pyelem);	} exit:	return pylist;} static PyObject *python_process_brstack(struct perf_sample *sample,					struct thread *thread){	struct branch_stack *br = sample->branch_stack;	struct branch_entry *entries = perf_sample__branch_entries(sample);	PyObject *pylist;	u64 i; 	pylist = PyList_New(0);	if (!pylist)		Py_FatalError("couldn't create Python list"); 	if (!(br && br->nr))		goto exit; 	for (i = 0; i < br->nr; i++) {		PyObject *pyelem;		struct addr_location al;

Lines 1–500 of 2224.