|
@@ -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;
|
|
@@ -391,13 +419,115 @@ 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(&sample->read.group.values[i]);
|
|
|
+ PyList_SET_ITEM(values, i, t);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ PyObject *t = get_sample_value_as_tuple(&sample->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,
|
|
|
+ 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 *)&evsel->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));
|
|
|
+ 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(
|
|
|
+ (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)
|
|
|
{
|
|
|
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;
|
|
@@ -407,10 +537,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 +554,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;
|
|
|
|
|
@@ -444,8 +580,10 @@ 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 (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,26 +622,35 @@ 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 (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(&t, 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);
|
|
|
}
|
|
|
|
|
|
+ Py_XDECREF(all_entries_dict);
|
|
|
Py_DECREF(t);
|
|
|
}
|
|
|
|
|
@@ -795,10 +942,16 @@ 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;
|
|
|
|
|
|
+ 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.
|
|
@@ -807,61 +960,16 @@ 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");
|
|
|
-
|
|
|
- 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 *)&evsel->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));
|
|
|
- }
|
|
|
-
|
|
|
/* ip unwinding */
|
|
|
callchain = python_process_callchain(sample, evsel, al);
|
|
|
- pydict_set_item_string_decref(dict, "callchain", callchain);
|
|
|
+ dict = get_perf_sample_dict(sample, evsel, al, callchain);
|
|
|
|
|
|
PyTuple_SetItem(t, n++, dict);
|
|
|
if (_PyTuple_Resize(&t, n) == -1)
|
|
|
Py_FatalError("error resizing Python tuple");
|
|
|
|
|
|
call_object(handler, t, handler_name);
|
|
|
-exit:
|
|
|
+
|
|
|
Py_DECREF(dict);
|
|
|
Py_DECREF(t);
|
|
|
}
|
|
@@ -1259,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, "
|
|
@@ -1328,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'])");
|
|
@@ -1338,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);
|
|
|
|