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 | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 55a45784c910..938b39f6ad31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -116,6 +116,34 @@ static PyObject *get_handler(const char *handler_name) | |||
116 | return handler; | 116 | return handler; |
117 | } | 117 | } |
118 | 118 | ||
119 | static int get_argument_count(PyObject *handler) | ||
120 | { | ||
121 | int arg_count = 0; | ||
122 | |||
123 | /* | ||
124 | * The attribute for the code object is func_code in Python 2, | ||
125 | * whereas it is __code__ in Python 3.0+. | ||
126 | */ | ||
127 | PyObject *code_obj = PyObject_GetAttrString(handler, | ||
128 | "func_code"); | ||
129 | if (PyErr_Occurred()) { | ||
130 | PyErr_Clear(); | ||
131 | code_obj = PyObject_GetAttrString(handler, | ||
132 | "__code__"); | ||
133 | } | ||
134 | PyErr_Clear(); | ||
135 | if (code_obj) { | ||
136 | PyObject *arg_count_obj = PyObject_GetAttrString(code_obj, | ||
137 | "co_argcount"); | ||
138 | if (arg_count_obj) { | ||
139 | arg_count = (int) PyInt_AsLong(arg_count_obj); | ||
140 | Py_DECREF(arg_count_obj); | ||
141 | } | ||
142 | Py_DECREF(code_obj); | ||
143 | } | ||
144 | return arg_count; | ||
145 | } | ||
146 | |||
119 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) | 147 | static void call_object(PyObject *handler, PyObject *args, const char *die_msg) |
120 | { | 148 | { |
121 | PyObject *retval; | 149 | PyObject *retval; |
@@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
499 | { | 527 | { |
500 | struct event_format *event = evsel->tp_format; | 528 | struct event_format *event = evsel->tp_format; |
501 | PyObject *handler, *context, *t, *obj = NULL, *callchain; | 529 | PyObject *handler, *context, *t, *obj = NULL, *callchain; |
502 | PyObject *dict = NULL; | 530 | PyObject *dict = NULL, *all_entries_dict = NULL; |
503 | static char handler_name[256]; | 531 | static char handler_name[256]; |
504 | struct format_field *field; | 532 | struct format_field *field; |
505 | unsigned long s, ns; | 533 | unsigned long s, ns; |
@@ -552,6 +580,8 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
552 | 580 | ||
553 | /* ip unwinding */ | 581 | /* ip unwinding */ |
554 | callchain = python_process_callchain(sample, evsel, al); | 582 | callchain = python_process_callchain(sample, evsel, al); |
583 | /* Need an additional reference for the perf_sample dict */ | ||
584 | Py_INCREF(callchain); | ||
555 | 585 | ||
556 | if (!dict) { | 586 | if (!dict) { |
557 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); | 587 | PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); |
@@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
602 | if (dict) | 632 | if (dict) |
603 | PyTuple_SetItem(t, n++, dict); | 633 | PyTuple_SetItem(t, n++, dict); |
604 | 634 | ||
635 | if (get_argument_count(handler) == (int) n + 1) { | ||
636 | all_entries_dict = get_perf_sample_dict(sample, evsel, al, | ||
637 | callchain); | ||
638 | PyTuple_SetItem(t, n++, all_entries_dict); | ||
639 | } else { | ||
640 | Py_DECREF(callchain); | ||
641 | } | ||
642 | |||
605 | if (_PyTuple_Resize(&t, n) == -1) | 643 | if (_PyTuple_Resize(&t, n) == -1) |
606 | Py_FatalError("error resizing Python tuple"); | 644 | Py_FatalError("error resizing Python tuple"); |
607 | 645 | ||
@@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
612 | Py_DECREF(dict); | 650 | Py_DECREF(dict); |
613 | } | 651 | } |
614 | 652 | ||
653 | Py_XDECREF(all_entries_dict); | ||
615 | Py_DECREF(t); | 654 | Py_DECREF(t); |
616 | } | 655 | } |
617 | 656 | ||