From: Joseph Schuchart <joseph.schuchart@tu-dresden.de>
To: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>,
Paul Mackerras <paulus@samba.org>, Ingo Molnar <mingo@redhat.com>,
Thomas Ilsche <thomas.ilsche@tu-dresden.de>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Provide additional sample information to Python scripts
Date: Thu, 03 Apr 2014 10:57:39 +0200 [thread overview]
Message-ID: <533D2283.3090703@tu-dresden.de> (raw)
In-Reply-To: <20140307141857.GA3153@ghostprotocols.net>
[-- Attachment #1.1: Type: text/plain, Size: 1364 bytes --]
On 07.03.2014 15:18, Arnaldo Carvalho de Melo wrote:
> Can you please resend, against the perf/core branch in
> git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git, and as an
> attachement or making sure that the patch is not mangled?
Arnaldo,
Please find attached our changes. I am sending you two patches since I
came across possible memory leaks while working on the original patch.
The first patch (perf_python_retval_decref.patch) adds calls to
Py_DECREF for the references returned by PyObject_CallObject().
The second patch (perf_python_add_sample.patch) contains our changes to
hand down the sample information for generic events. In addition, the
call-chain of the samples are constructed into a list and passed on. In
the case of generic events, this is just another entry in the dictionary
that is passed to the script as sole argument. For tracepoint events,
this adds another argument and hence changes the scripting interface.
Please feel free to remove these lines in python_process_tracepoint() if
you think that this is problematic.
I hope it is no problem that I am sending you two patches in one mail.
The patches are based on the git repository you pointed out, last
updated on April 2nd (commit 675b44bdf5f2a245f4479c5a8c40abf591007f36).
Please let me know if you have any questions.
Thanks,
Joseph
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: perf_python_add_sample.patch --]
[-- Type: text/x-patch; name="perf_python_add_sample.patch", Size: 6624 bytes --]
Perf: Provide sample information and call-chain to Python script
Provide additional sample information on generic events to Python
scripts, including pid, tid, and cpu for which the event was recorded.
Additionally, provide the call-chain recorded at each event with
resolved symbols (for both generic and tracepoint events).
At the moment, the pointer to the sample struct is passed to scripts,
which seems to be of little use. The patch puts this information in
dictionaries for easy access by Python scripts.
Signed-off-by: Joseph Schuchart <joseph.schuchart@tu-dresden.de>
Acked-by: Thomas Ilsche <thomas.ilsche@tu-dresden.de>
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index a7c8932..255d451 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -32,6 +32,7 @@
#include "../event.h"
#include "../thread.h"
#include "../trace-event.h"
+#include "../machine.h"
PyMODINIT_FUNC initperf_trace_context(void);
@@ -234,12 +235,90 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
return event;
}
+
+static PyObject *python_process_callchain(struct perf_sample *sample,
+ struct perf_evsel *evsel,
+ struct addr_location *al)
+{
+ PyObject *pylist;
+
+ pylist = PyList_New(0);
+ if (!pylist)
+ Py_FatalError("couldn't create Python list");
+
+ if (!symbol_conf.use_callchain || !sample->callchain)
+ goto exit;
+
+ if (machine__resolve_callchain(al->machine, evsel, al->thread,
+ sample, NULL, NULL,
+ PERF_MAX_STACK_DEPTH) != 0) {
+ pr_err("Failed to resolve callchain. Skipping\n");
+ goto exit;
+ }
+ callchain_cursor_commit(&callchain_cursor);
+
+
+ while (1) {
+ PyObject *pyelem;
+ struct callchain_cursor_node *node;
+ node = callchain_cursor_current(&callchain_cursor);
+ if (!node)
+ break;
+
+ pyelem = PyDict_New();
+ if (!pyelem)
+ Py_FatalError("couldn't create Python dictionary");
+
+
+ pydict_set_item_string_decref(pyelem, "ip",
+ PyLong_FromUnsignedLongLong(node->ip));
+
+ if (node->sym) {
+ PyObject *pysym = PyDict_New();
+ if (!pysym)
+ Py_FatalError("couldn't create Python dictionary");
+ pydict_set_item_string_decref(pysym, "start",
+ PyLong_FromUnsignedLongLong(node->sym->start));
+ pydict_set_item_string_decref(pysym, "end",
+ PyLong_FromUnsignedLongLong(node->sym->end));
+ pydict_set_item_string_decref(pysym, "binding",
+ PyInt_FromLong(node->sym->binding));
+ pydict_set_item_string_decref(pysym, "name",
+ PyString_FromStringAndSize(node->sym->name,
+ node->sym->namelen));
+ pydict_set_item_string_decref(pyelem, "sym", pysym);
+ }
+
+ if (node->map) {
+ struct map *map = node->map;
+ const char *dsoname = "[unknown]";
+ if (map && map->dso && (map->dso->name || map->dso->long_name)) {
+ if (symbol_conf.show_kernel_path && map->dso->long_name)
+ dsoname = map->dso->long_name;
+ else if (map->dso->name)
+ dsoname = map->dso->name;
+ }
+ pydict_set_item_string_decref(pyelem, "dso",
+ PyString_FromString(dsoname));
+ }
+
+ callchain_cursor_advance(&callchain_cursor);
+ PyList_Append(pylist, pyelem);
+ Py_DECREF(pyelem);
+ }
+
+exit:
+ return pylist;
+}
+
+
static void python_process_tracepoint(struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread,
struct addr_location *al)
{
- PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
+ PyObject *handler, *retval, *context, *t, *obj, *callchain;
+ PyObject *dict = NULL;
static char handler_name[256];
struct format_field *field;
unsigned long long val;
@@ -327,6 +406,14 @@ static void python_process_tracepoint(struct perf_sample *sample,
pydict_set_item_string_decref(dict, field->name, obj);
}
+
+ /* ip unwinding */
+ callchain = python_process_callchain(sample, evsel, al);
+ if (handler)
+ PyTuple_SetItem(t, n++, callchain);
+ else
+ pydict_set_item_string_decref(dict, "callchain", callchain);
+
if (!handler)
PyTuple_SetItem(t, n++, dict);
@@ -360,7 +447,7 @@ static void python_process_general_event(struct perf_sample *sample,
struct thread *thread,
struct addr_location *al)
{
- PyObject *handler, *retval, *t, *dict;
+ PyObject *handler, *retval, *t, *dict, *dict_sample, *callchain;
static char handler_name[64];
unsigned n = 0;
@@ -376,6 +463,10 @@ static void python_process_general_event(struct perf_sample *sample,
if (!dict)
Py_FatalError("couldn't create Python dictionary");
+ dict_sample = PyDict_New();
+ if (!dict_sample)
+ Py_FatalError("couldn't create Python dictionary");
+
snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
handler = PyDict_GetItemString(main_dict, handler_name);
@@ -385,15 +476,30 @@ static void python_process_general_event(struct perf_sample *sample,
pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
(const char *)&evsel->attr, sizeof(evsel->attr)));
- pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize(
- (const char *)sample, sizeof(*sample)));
+
+ pydict_set_item_string_decref(dict_sample, "pid",
+ PyInt_FromLong(sample->pid));
+ pydict_set_item_string_decref(dict_sample, "tid",
+ PyInt_FromLong(sample->tid));
+ pydict_set_item_string_decref(dict_sample, "cpu",
+ PyInt_FromLong(sample->cpu));
+ pydict_set_item_string_decref(dict_sample, "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);
+
+ /* ip unwinding */
+ callchain = python_process_callchain(sample, evsel, al);
+ pydict_set_item_string_decref(dict, "callchain", callchain);
+
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(thread)));
if (al->map) {
pydict_set_item_string_decref(dict, "dso",
- PyString_FromString(al->map->dso->name));
+ PyString_FromString(al->map->dso->name));
}
if (al->sym) {
pydict_set_item_string_decref(dict, "symbol",
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: perf_python_retval_decref.patch --]
[-- Type: text/x-patch; name="perf_python_retval_decref.patch", Size: 2224 bytes --]
Perf: Fix possible memory leaks in Python interface
The function PyObject_CallObject() returns a new PyObject reference
on which Py_DECREF has to be called to avoid memory leaks.
This patch adds these calls where necessary.
Signed-off-by: Joseph Schuchart <joseph.schuchart@tu-dresden.de>
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cd9774d..ee17f64 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -97,6 +97,8 @@ static void define_value(enum print_arg_type field_type,
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die(handler_name);
+ else
+ Py_DECREF(retval);
}
Py_DECREF(t);
@@ -143,6 +145,8 @@ static void define_field(enum print_arg_type field_type,
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die(handler_name);
+ else
+ Py_DECREF(retval);
}
Py_DECREF(t);
@@ -333,6 +337,8 @@ static void python_process_tracepoint(struct perf_sample *sample,
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die(handler_name);
+ else
+ Py_DECREF(retval);
} else {
handler = PyDict_GetItemString(main_dict, "trace_unhandled");
if (handler && PyCallable_Check(handler)) {
@@ -340,6 +346,8 @@ static void python_process_tracepoint(struct perf_sample *sample,
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die("trace_unhandled");
+ else
+ Py_DECREF(retval);
}
Py_DECREF(dict);
}
@@ -399,6 +407,8 @@ static void python_process_general_event(struct perf_sample *sample,
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die(handler_name);
+ else
+ Py_DECREF(retval);
exit:
Py_DECREF(dict);
Py_DECREF(t);
@@ -444,8 +454,8 @@ static int run_start_sub(void)
retval = PyObject_CallObject(handler, NULL);
if (retval == NULL)
handler_call_die("trace_begin");
-
- Py_DECREF(retval);
+ else
+ Py_DECREF(retval);
return err;
error:
Py_XDECREF(main_dict);
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4943 bytes --]
next prev parent reply other threads:[~2014-04-03 9:46 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-18 8:43 [PATCH] Provide additional sample information to Python scripts Joseph Schuchart
2014-03-07 14:18 ` Arnaldo Carvalho de Melo
2014-03-12 15:29 ` Thomas Ilsche
2014-03-12 18:39 ` Arnaldo Carvalho de Melo
2014-04-03 8:57 ` Joseph Schuchart [this message]
2014-05-29 6:01 ` Namhyung Kim
2014-06-04 12:07 ` Joseph Schuchart
2014-06-04 12:07 ` [PATCH 1/3] Add missing calls to Py_DECREF Joseph Schuchart
2014-06-04 14:44 ` Namhyung Kim
2014-06-04 12:07 ` [PATCH 2/3] Add callchain to generic and tracepoint events Joseph Schuchart
2014-06-04 14:46 ` Namhyung Kim
2014-07-07 17:17 ` Jiri Olsa
2014-07-09 7:40 ` [PATCH 1/3] perf script: Add missing calls to Py_DECREF for return values Joseph Schuchart
2014-07-09 8:14 ` Namhyung Kim
2014-07-09 7:40 ` [PATCH 2/3] perf script: Add callchain to generic and tracepoint events Joseph Schuchart
2014-07-09 8:15 ` Namhyung Kim
2014-07-09 11:27 ` Jiri Olsa
2014-07-09 11:43 ` Joseph Schuchart
2014-07-09 11:49 ` Jiri Olsa
2014-07-09 14:16 ` Joseph Schuchart
2014-07-09 14:16 ` [PATCH 1/3] perf script: Add missing calls to Py_DECREF Joseph Schuchart
2014-07-09 19:07 ` Arnaldo Carvalho de Melo
2014-07-18 4:22 ` [tip:perf/core] perf script: Add missing calls to Py_DECREF for return values tip-bot for Joseph Schuchart
2014-07-09 14:16 ` [PATCH 2/3] perf script: Add callchain to generic and tracepoint events Joseph Schuchart
2014-07-09 19:09 ` Arnaldo Carvalho de Melo
2014-07-09 19:12 ` Arnaldo Carvalho de Melo
2014-07-09 19:29 ` Arnaldo Carvalho de Melo
2014-07-10 11:50 ` Joseph Schuchart
2014-07-10 11:50 ` Joseph Schuchart
2014-07-18 4:22 ` [tip:perf/core] " tip-bot for Joseph Schuchart
2014-07-10 11:50 ` [PATCH 3/3] perf script: Provide additional sample information on generic events Joseph Schuchart
2014-07-18 4:23 ` [tip:perf/core] " tip-bot for Joseph Schuchart
2014-07-09 14:16 ` [PATCH 3/3] " Joseph Schuchart
2014-07-09 7:40 ` Joseph Schuchart
2014-07-09 8:16 ` Namhyung Kim
2014-06-04 12:07 ` [PATCH 3/3] " Joseph Schuchart
2014-06-04 14:55 ` Namhyung Kim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=533D2283.3090703@tu-dresden.de \
--to=joseph.schuchart@tu-dresden.de \
--cc=a.p.zijlstra@chello.nl \
--cc=acme@ghostprotocols.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=paulus@samba.org \
--cc=thomas.ilsche@tu-dresden.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).