diff options
Diffstat (limited to 'tools/perf/util/scripting-engines/trace-event-python.c')
| -rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 199 | 
1 files changed, 176 insertions, 23 deletions
| diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index cd9774df3750..cbce2545da45 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -27,11 +27,13 @@  #include <errno.h>  #include "../../perf.h" +#include "../debug.h"  #include "../evsel.h"  #include "../util.h"  #include "../event.h"  #include "../thread.h"  #include "../trace-event.h" +#include "../machine.h"  PyMODINIT_FUNC initperf_trace_context(void); @@ -50,10 +52,14 @@ static int zero_flag_atom;  static PyObject *main_module, *main_dict; +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();  }  /* @@ -97,6 +103,7 @@ static void define_value(enum print_arg_type field_type,  		retval = PyObject_CallObject(handler, t);  		if (retval == NULL)  			handler_call_die(handler_name); +		Py_DECREF(retval);  	}  	Py_DECREF(t); @@ -143,6 +150,7 @@ static void define_field(enum print_arg_type field_type,  		retval = PyObject_CallObject(handler, t);  		if (retval == NULL)  			handler_call_die(handler_name); +		Py_DECREF(retval);  	}  	Py_DECREF(t); @@ -197,6 +205,7 @@ static void define_event_symbols(struct event_format *event,  	case PRINT_BSTRING:  	case PRINT_DYNAMIC_ARRAY:  	case PRINT_FUNC: +	case PRINT_BITMASK:  		/* we should warn... */  		return;  	} @@ -230,15 +239,133 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)  	return event;  } +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 (machine__resolve_callchain(al->machine, evsel, al->thread, +					   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 thread *thread,  				      struct addr_location *al)  { -	PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; +	PyObject *handler, *retval, *context, *t, *obj, *callchain; +	PyObject *dict = NULL;  	static char handler_name[256];  	struct format_field *field; -	unsigned long long val;  	unsigned long s, ns;  	struct event_format *event;  	unsigned n = 0; @@ -279,18 +406,23 @@ static void python_process_tracepoint(struct perf_sample *sample,  	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) { @@ -302,20 +434,7 @@ static void python_process_tracepoint(struct perf_sample *sample,  				offset = field->offset;  			obj = PyString_FromString((char *)data + offset);  		} else { /* FIELD_IS_NUMERIC */ -			val = read_size(event, data + field->offset, -					field->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); -			} +			obj = get_field_numeric_entry(event, field, data);  		}  		if (handler)  			PyTuple_SetItem(t, n++, obj); @@ -323,6 +442,7 @@ static void python_process_tracepoint(struct perf_sample *sample,  			pydict_set_item_string_decref(dict, field->name, obj);  	} +  	if (!handler)  		PyTuple_SetItem(t, n++, dict); @@ -333,6 +453,7 @@ static void python_process_tracepoint(struct perf_sample *sample,  		retval = PyObject_CallObject(handler, t);  		if (retval == NULL)  			handler_call_die(handler_name); +		Py_DECREF(retval);  	} else {  		handler = PyDict_GetItemString(main_dict, "trace_unhandled");  		if (handler && PyCallable_Check(handler)) { @@ -340,6 +461,7 @@ static void python_process_tracepoint(struct perf_sample *sample,  			retval = PyObject_CallObject(handler, t);  			if (retval == NULL)  				handler_call_die("trace_unhandled"); +			Py_DECREF(retval);  		}  		Py_DECREF(dict);  	} @@ -352,7 +474,7 @@ static void python_process_general_event(struct perf_sample *sample,  					 struct thread *thread,  					 struct addr_location *al)  { -	PyObject *handler, *retval, *t, *dict; +	PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;  	static char handler_name[64];  	unsigned n = 0; @@ -368,6 +490,10 @@ static void python_process_general_event(struct perf_sample *sample,  	if (!dict)  		Py_FatalError("couldn't create Python dictionary"); +	dict_sample = PyDict_New(); +	if (!dict_sample) +		Py_FatalError("couldn't create Python dictionary"); +  	snprintf(handler_name, sizeof(handler_name), "%s", "process_event");  	handler = PyDict_GetItemString(main_dict, handler_name); @@ -377,8 +503,21 @@ static void python_process_general_event(struct perf_sample *sample,  	pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));  	pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(  			(const char *)&evsel->attr, sizeof(evsel->attr))); -	pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( -			(const char *)sample, sizeof(*sample))); + +	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); +  	pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(  			(const char *)sample->raw_data, sample->raw_size));  	pydict_set_item_string_decref(dict, "comm", @@ -392,6 +531,10 @@ static void python_process_general_event(struct perf_sample *sample,  			PyString_FromString(al->sym->name));  	} +	/* ip unwinding */ +	callchain = python_process_callchain(sample, evsel, al); +	pydict_set_item_string_decref(dict, "callchain", callchain); +  	PyTuple_SetItem(t, n++, dict);  	if (_PyTuple_Resize(&t, n) == -1)  		Py_FatalError("error resizing Python tuple"); @@ -399,6 +542,7 @@ static void python_process_general_event(struct perf_sample *sample,  	retval = PyObject_CallObject(handler, t);  	if (retval == NULL)  		handler_call_die(handler_name); +	Py_DECREF(retval);  exit:  	Py_DECREF(dict);  	Py_DECREF(t); @@ -520,8 +664,7 @@ static int python_stop_script(void)  	retval = PyObject_CallObject(handler, NULL);  	if (retval == NULL)  		handler_call_die("trace_end"); -	else -		Py_DECREF(retval); +	Py_DECREF(retval);  out:  	Py_XDECREF(main_dict);  	Py_XDECREF(main_module); @@ -588,6 +731,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  		fprintf(ofp, "common_nsecs, ");  		fprintf(ofp, "common_pid, ");  		fprintf(ofp, "common_comm,\n\t"); +		fprintf(ofp, "common_callchain, ");  		not_first = 0;  		count = 0; @@ -622,6 +766,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  			fprintf(ofp, "%s=", f->name);  			if (f->flags & FIELD_IS_STRING ||  			    f->flags & FIELD_IS_FLAG || +			    f->flags & FIELD_IS_ARRAY ||  			    f->flags & FIELD_IS_SYMBOLIC)  				fprintf(ofp, "%%s");  			else if (f->flags & FIELD_IS_SIGNED) @@ -630,7 +775,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  				fprintf(ofp, "%%u");  		} -		fprintf(ofp, "\\n\" %% \\\n\t\t("); +		fprintf(ofp, "\" %% \\\n\t\t(");  		not_first = 0;  		count = 0; @@ -666,7 +811,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  				fprintf(ofp, "%s", f->name);  		} -		fprintf(ofp, "),\n\n"); +		fprintf(ofp, ")\n\n"); + +		fprintf(ofp, "\t\tfor node in common_callchain:"); +		fprintf(ofp, "\n\t\t\tif 'sym' in node:"); +		fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])"); +		fprintf(ofp, "\n\t\t\telse:"); +		fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n"); +		fprintf(ofp, "\t\tprint \"\\n\"\n\n"); +  	}  	fprintf(ofp, "def trace_unhandled(event_name, context, " | 
