mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-26 14:17:26 -04:00
perf script: Add callchain to generic and tracepoint events
This provides valuable information for tracing performance problems. Since this change alters the interface for the python scripts, also adjust the script generation and the provided scripts. Signed-off-by: Joseph Schuchart <joseph.schuchart@tu-dresden.de> Acked-by: Thomas Ilsche <thomas.ilsche@tu-dresden.de> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Thomas Ilsche <thomas.ilsche@tu-dresden.de> Link: http://lkml.kernel.org/r/53BE7E1B.10503@tu-dresden.de Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
05f832e3a2
commit
0f5f5bcd11
11 changed files with 146 additions and 48 deletions
|
@ -32,6 +32,7 @@
|
|||
#include "../event.h"
|
||||
#include "../thread.h"
|
||||
#include "../trace-event.h"
|
||||
#include "../machine.h"
|
||||
|
||||
PyMODINIT_FUNC initperf_trace_context(void);
|
||||
|
||||
|
@ -278,12 +279,90 @@ static PyObject *get_field_numeric_entry(struct event_format *event,
|
|||
return obj;
|
||||
}
|
||||
|
||||
|
||||
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 s, ns;
|
||||
|
@ -326,18 +405,23 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
|||
PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
|
||||
PyTuple_SetItem(t, n++, context);
|
||||
|
||||
/* ip unwinding */
|
||||
callchain = python_process_callchain(sample, evsel, al);
|
||||
|
||||
if (handler) {
|
||||
PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
|
||||
PyTuple_SetItem(t, n++, PyInt_FromLong(s));
|
||||
PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
|
||||
PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
|
||||
PyTuple_SetItem(t, n++, PyString_FromString(comm));
|
||||
PyTuple_SetItem(t, n++, callchain);
|
||||
} else {
|
||||
pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
|
||||
pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
|
||||
pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
|
||||
pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
|
||||
pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
|
||||
pydict_set_item_string_decref(dict, "common_callchain", callchain);
|
||||
}
|
||||
for (field = event->format.fields; field; field = field->next) {
|
||||
if (field->flags & FIELD_IS_STRING) {
|
||||
|
@ -357,6 +441,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
|
|||
pydict_set_item_string_decref(dict, field->name, obj);
|
||||
|
||||
}
|
||||
|
||||
if (!handler)
|
||||
PyTuple_SetItem(t, n++, dict);
|
||||
|
||||
|
@ -388,7 +473,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, *callchain;
|
||||
static char handler_name[64];
|
||||
unsigned n = 0;
|
||||
|
||||
|
@ -428,6 +513,10 @@ static void python_process_general_event(struct perf_sample *sample,
|
|||
PyString_FromString(al->sym->name));
|
||||
}
|
||||
|
||||
/* ip unwinding */
|
||||
callchain = python_process_callchain(sample, evsel, al);
|
||||
pydict_set_item_string_decref(dict, "callchain", callchain);
|
||||
|
||||
PyTuple_SetItem(t, n++, dict);
|
||||
if (_PyTuple_Resize(&t, n) == -1)
|
||||
Py_FatalError("error resizing Python tuple");
|
||||
|
@ -624,6 +713,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
|
|||
fprintf(ofp, "common_nsecs, ");
|
||||
fprintf(ofp, "common_pid, ");
|
||||
fprintf(ofp, "common_comm,\n\t");
|
||||
fprintf(ofp, "common_callchain, ");
|
||||
|
||||
not_first = 0;
|
||||
count = 0;
|
||||
|
@ -667,7 +757,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
|
|||
fprintf(ofp, "%%u");
|
||||
}
|
||||
|
||||
fprintf(ofp, "\\n\" %% \\\n\t\t(");
|
||||
fprintf(ofp, "\" %% \\\n\t\t(");
|
||||
|
||||
not_first = 0;
|
||||
count = 0;
|
||||
|
@ -703,7 +793,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
|
|||
fprintf(ofp, "%s", f->name);
|
||||
}
|
||||
|
||||
fprintf(ofp, "),\n\n");
|
||||
fprintf(ofp, ")\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'])");
|
||||
fprintf(ofp, "\n\t\t\telse:");
|
||||
fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n");
|
||||
fprintf(ofp, "\t\tprint \"\\n\"\n\n");
|
||||
|
||||
}
|
||||
|
||||
fprintf(ofp, "def trace_unhandled(event_name, context, "
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue