diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-11-14 04:10:13 +0300 | 
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-11-14 04:10:13 +0300 | 
| commit | c25141062a82ae8bddced1b3ce2b57a1c0efabe0 (patch) | |
| tree | 105edf10059bc0c4f2f00338b0c861b813d1bb1a /tools/perf/util/scripting-engines/trace-event-python.c | |
| parent | 26dd633e437dca218547ccbeacc71fe8a620b6f6 (diff) | |
| parent | c1b433e04ef9c0a1c4d65bfe918472ffa334dff4 (diff) | |
| download | linux-c25141062a82ae8bddced1b3ce2b57a1c0efabe0.tar.xz | |
Merge branch 'next' into for-linus
Prepare input updates for 4.15 merge window.
Diffstat (limited to 'tools/perf/util/scripting-engines/trace-event-python.c')
| -rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 249 | 
1 files changed, 186 insertions, 63 deletions
| diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 40de3cb40d21..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -28,6 +28,7 @@  #include <stdbool.h>  #include <errno.h>  #include <linux/bitmap.h> +#include <linux/compiler.h>  #include <linux/time64.h>  #include "../../perf.h" @@ -84,7 +85,7 @@ struct tables {  static struct tables tables_global; -static void handler_call_die(const char *handler_name) NORETURN; +static void handler_call_die(const char *handler_name) __noreturn;  static void handler_call_die(const char *handler_name)  {  	PyErr_Print(); @@ -115,6 +116,34 @@ static PyObject *get_handler(const char *handler_name)  	return handler;  } +static int get_argument_count(PyObject *handler) +{ +	int arg_count = 0; + +	/* +	 * The attribute for the code object is func_code in Python 2, +	 * whereas it is __code__ in Python 3.0+. +	 */ +	PyObject *code_obj = PyObject_GetAttrString(handler, +		"func_code"); +	if (PyErr_Occurred()) { +		PyErr_Clear(); +		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) PyInt_AsLong(arg_count_obj); +			Py_DECREF(arg_count_obj); +		} +		Py_DECREF(code_obj); +	} +	return arg_count; +} +  static void call_object(PyObject *handler, PyObject *args, const char *die_msg)  {  	PyObject *retval; @@ -390,13 +419,115 @@ exit:  	return pylist;  } +static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) +{ +	PyObject *t; + +	t = PyTuple_New(2); +	if (!t) +		Py_FatalError("couldn't create Python tuple"); +	PyTuple_SetItem(t, 0, PyLong_FromUnsignedLongLong(value->id)); +	PyTuple_SetItem(t, 1, PyLong_FromUnsignedLongLong(value->value)); +	return t; +} + +static void set_sample_read_in_dict(PyObject *dict_sample, +					 struct perf_sample *sample, +					 struct perf_evsel *evsel) +{ +	u64 read_format = evsel->attr.read_format; +	PyObject *values; +	unsigned int i; + +	if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { +		pydict_set_item_string_decref(dict_sample, "time_enabled", +			PyLong_FromUnsignedLongLong(sample->read.time_enabled)); +	} + +	if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { +		pydict_set_item_string_decref(dict_sample, "time_running", +			PyLong_FromUnsignedLongLong(sample->read.time_running)); +	} + +	if (read_format & PERF_FORMAT_GROUP) +		values = PyList_New(sample->read.group.nr); +	else +		values = PyList_New(1); + +	if (!values) +		Py_FatalError("couldn't create Python list"); + +	if (read_format & PERF_FORMAT_GROUP) { +		for (i = 0; i < sample->read.group.nr; i++) { +			PyObject *t = get_sample_value_as_tuple(&sample->read.group.values[i]); +			PyList_SET_ITEM(values, i, t); +		} +	} else { +		PyObject *t = get_sample_value_as_tuple(&sample->read.one); +		PyList_SET_ITEM(values, 0, t); +	} +	pydict_set_item_string_decref(dict_sample, "values", values); +} + +static PyObject *get_perf_sample_dict(struct perf_sample *sample, +					 struct perf_evsel *evsel, +					 struct addr_location *al, +					 PyObject *callchain) +{ +	PyObject *dict, *dict_sample; + +	dict = PyDict_New(); +	if (!dict) +		Py_FatalError("couldn't create Python dictionary"); + +	dict_sample = PyDict_New(); +	if (!dict_sample) +		Py_FatalError("couldn't create Python dictionary"); + +	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, "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)); +	set_sample_read_in_dict(dict_sample, sample, evsel); +	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", +			PyString_FromString(thread__comm_str(al->thread))); +	if (al->map) { +		pydict_set_item_string_decref(dict, "dso", +			PyString_FromString(al->map->dso->name)); +	} +	if (al->sym) { +		pydict_set_item_string_decref(dict, "symbol", +			PyString_FromString(al->sym->name)); +	} + +	pydict_set_item_string_decref(dict, "callchain", callchain); + +	return dict; +} +  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 = NULL, *callchain; -	PyObject *dict = NULL; +	PyObject *dict = NULL, *all_entries_dict = NULL;  	static char handler_name[256];  	struct format_field *field;  	unsigned long s, ns; @@ -406,10 +537,7 @@ static void python_process_tracepoint(struct perf_sample *sample,  	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"); +	const char *default_handler_name = "trace_unhandled";  	if (!event) {  		snprintf(handler_name, sizeof(handler_name), @@ -426,10 +554,19 @@ static void python_process_tracepoint(struct perf_sample *sample,  	handler = get_handler(handler_name);  	if (!handler) { +		handler = get_handler(default_handler_name); +		if (!handler) +			return;  		dict = PyDict_New();  		if (!dict)  			Py_FatalError("couldn't create Python dict");  	} + +	t = PyTuple_New(MAX_FIELDS); +	if (!t) +		Py_FatalError("couldn't create Python tuple"); + +  	s = nsecs / NSEC_PER_SEC;  	ns = nsecs - s * NSEC_PER_SEC; @@ -443,8 +580,10 @@ static void python_process_tracepoint(struct perf_sample *sample,  	/* ip unwinding */  	callchain = python_process_callchain(sample, evsel, al); +	/* Need an additional reference for the perf_sample dict */ +	Py_INCREF(callchain); -	if (handler) { +	if (!dict) {  		PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));  		PyTuple_SetItem(t, n++, PyInt_FromLong(s));  		PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); @@ -483,26 +622,35 @@ static void python_process_tracepoint(struct perf_sample *sample,  		} else { /* FIELD_IS_NUMERIC */  			obj = get_field_numeric_entry(event, field, data);  		} -		if (handler) +		if (!dict)  			PyTuple_SetItem(t, n++, obj);  		else  			pydict_set_item_string_decref(dict, field->name, obj);  	} -	if (!handler) +	if (dict)  		PyTuple_SetItem(t, n++, dict); +	if (get_argument_count(handler) == (int) n + 1) { +		all_entries_dict = get_perf_sample_dict(sample, evsel, al, +			callchain); +		PyTuple_SetItem(t, n++,	all_entries_dict); +	} else { +		Py_DECREF(callchain); +	} +  	if (_PyTuple_Resize(&t, n) == -1)  		Py_FatalError("error resizing Python tuple"); -	if (handler) { +	if (!dict) {  		call_object(handler, t, handler_name);  	} else { -		try_call_object("trace_unhandled", t); +		call_object(handler, t, default_handler_name);  		Py_DECREF(dict);  	} +	Py_XDECREF(all_entries_dict);  	Py_DECREF(t);  } @@ -794,10 +942,16 @@ static void python_process_general_event(struct perf_sample *sample,  					 struct perf_evsel *evsel,  					 struct addr_location *al)  { -	PyObject *handler, *t, *dict, *callchain, *dict_sample; +	PyObject *handler, *t, *dict, *callchain;  	static char handler_name[64];  	unsigned n = 0; +	snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); + +	handler = get_handler(handler_name); +	if (!handler) +		return; +  	/*  	 * Use the MAX_FIELDS to make the function expandable, though  	 * currently there is only one item for the tuple. @@ -806,61 +960,16 @@ static void python_process_general_event(struct perf_sample *sample,  	if (!t)  		Py_FatalError("couldn't create Python tuple"); -	dict = PyDict_New(); -	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 = get_handler(handler_name); -	if (!handler) -		goto exit; - -	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, "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", -			PyString_FromString(thread__comm_str(al->thread))); -	if (al->map) { -		pydict_set_item_string_decref(dict, "dso", -			PyString_FromString(al->map->dso->name)); -	} -	if (al->sym) { -		pydict_set_item_string_decref(dict, "symbol", -			PyString_FromString(al->sym->name)); -	} -  	/* ip unwinding */  	callchain = python_process_callchain(sample, evsel, al); -	pydict_set_item_string_decref(dict, "callchain", callchain); +	dict = get_perf_sample_dict(sample, evsel, al, callchain);  	PyTuple_SetItem(t, n++, dict);  	if (_PyTuple_Resize(&t, n) == -1)  		Py_FatalError("error resizing Python tuple");  	call_object(handler, t, handler_name); -exit: +  	Py_DECREF(dict);  	Py_DECREF(t);  } @@ -1258,6 +1367,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  			fprintf(ofp, "%s", f->name);  		} +		if (not_first++) +			fprintf(ofp, ", "); +		if (++count % 5 == 0) +			fprintf(ofp, "\n\t\t"); +		fprintf(ofp, "perf_sample_dict"); +  		fprintf(ofp, "):\n");  		fprintf(ofp, "\t\tprint_header(event_name, common_cpu, " @@ -1327,6 +1442,9 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  		fprintf(ofp, ")\n\n"); +		fprintf(ofp, "\t\tprint 'Sample: {'+" +			"get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\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'])"); @@ -1337,15 +1455,20 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)  	}  	fprintf(ofp, "def trace_unhandled(event_name, context, " -		"event_fields_dict):\n"); +		"event_fields_dict, perf_sample_dict):\n"); -	fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))" -		"for k,v in sorted(event_fields_dict.items())])\n\n"); +	fprintf(ofp, "\t\tprint get_dict_as_string(event_fields_dict)\n"); +	fprintf(ofp, "\t\tprint 'Sample: {'+" +		"get_dict_as_string(perf_sample_dict['sample'], ', ')+'}'\n\n");  	fprintf(ofp, "def print_header("  		"event_name, cpu, secs, nsecs, pid, comm):\n"  		"\tprint \"%%-20s %%5u %%05u.%%09u %%8u %%-20s \" %% \\\n\t" -		"(event_name, cpu, secs, nsecs, pid, comm),\n"); +		"(event_name, cpu, secs, nsecs, pid, comm),\n\n"); + +	fprintf(ofp, "def get_dict_as_string(a_dict, delimiter=' '):\n" +		"\treturn delimiter.join" +		"(['%%s=%%s'%%(k,str(v))for k,v in sorted(a_dict.items())])\n");  	fclose(ofp); | 
