[PATCH 1/1] perf script python: Garbled text in tracepoint fields
Pass the exact length of the string to is_printable_array instead of the entire field size. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- tools/perf/util/scripting-engines/trace-event-python.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index c7187f067d31..45cc0c6635bb 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -601,6 +601,7 @@ static void python_process_tracepoint(struct perf_sample *sample, for (field = event->format.fields; field; field = field->next) { unsigned int offset, len; unsigned long long val; + char *end_ptr = NULL; if (field->flags & FIELD_IS_ARRAY) { offset = field->offset; @@ -612,8 +613,12 @@ static void python_process_tracepoint(struct perf_sample *sample, len = offset >> 16; offset &= 0x; } - if (field->flags & FIELD_IS_STRING && - is_printable_array(data + offset, len)) { + /* field may contain unused chars after the null char */ + if (field->flags & FIELD_IS_STRING) + end_ptr = memchr(data + offset, '\0', len); + if (end_ptr && + is_printable_array(data + offset, + (int)(end_ptr - ((char *)data + offset)) + 1)) { obj = PyString_FromString((char *) data + offset); } else { obj = PyByteArray_FromStringAndSize((const char *) data + offset, len); -- 2.14.0.434.g98096fd7a8-goog
[PATCH 1/1] perf script python: Garbled text in tracepoint fields
Pass the exact length of the string to is_printable_array instead of the entire field size. Signed-off-by: Arun Kalyanasundaram --- tools/perf/util/scripting-engines/trace-event-python.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index c7187f067d31..45cc0c6635bb 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -601,6 +601,7 @@ static void python_process_tracepoint(struct perf_sample *sample, for (field = event->format.fields; field; field = field->next) { unsigned int offset, len; unsigned long long val; + char *end_ptr = NULL; if (field->flags & FIELD_IS_ARRAY) { offset = field->offset; @@ -612,8 +613,12 @@ static void python_process_tracepoint(struct perf_sample *sample, len = offset >> 16; offset &= 0x; } - if (field->flags & FIELD_IS_STRING && - is_printable_array(data + offset, len)) { + /* field may contain unused chars after the null char */ + if (field->flags & FIELD_IS_STRING) + end_ptr = memchr(data + offset, '\0', len); + if (end_ptr && + is_printable_array(data + offset, + (int)(end_ptr - ((char *)data + offset)) + 1)) { obj = PyString_FromString((char *) data + offset); } else { obj = PyByteArray_FromStringAndSize((const char *) data + offset, len); -- 2.14.0.434.g98096fd7a8-goog
[PATCH 0/1] perf script python: Garbled text in tracepoint fields
The string stored in some of the fields of tracepoint handlers has unused non-ascii characters beyond the first null ternimating character. As a result the call to is_printable_array fails and the python handlers receive the entire field as a byte array instead of just the subset of chars that represent the string. This change calls is_printable_array with the correct length of the string instead of the entire field size. Bug report: lkml/2017/7/18/228 Arun Kalyanasundaram (1): perf script python: Garbled text in tracepoint fields tools/perf/util/scripting-engines/trace-event-python.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) -- 2.14.0.434.g98096fd7a8-goog
[PATCH 0/1] perf script python: Garbled text in tracepoint fields
The string stored in some of the fields of tracepoint handlers has unused non-ascii characters beyond the first null ternimating character. As a result the call to is_printable_array fails and the python handlers receive the entire field as a byte array instead of just the subset of chars that represent the string. This change calls is_printable_array with the correct length of the string instead of the entire field size. Bug report: lkml/2017/7/18/228 Arun Kalyanasundaram (1): perf script python: Garbled text in tracepoint fields tools/perf/util/scripting-engines/trace-event-python.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) -- 2.14.0.434.g98096fd7a8-goog
[tip:perf/core] perf script python: Add perf_sample dict to tracepoint handlers
Commit-ID: f38d281663b011d1d8a1b0119bb8357706d134a8 Gitweb: http://git.kernel.org/tip/f38d281663b011d1d8a1b0119bb8357706d134a8 Author: Arun Kalyanasundaram <arunk...@google.com> AuthorDate: Fri, 21 Jul 2017 15:04:21 -0700 Committer: Arnaldo Carvalho de Melo <a...@redhat.com> CommitDate: Tue, 25 Jul 2017 22:43:20 -0300 perf script python: Add perf_sample dict to tracepoint handlers The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> Acked-by: Jiri Olsa <jo...@kernel.org> Cc: Alexander Shishkin <alexander.shish...@linux.intel.com> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: David Carrillo-Cisneros <davi...@google.com> Cc: David S. Miller <da...@davemloft.net> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Seongjae Park <sj38.p...@gmail.com> Cc: Stephane Eranian <eran...@google.com> Link: http://lkml.kernel.org/r/20170721220422.63962-5-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com> --- .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 55a4578..938b39f 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); }
[tip:perf/core] perf script python: Add perf_sample dict to tracepoint handlers
Commit-ID: f38d281663b011d1d8a1b0119bb8357706d134a8 Gitweb: http://git.kernel.org/tip/f38d281663b011d1d8a1b0119bb8357706d134a8 Author: Arun Kalyanasundaram AuthorDate: Fri, 21 Jul 2017 15:04:21 -0700 Committer: Arnaldo Carvalho de Melo CommitDate: Tue, 25 Jul 2017 22:43:20 -0300 perf script python: Add perf_sample dict to tracepoint handlers The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Daniel Borkmann Cc: David Carrillo-Cisneros Cc: David S. Miller Cc: Peter Zijlstra Cc: Seongjae Park Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170721220422.63962-5-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 55a4578..938b39f 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); }
[tip:perf/core] perf script python: Generate hooks with additional argument
Commit-ID: a641860550f05a4b8889dca61aab73c84b2d5e16 Gitweb: http://git.kernel.org/tip/a641860550f05a4b8889dca61aab73c84b2d5e16 Author: Arun Kalyanasundaram <arunk...@google.com> AuthorDate: Fri, 21 Jul 2017 15:04:22 -0700 Committer: Arnaldo Carvalho de Melo <a...@redhat.com> CommitDate: Tue, 25 Jul 2017 22:43:21 -0300 perf script python: Generate hooks with additional argument Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> Acked-by: Jiri Olsa <jo...@kernel.org> Cc: Alexander Shishkin <alexander.shish...@linux.intel.com> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: David Carrillo-Cisneros <davi...@google.com> Cc: David S. Miller <da...@davemloft.net> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Seongjae Park <sj38.p...@gmail.com> Cc: Stephane Eranian <eran...@google.com> Link: http://lkml.kernel.org/r/20170721220422.63962-6-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com> --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f..c7187f0 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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);
[tip:perf/core] perf script python: Generate hooks with additional argument
Commit-ID: a641860550f05a4b8889dca61aab73c84b2d5e16 Gitweb: http://git.kernel.org/tip/a641860550f05a4b8889dca61aab73c84b2d5e16 Author: Arun Kalyanasundaram AuthorDate: Fri, 21 Jul 2017 15:04:22 -0700 Committer: Arnaldo Carvalho de Melo CommitDate: Tue, 25 Jul 2017 22:43:21 -0300 perf script python: Generate hooks with additional argument Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Daniel Borkmann Cc: David Carrillo-Cisneros Cc: David S. Miller Cc: Peter Zijlstra Cc: Seongjae Park Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170721220422.63962-6-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f..c7187f0 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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);
[tip:perf/core] perf script python: Add sample_read to dict
Commit-ID: 74ec14f3893c3065053b91cec850cffa2d565e0a Gitweb: http://git.kernel.org/tip/74ec14f3893c3065053b91cec850cffa2d565e0a Author: Arun Kalyanasundaram <arunk...@google.com> AuthorDate: Fri, 21 Jul 2017 15:04:20 -0700 Committer: Arnaldo Carvalho de Melo <a...@redhat.com> CommitDate: Tue, 25 Jul 2017 22:43:19 -0300 perf script python: Add sample_read to dict Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> Acked-by: Jiri Olsa <jo...@kernel.org> Cc: Alexander Shishkin <alexander.shish...@linux.intel.com> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: David Carrillo-Cisneros <davi...@google.com> Cc: David S. Miller <da...@davemloft.net> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Seongjae Park <sj38.p...@gmail.com> Cc: Stephane Eranian <eran...@google.com> Link: http://lkml.kernel.org/r/20170721220422.63962-4-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com> --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6d..55a4578 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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(
[tip:perf/core] perf script python: Add sample_read to dict
Commit-ID: 74ec14f3893c3065053b91cec850cffa2d565e0a Gitweb: http://git.kernel.org/tip/74ec14f3893c3065053b91cec850cffa2d565e0a Author: Arun Kalyanasundaram AuthorDate: Fri, 21 Jul 2017 15:04:20 -0700 Committer: Arnaldo Carvalho de Melo CommitDate: Tue, 25 Jul 2017 22:43:19 -0300 perf script python: Add sample_read to dict Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Daniel Borkmann Cc: David Carrillo-Cisneros Cc: David S. Miller Cc: Peter Zijlstra Cc: Seongjae Park Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170721220422.63962-4-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6d..55a4578 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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(
[tip:perf/core] perf script python: Refactor creation of perf sample dict
Commit-ID: 892e76b2e8c5e85e69514478e3319575a68b9770 Gitweb: http://git.kernel.org/tip/892e76b2e8c5e85e69514478e3319575a68b9770 Author: Arun Kalyanasundaram <arunk...@google.com> AuthorDate: Fri, 21 Jul 2017 15:04:19 -0700 Committer: Arnaldo Carvalho de Melo <a...@redhat.com> CommitDate: Tue, 25 Jul 2017 22:43:19 -0300 perf script python: Refactor creation of perf sample dict Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> Acked-by: Jiri Olsa <jo...@kernel.org> Cc: Alexander Shishkin <alexander.shish...@linux.intel.com> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: David Carrillo-Cisneros <davi...@google.com> Cc: David S. Miller <da...@davemloft.net> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Seongjae Park <sj38.p...@gmail.com> Cc: Stephane Eranian <eran...@google.com> Link: http://lkml.kernel.org/r/20170721220422.63962-3-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com> --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f482..69d1b6d 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ exit: return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ static void python_process_general_event(struct perf_sample *sample, if (!t) Py_FatalError("couldn't create Python tuple"); - dict = PyDict_New(); - if (!dict) -
[tip:perf/core] perf script python: Refactor creation of perf sample dict
Commit-ID: 892e76b2e8c5e85e69514478e3319575a68b9770 Gitweb: http://git.kernel.org/tip/892e76b2e8c5e85e69514478e3319575a68b9770 Author: Arun Kalyanasundaram AuthorDate: Fri, 21 Jul 2017 15:04:19 -0700 Committer: Arnaldo Carvalho de Melo CommitDate: Tue, 25 Jul 2017 22:43:19 -0300 perf script python: Refactor creation of perf sample dict Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Daniel Borkmann Cc: David Carrillo-Cisneros Cc: David S. Miller Cc: Peter Zijlstra Cc: Seongjae Park Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170721220422.63962-3-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f482..69d1b6d 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ exit: return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); -
[tip:perf/core] perf script python: Allocate memory only if handler exists
Commit-ID: e9f9a9ca8588e58dc0800b44adc41d32f6fc813a Gitweb: http://git.kernel.org/tip/e9f9a9ca8588e58dc0800b44adc41d32f6fc813a Author: Arun Kalyanasundaram <arunk...@google.com> AuthorDate: Fri, 21 Jul 2017 15:04:18 -0700 Committer: Arnaldo Carvalho de Melo <a...@redhat.com> CommitDate: Tue, 25 Jul 2017 22:43:18 -0300 perf script python: Allocate memory only if handler exists Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> Acked-by: Jiri Olsa <jo...@kernel.org> Cc: Alexander Shishkin <alexander.shish...@linux.intel.com> Cc: Daniel Borkmann <dan...@iogearbox.net> Cc: David Carrillo-Cisneros <davi...@google.com> Cc: David S. Miller <da...@davemloft.net> Cc: Peter Zijlstra <pet...@infradead.org> Cc: Seongjae Park <sj38.p...@gmail.com> Cc: Stephane Eranian <eran...@google.com> Link: http://lkml.kernel.org/r/20170721220422.63962-2-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com> --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00..8a8f482 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, if (!dict_sample) Py_FatalError("couldn't creat
[tip:perf/core] perf script python: Allocate memory only if handler exists
Commit-ID: e9f9a9ca8588e58dc0800b44adc41d32f6fc813a Gitweb: http://git.kernel.org/tip/e9f9a9ca8588e58dc0800b44adc41d32f6fc813a Author: Arun Kalyanasundaram AuthorDate: Fri, 21 Jul 2017 15:04:18 -0700 Committer: Arnaldo Carvalho de Melo CommitDate: Tue, 25 Jul 2017 22:43:18 -0300 perf script python: Allocate memory only if handler exists Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Daniel Borkmann Cc: David Carrillo-Cisneros Cc: David S. Miller Cc: Peter Zijlstra Cc: Seongjae Park Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20170721220422.63962-2-arunk...@google.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00..8a8f482 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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)));
[PATCH v2 2/5] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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->
[PATCH v2 2/5] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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, &q
[PATCH v2 1/5] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 1/5] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 4/5] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- Changes in v2: - Make an explicit call to Py_INCREF on callchain in process tracepoint to keep the object alive in get_perf_sample_dict. .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 4/5] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram --- Changes in v2: - Make an explicit call to Py_INCREF on callchain in process tracepoint to keep the object alive in get_perf_sample_dict. .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 3/5] perf script python: Add sample_read to dict
Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..55a45784c910 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ static PyObject *python_process_callchain(struct perf_sample *sample, 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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( -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 3/5] perf script python: Add sample_read to dict
Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..55a45784c910 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ static PyObject *python_process_callchain(struct perf_sample *sample, 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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( -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 5/5] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f6ad31..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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); -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 0/5] perf script python: Provide sample dict to all handlers
v2: - Add sample_read struct to the dict (in 3/5). - Increase reference count of callchain in process tracepoint to avoid unnecessary garbage collection (in 4/5). The process_event python hook receives a dict with most perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. In addition, provide time_enabled, time_running and counter value in the perf_sample dict. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (5): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add sample_read to dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 246 +++-- 1 file changed, 184 insertions(+), 62 deletions(-) -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 5/5] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f6ad31..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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); -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH v2 0/5] perf script python: Provide sample dict to all handlers
v2: - Add sample_read struct to the dict (in 3/5). - Increase reference count of callchain in process tracepoint to avoid unnecessary garbage collection (in 4/5). The process_event python hook receives a dict with most perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. In addition, provide time_enabled, time_running and counter value in the perf_sample dict. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (5): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add sample_read to dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 246 +++-- 1 file changed, 184 insertions(+), 62 deletions(-) -- 2.14.0.rc0.284.gd933b75aa4-goog
Re: [PATCH 0/5] perf script python: Provide perf_sample dict to all handlers
My apologies. Yes, I did make a couple of changes to the patch. I was not sure if I should be sending a v2 since the previous one was a rfc. Please ignore this patch, I will resend this highlighting the new changes made. On Fri, Jul 21, 2017 at 9:28 AM, Arnaldo Carvalho de Melo <a...@kernel.org> wrote: > Em Fri, Jul 21, 2017 at 09:46:39AM +0200, Jiri Olsa escreveu: >> On Thu, Jul 20, 2017 at 07:01:13PM -0700, Arun Kalyanasundaram wrote: >> > The process_event python hook receives a dict with most perf_sample >> > entries. >> >> hi, >> was there any change to the rfc post? > > I was wondering that, please stick a v1, v2, etc to the subject, and > state the changes across versions, to make things clear. > > - Arnaldo > >> thanks, >> jirka >> >> > >> > Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate >> > the introduction of this dict and do not receive it. This patch series >> > adds the dict to all handlers, aiming to unify the information passed to >> > them. >> > >> > This change adds an additional argument to the affected handlers. To >> > keep backwards compatibility (and avoid unnecessary work), do not pass >> > the aforementioned dict if the number of arguments signals that handler >> > version predates this change. >> > >> > In addition, provide time_enabled, time_running and counter value in the >> > perf_sample dict. >> > >> > Initial Discussion: https://lkml.org/lkml/2017/7/1/108 >> > >> > Arun Kalyanasundaram (5): >> > perf script python: Allocate memory only if handler exists >> > perf script python: Refactor creation of perf sample dict >> > perf script python: Add sample_read to dict >> > perf script python: Add perf_sample dict to tracepoint handlers >> > perf script python: Generate hooks with additional argument >> > >> > .../util/scripting-engines/trace-event-python.c| 246 >> > +++-- >> > 1 file changed, 184 insertions(+), 62 deletions(-) >> > >> > -- >> > 2.14.0.rc0.284.gd933b75aa4-goog >> >
Re: [PATCH 0/5] perf script python: Provide perf_sample dict to all handlers
My apologies. Yes, I did make a couple of changes to the patch. I was not sure if I should be sending a v2 since the previous one was a rfc. Please ignore this patch, I will resend this highlighting the new changes made. On Fri, Jul 21, 2017 at 9:28 AM, Arnaldo Carvalho de Melo wrote: > Em Fri, Jul 21, 2017 at 09:46:39AM +0200, Jiri Olsa escreveu: >> On Thu, Jul 20, 2017 at 07:01:13PM -0700, Arun Kalyanasundaram wrote: >> > The process_event python hook receives a dict with most perf_sample >> > entries. >> >> hi, >> was there any change to the rfc post? > > I was wondering that, please stick a v1, v2, etc to the subject, and > state the changes across versions, to make things clear. > > - Arnaldo > >> thanks, >> jirka >> >> > >> > Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate >> > the introduction of this dict and do not receive it. This patch series >> > adds the dict to all handlers, aiming to unify the information passed to >> > them. >> > >> > This change adds an additional argument to the affected handlers. To >> > keep backwards compatibility (and avoid unnecessary work), do not pass >> > the aforementioned dict if the number of arguments signals that handler >> > version predates this change. >> > >> > In addition, provide time_enabled, time_running and counter value in the >> > perf_sample dict. >> > >> > Initial Discussion: https://lkml.org/lkml/2017/7/1/108 >> > >> > Arun Kalyanasundaram (5): >> > perf script python: Allocate memory only if handler exists >> > perf script python: Refactor creation of perf sample dict >> > perf script python: Add sample_read to dict >> > perf script python: Add perf_sample dict to tracepoint handlers >> > perf script python: Generate hooks with additional argument >> > >> > .../util/scripting-engines/trace-event-python.c| 246 >> > +++-- >> > 1 file changed, 184 insertions(+), 62 deletions(-) >> > >> > -- >> > 2.14.0.rc0.284.gd933b75aa4-goog >> >
[PATCH 1/5] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 2/5] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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->
[PATCH 1/5] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 2/5] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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, &q
[PATCH 4/5] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 4/5] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 41 +- 1 file changed, 40 insertions(+), 1 deletion(-) 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) 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; @@ -499,7 +527,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -552,6 +580,8 @@ 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 (!dict) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); @@ -602,6 +632,14 @@ static void python_process_tracepoint(struct perf_sample *sample, 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(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -612,6 +650,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 5/5] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f6ad31..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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); -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 5/5] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 22 ++ 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 938b39f6ad31..c7187f067d31 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1367,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, " @@ -1436,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'])"); @@ -1446,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); -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 0/5] perf script python: Provide perf_sample dict to all handlers
The process_event python hook receives a dict with most perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. In addition, provide time_enabled, time_running and counter value in the perf_sample dict. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (5): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add sample_read to dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 246 +++-- 1 file changed, 184 insertions(+), 62 deletions(-) -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 3/5] perf script python: Add sample_read to dict
Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..55a45784c910 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ static PyObject *python_process_callchain(struct perf_sample *sample, 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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( -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 0/5] perf script python: Provide perf_sample dict to all handlers
The process_event python hook receives a dict with most perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. In addition, provide time_enabled, time_running and counter value in the perf_sample dict. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (5): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add sample_read to dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 246 +++-- 1 file changed, 184 insertions(+), 62 deletions(-) -- 2.14.0.rc0.284.gd933b75aa4-goog
[PATCH 3/5] perf script python: Add sample_read to dict
Provide time_enabled, time_running and counter value in the perf_sample dict. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 51 ++ 1 file changed, 51 insertions(+) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..55a45784c910 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,56 @@ static PyObject *python_process_callchain(struct perf_sample *sample, 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(>read.group.values[i]); + PyList_SET_ITEM(values, i, t); + } + } else { + PyObject *t = get_sample_value_as_tuple(>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, @@ -422,6 +472,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, 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( -- 2.14.0.rc0.284.gd933b75aa4-goog
Re: [RFC 0/4] perf script python: Provide perf_sample dict to all handlers
Thank you for taking a look into it. I don't see the garbled output. Can you please send me the perf.data file or a way to reproduce it? On Tue, Jul 18, 2017 at 1:35 AM, Jiri Olsa <jo...@redhat.com> wrote: > On Mon, Jul 17, 2017 at 03:10:36PM -0700, Arun Kalyanasundaram wrote: >> The process_event python hook receives a dict with all perf_sample entries. >> >> Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the >> introduction of this dict and do not receive it. This patch series adds the >> dict to all handlers, aiming to unify the information passed to them. >> >> This change adds an additional argument to the affected handlers. To keep >> backwards compatibility (and avoid unnecessary work), do not pass the >> aforementioned dict if the number of arguments signals that handler version >> predates this change. >> >> Initial Discussion: https://lkml.org/lkml/2017/7/1/108 >> >> Arun Kalyanasundaram (4): >> perf script python: Allocate memory only if handler exists >> perf script python: Refactor creation of perf sample dict >> perf script python: Add perf_sample dict to tracepoint handlers >> perf script python: Generate hooks with additional argument >> >> .../util/scripting-engines/trace-event-python.c| 189 >> ++--- >> 1 file changed, 128 insertions(+), 61 deletions(-) > > looks good, but any idea the perf-script.py output gives > some trash at the end of 'comm' args? like: > > sched__sched_stat_runtime 1 199971.01018286921999 perf > comm=perf^@^@-x86_64-l^@, pid=21999 > > > thanks, > jirka
Re: [RFC 0/4] perf script python: Provide perf_sample dict to all handlers
Thank you for taking a look into it. I don't see the garbled output. Can you please send me the perf.data file or a way to reproduce it? On Tue, Jul 18, 2017 at 1:35 AM, Jiri Olsa wrote: > On Mon, Jul 17, 2017 at 03:10:36PM -0700, Arun Kalyanasundaram wrote: >> The process_event python hook receives a dict with all perf_sample entries. >> >> Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the >> introduction of this dict and do not receive it. This patch series adds the >> dict to all handlers, aiming to unify the information passed to them. >> >> This change adds an additional argument to the affected handlers. To keep >> backwards compatibility (and avoid unnecessary work), do not pass the >> aforementioned dict if the number of arguments signals that handler version >> predates this change. >> >> Initial Discussion: https://lkml.org/lkml/2017/7/1/108 >> >> Arun Kalyanasundaram (4): >> perf script python: Allocate memory only if handler exists >> perf script python: Refactor creation of perf sample dict >> perf script python: Add perf_sample dict to tracepoint handlers >> perf script python: Generate hooks with additional argument >> >> .../util/scripting-engines/trace-event-python.c| 189 >> ++--- >> 1 file changed, 128 insertions(+), 61 deletions(-) > > looks good, but any idea the perf-script.py output gives > some trash at the end of 'comm' args? like: > > sched__sched_stat_runtime 1 199971.01018286921999 perf > comm=perf^@^@-x86_64-l^@, pid=21999 > > > thanks, > jirka
[RFC 2/4] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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->
[RFC 2/4] perf script python: Refactor creation of perf sample dict
Move the creation of the dict containing perf_sample entries into a helper function to enable its reuse in other sample processing routines. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 94 -- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 8a8f4829d3e2..69d1b6db96f6 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -391,6 +391,57 @@ static PyObject *python_process_callchain(struct perf_sample *sample, return pylist; } +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 *)>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)); + } + + 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) @@ -801,7 +852,7 @@ 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; @@ -819,48 +870,9 @@ 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"); - - 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 *)>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, &q
[RFC 3/4] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 37 +- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..a23f5940f826 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) 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; @@ -448,7 +476,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -551,6 +579,12 @@ static void python_process_tracepoint(struct perf_sample *sample, 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); + } + if (_PyTuple_Resize(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -561,6 +595,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.13.2.932.g7449e964c-goog
[RFC 3/4] perf script python: Add perf_sample dict to tracepoint handlers
The process_event python hook receives a dict with all perf_sample entries, but the tracepoint specific and trace_unhandled hooks predate the introduction of this dict, and do not receive it. Add the aforementioned dict as an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the dict if the number of arguments signals that handler version predates this change. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 37 +- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 69d1b6db96f6..a23f5940f826 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) 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; @@ -448,7 +476,7 @@ static void python_process_tracepoint(struct perf_sample *sample, { 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; @@ -551,6 +579,12 @@ static void python_process_tracepoint(struct perf_sample *sample, 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); + } + if (_PyTuple_Resize(, n) == -1) Py_FatalError("error resizing Python tuple"); @@ -561,6 +595,7 @@ static void python_process_tracepoint(struct perf_sample *sample, Py_DECREF(dict); } + Py_XDECREF(all_entries_dict); Py_DECREF(t); } -- 2.13.2.932.g7449e964c-goog
[RFC 1/4] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.13.2.932.g7449e964c-goog
[RFC 1/4] perf script python: Allocate memory only if handler exists
Avoid allocating memory if hook handler is not available. This saves unused memory allocation and simplifies error path. Let handler in python_process_tracepoint point to either tracepoint specific or trace_unhandled hook. Use dict to check if handler points to trace_unhandled. Remove the exit label in python_process_general_event and return when no handler is available. Signed-off-by: Arun Kalyanasundaram --- .../util/scripting-engines/trace-event-python.c| 38 +- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 57b7a00e6f16..8a8f4829d3e2 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -407,10 +407,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), @@ -427,10 +424,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; @@ -445,7 +451,7 @@ static void python_process_tracepoint(struct perf_sample *sample, /* ip unwinding */ callchain = python_process_callchain(sample, evsel, al); - 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)); @@ -484,23 +490,23 @@ 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 (_PyTuple_Resize(, 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); } @@ -799,6 +805,12 @@ static void python_process_general_event(struct perf_sample *sample, 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. @@ -815,12 +827,6 @@ static void python_process_general_event(struct perf_sample *sample, 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 *)>attr, sizeof(evsel->attr))); @@ -861,7 +867,7 @@ static void python_process_general_event(struct perf_sample *sample, Py_FatalError("error resizing Python tuple"); call_object(handler, t, handler_name); -exit: + Py_DECREF(dict); Py_DECREF(t); } -- 2.13.2.932.g7449e964c-goog
[RFC 4/4] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram <arunk...@google.com> --- .../perf/util/scripting-engines/trace-event-python.c | 20 +--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index a23f5940f826..2fef0cb0383c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1312,6 +1312,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, " @@ -1381,6 +1387,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'])"); @@ -1391,16 +1400,21 @@ 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"); + 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())])"); + fclose(ofp); fprintf(stderr, "generated Python script: %s\n", fname); -- 2.13.2.932.g7449e964c-goog
[RFC 0/4] perf script python: Provide perf_sample dict to all handlers
The process_event python hook receives a dict with all perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (4): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 189 ++--- 1 file changed, 128 insertions(+), 61 deletions(-) -- 2.13.2.932.g7449e964c-goog
[RFC 4/4] perf script python: Generate hooks with additional argument
Modify the signature of tracepoint specific and trace_unhandled hooks to add the perf_sample dict as a new argument. Create a python helper function to print a dictionary. Signed-off-by: Arun Kalyanasundaram --- .../perf/util/scripting-engines/trace-event-python.c | 20 +--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index a23f5940f826..2fef0cb0383c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1312,6 +1312,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, " @@ -1381,6 +1387,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'])"); @@ -1391,16 +1400,21 @@ 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"); + 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())])"); + fclose(ofp); fprintf(stderr, "generated Python script: %s\n", fname); -- 2.13.2.932.g7449e964c-goog
[RFC 0/4] perf script python: Provide perf_sample dict to all handlers
The process_event python hook receives a dict with all perf_sample entries. Other handlers (e.g. trace_unhandled, python_process_tracepoint) predate the introduction of this dict and do not receive it. This patch series adds the dict to all handlers, aiming to unify the information passed to them. This change adds an additional argument to the affected handlers. To keep backwards compatibility (and avoid unnecessary work), do not pass the aforementioned dict if the number of arguments signals that handler version predates this change. Initial Discussion: https://lkml.org/lkml/2017/7/1/108 Arun Kalyanasundaram (4): perf script python: Allocate memory only if handler exists perf script python: Refactor creation of perf sample dict perf script python: Add perf_sample dict to tracepoint handlers perf script python: Generate hooks with additional argument .../util/scripting-engines/trace-event-python.c| 189 ++--- 1 file changed, 128 insertions(+), 61 deletions(-) -- 2.13.2.932.g7449e964c-goog
Re: tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi Masama, Thank you for looking into this. You are right, I don't see the issue when my trace_clock = x86-tsc. I tried with other clocks and apparently, I only see this when my clock is either perf or global. You mentioned this happens when "it adjusts timestamp", so does that mean this is an expected behavior in this case? I am running this on a haswell x86 architecture with 72 cores. Thank you, - Arun On Sun, Jul 9, 2017 at 5:18 PM, Masami Hiramatsu <mhira...@kernel.org> wrote: > Hello Arun, > > On Fri, 7 Jul 2017 16:06:40 -0700 > Arun Kalyanasundaram <arunk...@google.com> wrote: > >> Hi Steven, >> >> Thank you very much for your reply. I am using kernel - v4.12-rc3. >> >> I did something like this and see the issue: >> # trace-cmd record -e kprobes:s1 -e kprobes:s2 -- taskset -c 0 my_program >> # ./trace-cmd report -t --cpu 0 >> >> The issue is pretty intermittent and only happens when there are a lot >> of samples, and so "my_program" generates a few hundred threads. Any >> pointers on debugging this would be very helpful, or please let me >> know if you want me to collect any log messages. > > Ok, so this happens with ftrace+trace-cmd too. > If you run it on x86-64, could you add "-C x86-tsc" and check still > it happens? If not, I guess it happens when it adjusts timestamp. > > Thank you, > > -- > Masami Hiramatsu <mhira...@kernel.org>
Re: tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi Masama, Thank you for looking into this. You are right, I don't see the issue when my trace_clock = x86-tsc. I tried with other clocks and apparently, I only see this when my clock is either perf or global. You mentioned this happens when "it adjusts timestamp", so does that mean this is an expected behavior in this case? I am running this on a haswell x86 architecture with 72 cores. Thank you, - Arun On Sun, Jul 9, 2017 at 5:18 PM, Masami Hiramatsu wrote: > Hello Arun, > > On Fri, 7 Jul 2017 16:06:40 -0700 > Arun Kalyanasundaram wrote: > >> Hi Steven, >> >> Thank you very much for your reply. I am using kernel - v4.12-rc3. >> >> I did something like this and see the issue: >> # trace-cmd record -e kprobes:s1 -e kprobes:s2 -- taskset -c 0 my_program >> # ./trace-cmd report -t --cpu 0 >> >> The issue is pretty intermittent and only happens when there are a lot >> of samples, and so "my_program" generates a few hundred threads. Any >> pointers on debugging this would be very helpful, or please let me >> know if you want me to collect any log messages. > > Ok, so this happens with ftrace+trace-cmd too. > If you run it on x86-64, could you add "-C x86-tsc" and check still > it happens? If not, I guess it happens when it adjusts timestamp. > > Thank you, > > -- > Masami Hiramatsu
Re: tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi Steven, Thank you very much for your reply. I am using kernel - v4.12-rc3. I did something like this and see the issue: # trace-cmd record -e kprobes:s1 -e kprobes:s2 -- taskset -c 0 my_program # ./trace-cmd report -t --cpu 0 The issue is pretty intermittent and only happens when there are a lot of samples, and so "my_program" generates a few hundred threads. Any pointers on debugging this would be very helpful, or please let me know if you want me to collect any log messages. On Fri, Jul 7, 2017 at 12:01 PM, Steven Rostedt <rost...@goodmis.org> wrote: > On Fri, 7 Jul 2017 10:34:48 -0700 > Arun Kalyanasundaram <arunk...@google.com> wrote: > >> Hi, >> >> I am trying to use kprobes to time a few kernel functions. However, when I >> add two kprobes on a function that are a few instructions apart, I >> sometimes get the same timestamp (measured in nano seconds) on the two >> probes. >> >> For example, if I add the two probes as follows, >> 1) perf probe -a "kprobe1=__schedule" >> 2) perf probe -a "kprobe2=__schedule+12" >> >> I then use "perf record" on a multi-threaded benchmark (e.g. stream: >> https://www.cs.virginia.edu/stream/) to collect samples. I then see the >> same timestamp on kprobe1 and kprobe2 for the same thread running on the >> same CPU. Following is an example of the output showing the same timestamp >> on the two probes. >> >> comm,tid,cpu,time,event,ip,sym >> stream,62182,[064],3020935.384132080,probe:kprobe1,b36399f1,__schedule >> stream,62182,[064],3020935.384132080,probe:kprobe2,b36399fd,__schedule >> >> Since it happens intermittently, I am wondering if there is some sort of >> race condition here. Please let me know if this is an expected behavior or >> is there something wrong in the way I use kprobes. >> > > I don't see this with ftrace. What kernel are you using? > > # cd /sys/kernel/debug/tracing > # echo perf > trace_clock > # echo 'p:s1 __schedule' > kprobe_events > # echo 'p:s2 __schedule+12' >> kprobe_events > # echo 1 > events/kprobes/enable > # cd > # trace-cmd extract > # trace-cmd report -t --cpu 0 | less > > I didn't see anything where they had the same timestamps. > > > -- Steve
Re: tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi Steven, Thank you very much for your reply. I am using kernel - v4.12-rc3. I did something like this and see the issue: # trace-cmd record -e kprobes:s1 -e kprobes:s2 -- taskset -c 0 my_program # ./trace-cmd report -t --cpu 0 The issue is pretty intermittent and only happens when there are a lot of samples, and so "my_program" generates a few hundred threads. Any pointers on debugging this would be very helpful, or please let me know if you want me to collect any log messages. On Fri, Jul 7, 2017 at 12:01 PM, Steven Rostedt wrote: > On Fri, 7 Jul 2017 10:34:48 -0700 > Arun Kalyanasundaram wrote: > >> Hi, >> >> I am trying to use kprobes to time a few kernel functions. However, when I >> add two kprobes on a function that are a few instructions apart, I >> sometimes get the same timestamp (measured in nano seconds) on the two >> probes. >> >> For example, if I add the two probes as follows, >> 1) perf probe -a "kprobe1=__schedule" >> 2) perf probe -a "kprobe2=__schedule+12" >> >> I then use "perf record" on a multi-threaded benchmark (e.g. stream: >> https://www.cs.virginia.edu/stream/) to collect samples. I then see the >> same timestamp on kprobe1 and kprobe2 for the same thread running on the >> same CPU. Following is an example of the output showing the same timestamp >> on the two probes. >> >> comm,tid,cpu,time,event,ip,sym >> stream,62182,[064],3020935.384132080,probe:kprobe1,b36399f1,__schedule >> stream,62182,[064],3020935.384132080,probe:kprobe2,b36399fd,__schedule >> >> Since it happens intermittently, I am wondering if there is some sort of >> race condition here. Please let me know if this is an expected behavior or >> is there something wrong in the way I use kprobes. >> > > I don't see this with ftrace. What kernel are you using? > > # cd /sys/kernel/debug/tracing > # echo perf > trace_clock > # echo 'p:s1 __schedule' > kprobe_events > # echo 'p:s2 __schedule+12' >> kprobe_events > # echo 1 > events/kprobes/enable > # cd > # trace-cmd extract > # trace-cmd report -t --cpu 0 | less > > I didn't see anything where they had the same timestamps. > > > -- Steve
[Resend: Adding linux-kernel] tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi, I am trying to use kprobes to time a few kernel functions. However, when I add two kprobes on a function that are a few instructions apart, I sometimes get the same timestamp (measured in nano seconds) on the two probes. For example, if I add the two probes as follows, 1) perf probe -a "kprobe1=__schedule" 2) perf probe -a "kprobe2=__schedule+12" I then use "perf record" on a multi-threaded benchmark (e.g. www.cs.virginia.edu/stream/) to collect samples. I then see the same timestamp on kprobe1 and kprobe2 for the same thread running on the same CPU. Following is an example of the output showing the same timestamp on the two probes. comm,tid,cpu,time,event,ip,sym stream,62182,[064],3020935.384132080,probe:kprobe1,b36399f1,__schedule stream,62182,[064],3020935.384132080,probe:kprobe2,b36399fd,__schedule Since it happens intermittently, I am wondering if there is some sort of race condition here. Please let me know if this is an expected behavior or is there something wrong in the way I use kprobes. Thank you, - Arun
[Resend: Adding linux-kernel] tracing/kprobes: [Bug] Identical timestamps on two kprobes that are few instructions apart
Hi, I am trying to use kprobes to time a few kernel functions. However, when I add two kprobes on a function that are a few instructions apart, I sometimes get the same timestamp (measured in nano seconds) on the two probes. For example, if I add the two probes as follows, 1) perf probe -a "kprobe1=__schedule" 2) perf probe -a "kprobe2=__schedule+12" I then use "perf record" on a multi-threaded benchmark (e.g. www.cs.virginia.edu/stream/) to collect samples. I then see the same timestamp on kprobe1 and kprobe2 for the same thread running on the same CPU. Following is an example of the output showing the same timestamp on the two probes. comm,tid,cpu,time,event,ip,sym stream,62182,[064],3020935.384132080,probe:kprobe1,b36399f1,__schedule stream,62182,[064],3020935.384132080,probe:kprobe2,b36399fd,__schedule Since it happens intermittently, I am wondering if there is some sort of race condition here. Please let me know if this is an expected behavior or is there something wrong in the way I use kprobes. Thank you, - Arun
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
Arnaldo: So, I think what you are suggesting is, we should check the signature of the hook to determine if it has an additional attribute and only then should we provide the dict. May be something like this: PyObject* custom_dict = PyObject_GetAttrString(handler, "other_fields_dict"); if (custom_dict) //Add dict to PyTuple Do you think this would be a better approach? Thank you, - Arun On Wed, Jul 5, 2017 at 1:41 PM, Arun Kalyanasundaram <arunk...@google.com> wrote: > I wasn't entirely sure if we should modify the signature of the python > hooks_ as this would make existing scripts incompatible. So the patch > only adds sample->pid to the event_fields_dict param in > trace_unhandled(). > > > On Wed, Jul 5, 2017 at 12:26 PM, Arnaldo Carvalho de Melo > <a...@kernel.org> wrote: >> Em Wed, Jul 05, 2017 at 04:25:45PM -0300, Arnaldo Carvalho de Melo escreveu: >>> Em Wed, Jul 05, 2017 at 09:22:07AM -0700, Arun Kalyanasundaram escreveu: >>> > Hi Arnaldo, >>> > >>> > Thank you for your reply. >>> > I actually meant tracepoint event handlers: def >>> > trace_unhandled(event_name, context, event_fields_dict) >>> > The dict parameter contains an attribute "common_pid" which is >>> > actually the "tid" of the thread. There are no other attributes that >>> > contain the actual pid of the process. So, I was wondering if this is >>> > something intentional? If not I can share a patch to fix this. >>> >>> Yeah there is a problem in: >>> >>> tools/perf/util/scripting-engines/trace-event-python.c >>> >>> static void python_process_event(union perf_event *event, >>> struct perf_sample *sample, >>> struct perf_evsel *evsel, >>> struct addr_location *al) >>> { >>> struct tables *tables = _global; >>> >>> switch (evsel->attr.type) { >>> case PERF_TYPE_TRACEPOINT: >>> python_process_tracepoint(sample, evsel, al); >>> break; >>> /* Reserve for future process_hw/sw/raw APIs */ >>> default: >>> if (tables->db_export_mode) >>> db_export__sample(>dbe, event, sample, >>> evsel, al); >>> else >>> python_process_general_event(sample, evsel, al); >>> } >>> } >>> >>> The python_process_tracepoint() thing predates >>> python_process_general_event(), and doesn't adds the dict with all the >>> perf_sample entries that python_process_general_event() passes to the >>> python method :-\ >>> >>> Both the per-tracepoint python hooks _and_ trace_unhandled() should get >>> that dict, is that what your patch does? >> >> Well, for performance reasons I think perhaps we could take a look at >> the signature of the python hook and provide the dictionary only if it >> is in it? >> >> - Arnaldo
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
Arnaldo: So, I think what you are suggesting is, we should check the signature of the hook to determine if it has an additional attribute and only then should we provide the dict. May be something like this: PyObject* custom_dict = PyObject_GetAttrString(handler, "other_fields_dict"); if (custom_dict) //Add dict to PyTuple Do you think this would be a better approach? Thank you, - Arun On Wed, Jul 5, 2017 at 1:41 PM, Arun Kalyanasundaram wrote: > I wasn't entirely sure if we should modify the signature of the python > hooks_ as this would make existing scripts incompatible. So the patch > only adds sample->pid to the event_fields_dict param in > trace_unhandled(). > > > On Wed, Jul 5, 2017 at 12:26 PM, Arnaldo Carvalho de Melo > wrote: >> Em Wed, Jul 05, 2017 at 04:25:45PM -0300, Arnaldo Carvalho de Melo escreveu: >>> Em Wed, Jul 05, 2017 at 09:22:07AM -0700, Arun Kalyanasundaram escreveu: >>> > Hi Arnaldo, >>> > >>> > Thank you for your reply. >>> > I actually meant tracepoint event handlers: def >>> > trace_unhandled(event_name, context, event_fields_dict) >>> > The dict parameter contains an attribute "common_pid" which is >>> > actually the "tid" of the thread. There are no other attributes that >>> > contain the actual pid of the process. So, I was wondering if this is >>> > something intentional? If not I can share a patch to fix this. >>> >>> Yeah there is a problem in: >>> >>> tools/perf/util/scripting-engines/trace-event-python.c >>> >>> static void python_process_event(union perf_event *event, >>> struct perf_sample *sample, >>> struct perf_evsel *evsel, >>> struct addr_location *al) >>> { >>> struct tables *tables = _global; >>> >>> switch (evsel->attr.type) { >>> case PERF_TYPE_TRACEPOINT: >>> python_process_tracepoint(sample, evsel, al); >>> break; >>> /* Reserve for future process_hw/sw/raw APIs */ >>> default: >>> if (tables->db_export_mode) >>> db_export__sample(>dbe, event, sample, >>> evsel, al); >>> else >>> python_process_general_event(sample, evsel, al); >>> } >>> } >>> >>> The python_process_tracepoint() thing predates >>> python_process_general_event(), and doesn't adds the dict with all the >>> perf_sample entries that python_process_general_event() passes to the >>> python method :-\ >>> >>> Both the per-tracepoint python hooks _and_ trace_unhandled() should get >>> that dict, is that what your patch does? >> >> Well, for performance reasons I think perhaps we could take a look at >> the signature of the python hook and provide the dictionary only if it >> is in it? >> >> - Arnaldo
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
I wasn't entirely sure if we should modify the signature of the python hooks_ as this would make existing scripts incompatible. So the patch only adds sample->pid to the event_fields_dict param in trace_unhandled(). On Wed, Jul 5, 2017 at 12:26 PM, Arnaldo Carvalho de Melo <a...@kernel.org> wrote: > Em Wed, Jul 05, 2017 at 04:25:45PM -0300, Arnaldo Carvalho de Melo escreveu: >> Em Wed, Jul 05, 2017 at 09:22:07AM -0700, Arun Kalyanasundaram escreveu: >> > Hi Arnaldo, >> > >> > Thank you for your reply. >> > I actually meant tracepoint event handlers: def >> > trace_unhandled(event_name, context, event_fields_dict) >> > The dict parameter contains an attribute "common_pid" which is >> > actually the "tid" of the thread. There are no other attributes that >> > contain the actual pid of the process. So, I was wondering if this is >> > something intentional? If not I can share a patch to fix this. >> >> Yeah there is a problem in: >> >> tools/perf/util/scripting-engines/trace-event-python.c >> >> static void python_process_event(union perf_event *event, >> struct perf_sample *sample, >> struct perf_evsel *evsel, >> struct addr_location *al) >> { >> struct tables *tables = _global; >> >> switch (evsel->attr.type) { >> case PERF_TYPE_TRACEPOINT: >> python_process_tracepoint(sample, evsel, al); >> break; >> /* Reserve for future process_hw/sw/raw APIs */ >> default: >> if (tables->db_export_mode) >> db_export__sample(>dbe, event, sample, >> evsel, al); >> else >> python_process_general_event(sample, evsel, al); >> } >> } >> >> The python_process_tracepoint() thing predates >> python_process_general_event(), and doesn't adds the dict with all the >> perf_sample entries that python_process_general_event() passes to the >> python method :-\ >> >> Both the per-tracepoint python hooks _and_ trace_unhandled() should get >> that dict, is that what your patch does? > > Well, for performance reasons I think perhaps we could take a look at > the signature of the python hook and provide the dictionary only if it > is in it? > > - Arnaldo
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
I wasn't entirely sure if we should modify the signature of the python hooks_ as this would make existing scripts incompatible. So the patch only adds sample->pid to the event_fields_dict param in trace_unhandled(). On Wed, Jul 5, 2017 at 12:26 PM, Arnaldo Carvalho de Melo wrote: > Em Wed, Jul 05, 2017 at 04:25:45PM -0300, Arnaldo Carvalho de Melo escreveu: >> Em Wed, Jul 05, 2017 at 09:22:07AM -0700, Arun Kalyanasundaram escreveu: >> > Hi Arnaldo, >> > >> > Thank you for your reply. >> > I actually meant tracepoint event handlers: def >> > trace_unhandled(event_name, context, event_fields_dict) >> > The dict parameter contains an attribute "common_pid" which is >> > actually the "tid" of the thread. There are no other attributes that >> > contain the actual pid of the process. So, I was wondering if this is >> > something intentional? If not I can share a patch to fix this. >> >> Yeah there is a problem in: >> >> tools/perf/util/scripting-engines/trace-event-python.c >> >> static void python_process_event(union perf_event *event, >> struct perf_sample *sample, >> struct perf_evsel *evsel, >> struct addr_location *al) >> { >> struct tables *tables = _global; >> >> switch (evsel->attr.type) { >> case PERF_TYPE_TRACEPOINT: >> python_process_tracepoint(sample, evsel, al); >> break; >> /* Reserve for future process_hw/sw/raw APIs */ >> default: >> if (tables->db_export_mode) >> db_export__sample(>dbe, event, sample, >> evsel, al); >> else >> python_process_general_event(sample, evsel, al); >> } >> } >> >> The python_process_tracepoint() thing predates >> python_process_general_event(), and doesn't adds the dict with all the >> perf_sample entries that python_process_general_event() passes to the >> python method :-\ >> >> Both the per-tracepoint python hooks _and_ trace_unhandled() should get >> that dict, is that what your patch does? > > Well, for performance reasons I think perhaps we could take a look at > the signature of the python hook and provide the dictionary only if it > is in it? > > - Arnaldo
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
Hi Arnaldo, Thank you for your reply. I actually meant tracepoint event handlers: def trace_unhandled(event_name, context, event_fields_dict) The dict parameter contains an attribute "common_pid" which is actually the "tid" of the thread. There are no other attributes that contain the actual pid of the process. So, I was wondering if this is something intentional? If not I can share a patch to fix this. Best, - Arun On Sat, Jul 1, 2017 at 7:47 AM, Arnaldo Carvalho de Melo <a...@redhat.com> wrote: > Em Fri, Jun 30, 2017 at 03:40:57PM -0700, Arun Kalyanasundaram escreveu: >> The handlers in the python script generated from "perf script" have an >> attribute: common_pid. This attribute contains the tid of the process >> instead of its pid. I would like to know if this is the expected behavior. >> There are no other attributes in the Python handler that provide the pid >> and knowing the process id is useful to be able to group all samples that >> belong to the same process that generated different threads. > > Humm, you have: > > def process_event(param_dict): > event_attr = param_dict["attr"] > sample = param_dict["sample"] > raw_buf= param_dict["raw_buf"] > comm = param_dict["comm"] > name = param_dict["ev_name"] > > And then, on sample you have (from a recent python script for processing > Intel PT samples): > > def print_common_start(comm, sample, name): >ts = sample["time"] >cpu = sample["cpu"] >pid = sample["pid"] >tid = sample["tid"] >print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts > / 10, ts %10, name), > > - Arnaldo
Re: perf script: Question: Python trace processing script contains the tid of the process in the common_pid attribute
Hi Arnaldo, Thank you for your reply. I actually meant tracepoint event handlers: def trace_unhandled(event_name, context, event_fields_dict) The dict parameter contains an attribute "common_pid" which is actually the "tid" of the thread. There are no other attributes that contain the actual pid of the process. So, I was wondering if this is something intentional? If not I can share a patch to fix this. Best, - Arun On Sat, Jul 1, 2017 at 7:47 AM, Arnaldo Carvalho de Melo wrote: > Em Fri, Jun 30, 2017 at 03:40:57PM -0700, Arun Kalyanasundaram escreveu: >> The handlers in the python script generated from "perf script" have an >> attribute: common_pid. This attribute contains the tid of the process >> instead of its pid. I would like to know if this is the expected behavior. >> There are no other attributes in the Python handler that provide the pid >> and knowing the process id is useful to be able to group all samples that >> belong to the same process that generated different threads. > > Humm, you have: > > def process_event(param_dict): > event_attr = param_dict["attr"] > sample = param_dict["sample"] > raw_buf= param_dict["raw_buf"] > comm = param_dict["comm"] > name = param_dict["ev_name"] > > And then, on sample you have (from a recent python script for processing > Intel PT samples): > > def print_common_start(comm, sample, name): >ts = sample["time"] >cpu = sample["cpu"] >pid = sample["pid"] >tid = sample["tid"] >print "%16s %5u/%-5u [%03u] %9u.%09u %7s:" % (comm, pid, tid, cpu, ts > / 10, ts %10, name), > > - Arnaldo
Re: [PATCH v2]: perf/core: addressing 4x slowdown during per-process, profiling of STREAM benchmark on Intel Xeon Phi
Hi Alexey, I am interested in validating this fix. Can you please share some of your testcases or let me know if you use any standard OpenMP benchmarks? - Arun
Re: [PATCH v2]: perf/core: addressing 4x slowdown during per-process, profiling of STREAM benchmark on Intel Xeon Phi
Hi Alexey, I am interested in validating this fix. Can you please share some of your testcases or let me know if you use any standard OpenMP benchmarks? - Arun