[PATCH] Provide additional sample information to Python scripts

From: Joseph Schuchart
Date: Tue Feb 18 2014 - 04:01:14 EST


Good morning,

We have developed a patch for the perf Python scripting interface to
provide additional information about the pid, tid, and cpu of generic
events as well as information about the call-stack and resolved symbol
names. This provides scripts with a greater level of detail. The
mentioned information is already available to the scripting engine and
just has to be handed down. This is done by the attached patch. The
patch is based on Linux-3.13.3.

Please let me know if you have any questions on this.

Thanks
Joseph
--
Dipl. Inf. Joseph Schuchart
Computer Scientist

Technische Universität Dresden
Center for Information Services and High Performance Computing (ZIH)
01062 Dresden, Germany

Phone: +49 351 463-36494
Fax: +49 351 463-3773
E-Mail: joseph.schuchart@xxxxxxxxxxxxx
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-stack recorded at each event with
resolved symbols. 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@xxxxxxxxxxxxx>
Acked-by: Thomas Ilsche <thomas.ilsche@xxxxxxxxxxxxx>

@@ -359,7 +359,7 @@ static void python_process_general_event
struct thread *thread,
struct addr_location *al)
{
- PyObject *handler, *retval, *t, *dict;
+ PyObject *handler, *retval, *t, *dict, *dict_sample;
static char handler_name[64];
unsigned n = 0;

@@ -375,6 +375,10 @@ static void python_process_general_event
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);
@@ -384,8 +388,76 @@ static void python_process_general_event
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)));
+
+ /* PID/TIDs are limited to 2^29, so we can safely use PyInt */
+ 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", dict_sample);
+
+ /* ip unwinding */
+
+ if (symbol_conf.use_callchain && sample->callchain) {
+ PyObject *pylist;
+
+ if (machine__resolve_callchain(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);
+
+ pylist = PyList_New(0);
+ if (!pylist)
+ Py_FatalError("couldn't create Python list");
+
+ 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", PyInt_FromLong(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", PyInt_FromLong(node->sym->start));
+ pydict_set_item_string_decref(pysym, "end", PyInt_FromLong(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);
+ Py_DECREF(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);
+ }
+ PyDict_SetItemString(dict, "callstack", pylist);
+ Py_DECREF(pylist);
+ }
+
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",
@@ -407,6 +479,7 @@ static void python_process_general_event
if (retval == NULL)
handler_call_die(handler_name);
exit:
+ Py_DECREF(dict_sample);
Py_DECREF(dict);
Py_DECREF(t);
}

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature