summaryrefslogtreecommitdiff
path: root/tools/perf/util/python.c
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2026-06-15 18:15:33 -0700
committerNamhyung Kim <namhyung@kernel.org>2026-06-30 10:17:14 -0700
commit600a22ef7eb5520a98e63f3640065cb9397139c2 (patch)
treeaf138d03a29689dfbbcd2fd0684b300f675f3f0d /tools/perf/util/python.c
parentb4e38080066d3010488e89f19e57fce38746cb51 (diff)
perf python: Refactor and add accessors to sample event
Add common evsel field for events and move sample specific fields to only be present in sample events. Add accessors for sample events. Ensure offsets are within the bounds of the event. Allocate just enough memory for the copied event, don't make the maximum event size each time. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alice Rogers <alice.mei.rogers@gmail.com> Cc: Dapeng Mi <dapeng1.mi@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@linaro.org> Cc: Leo Yan <leo.yan@linux.dev> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Richter <tmricht@linux.ibm.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools/perf/util/python.c')
-rw-r--r--tools/perf/util/python.c519
1 files changed, 426 insertions, 93 deletions
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index dc71fe7e3787..72d297156ad0 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -13,21 +13,28 @@
#include <perf/mmap.h>
#include <structmember.h>
+#include "addr_location.h"
+#include "build-id.h"
#include "callchain.h"
#include "comm.h"
#include "counts.h"
#include "data.h"
#include "debug.h"
+#include "dso.h"
#include "event.h"
#include "evlist.h"
#include "evsel.h"
#include "expr.h"
+#include "map.h"
#include "metricgroup.h"
#include "mmap.h"
#include "pmus.h"
#include "print_binary.h"
#include "record.h"
+#include "sample.h"
#include "session.h"
+#include "srccode.h"
+#include "srcline.h"
#include "strbuf.h"
#include "symbol.h"
#include "stat.h"
@@ -37,7 +44,6 @@
#include "tool.h"
#include "tp_pmu.h"
#include "trace-event.h"
-#include "util/sample.h"
#ifdef HAVE_LIBTRACEEVENT
#include <event-parse.h>
@@ -45,6 +51,8 @@
PyMODINIT_FUNC PyInit_perf(void);
+static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel);
+
#define member_def(type, member, ptype, help) \
{ #member, ptype, \
offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
@@ -73,21 +81,53 @@ PyMODINIT_FUNC PyInit_perf(void);
struct pyrf_event {
PyObject_HEAD
+ /** @sample: The parsed sample from the event. */
struct perf_sample sample;
- union perf_event event;
+ /** @al: The address location from machine__resolve, lazily computed. */
+ struct addr_location al;
+ /** @al_resolved: True when machine__resolve been called. */
+ bool al_resolved;
+ /** @event: The underlying perf_event that may be in a file or ring buffer. */
+ union perf_event event;
};
#define sample_members \
- sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"), \
sample_member_def(sample_pid, pid, T_INT, "event pid"), \
sample_member_def(sample_tid, tid, T_INT, "event tid"), \
sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"), \
- sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), \
sample_member_def(sample_id, id, T_ULONGLONG, "event id"), \
sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \
sample_member_def(sample_period, period, T_ULONGLONG, "event period"), \
sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
+static PyObject *pyrf_event__get_evsel(PyObject *self, void *closure __maybe_unused)
+{
+ struct pyrf_event *pevent = (void *)self;
+
+ if (!pevent->sample.evsel)
+ Py_RETURN_NONE;
+
+ return pyrf_evsel__from_evsel(pevent->sample.evsel);
+}
+
+static PyGetSetDef pyrf_event__getset[] = {
+ {
+ .name = "evsel",
+ .get = pyrf_event__get_evsel,
+ .set = NULL,
+ .doc = "tracking event.",
+ },
+ { .name = NULL, },
+};
+
+static void pyrf_event__delete(struct pyrf_event *pevent)
+{
+ if (pevent->al_resolved)
+ addr_location__exit(&pevent->al);
+ perf_sample__exit(&pevent->sample);
+ Py_TYPE(pevent)->tp_free((PyObject *)pevent);
+}
+
static const char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
static PyMemberDef pyrf_mmap_event__members[] = {
@@ -126,9 +166,11 @@ static PyTypeObject pyrf_mmap_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.mmap_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_mmap_event__doc,
.tp_members = pyrf_mmap_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_mmap_event__repr,
};
@@ -161,9 +203,11 @@ static PyTypeObject pyrf_task_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.task_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_task_event__doc,
.tp_members = pyrf_task_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_task_event__repr,
};
@@ -190,9 +234,11 @@ static PyTypeObject pyrf_comm_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.comm_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_comm_event__doc,
.tp_members = pyrf_comm_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_comm_event__repr,
};
@@ -222,9 +268,11 @@ static PyTypeObject pyrf_throttle_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.throttle_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_throttle_event__doc,
.tp_members = pyrf_throttle_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_throttle_event__repr,
};
@@ -232,6 +280,7 @@ static const char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
static PyMemberDef pyrf_lost_event__members[] = {
sample_members
+ member_def(perf_event_header, type, T_UINT, "event type"),
member_def(perf_record_lost, id, T_ULONGLONG, "event id"),
member_def(perf_record_lost, lost, T_ULONGLONG, "number of lost events"),
{ .name = NULL, },
@@ -257,9 +306,11 @@ static PyTypeObject pyrf_lost_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.lost_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_lost_event__doc,
.tp_members = pyrf_lost_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_lost_event__repr,
};
@@ -267,6 +318,7 @@ static const char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
static PyMemberDef pyrf_read_event__members[] = {
sample_members
+ member_def(perf_event_header, type, T_UINT, "event type"),
member_def(perf_record_read, pid, T_UINT, "event pid"),
member_def(perf_record_read, tid, T_UINT, "event tid"),
{ .name = NULL, },
@@ -287,9 +339,11 @@ static PyTypeObject pyrf_read_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.read_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_read_event__doc,
.tp_members = pyrf_read_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_read_event__repr,
};
@@ -297,16 +351,17 @@ static const char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object
static PyMemberDef pyrf_sample_event__members[] = {
sample_members
+ sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"),
+ sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"),
+ sample_member_def(sample_phys_addr, phys_addr, T_ULONGLONG, "event physical addr"),
+ sample_member_def(sample_weight, weight, T_ULONGLONG, "event weight"),
+ sample_member_def(sample_data_src, data_src, T_ULONGLONG, "event data source"),
+ sample_member_def(sample_insn_count, insn_cnt, T_ULONGLONG, "event instruction count"),
+ sample_member_def(sample_cyc_count, cyc_cnt, T_ULONGLONG, "event cycle count"),
member_def(perf_event_header, type, T_UINT, "event type"),
{ .name = NULL, },
};
-static void pyrf_sample_event__delete(struct pyrf_event *pevent)
-{
- perf_sample__exit(&pevent->sample);
- Py_TYPE(pevent)->tp_free((PyObject *)pevent);
-}
-
static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent)
{
PyObject *ret;
@@ -324,6 +379,8 @@ static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent)
#ifdef HAVE_LIBTRACEEVENT
static bool is_tracepoint(const struct pyrf_event *pevent)
{
+ if (!pevent->sample.evsel)
+ return false;
return pevent->sample.evsel->core.attr.type == PERF_TYPE_TRACEPOINT;
}
@@ -394,6 +451,199 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
}
#endif /* HAVE_LIBTRACEEVENT */
+static int pyrf_sample_event__resolve_al(struct pyrf_event *pevent)
+{
+ struct evsel *evsel = pevent->sample.evsel;
+ struct evlist *evlist = evsel ? evsel->evlist : NULL;
+ struct perf_session *session = evlist ? evlist__session(evlist) : NULL;
+
+ if (pevent->al_resolved)
+ return 0;
+
+ if (!session)
+ return -1;
+
+ addr_location__init(&pevent->al);
+ if (machine__resolve(&session->machines.host, &pevent->al, &pevent->sample) < 0) {
+ addr_location__exit(&pevent->al);
+ return -1;
+ }
+
+ pevent->al_resolved = true;
+ return 0;
+}
+
+static PyObject *pyrf_sample_event__get_dso(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ return PyUnicode_FromString(dso__name(map__dso(pevent->al.map)));
+}
+
+static PyObject *pyrf_sample_event__get_dso_long_name(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ return PyUnicode_FromString(dso__long_name(map__dso(pevent->al.map)));
+}
+
+static PyObject *pyrf_sample_event__get_dso_bid(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ char sbuild_id[SBUILD_ID_SIZE];
+
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ build_id__snprintf(dso__bid(map__dso(pevent->al.map)), sbuild_id, sizeof(sbuild_id));
+ return PyUnicode_FromString(sbuild_id);
+}
+
+static PyObject *pyrf_sample_event__get_map_start(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ return PyLong_FromUnsignedLong(map__start(pevent->al.map));
+}
+
+static PyObject *pyrf_sample_event__get_map_end(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ return PyLong_FromUnsignedLong(map__end(pevent->al.map));
+}
+
+static PyObject *pyrf_sample_event__get_map_pgoff(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.map)
+ Py_RETURN_NONE;
+
+ return PyLong_FromUnsignedLongLong(map__pgoff(pevent->al.map));
+}
+
+static PyObject *pyrf_sample_event__get_symbol(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
+ Py_RETURN_NONE;
+
+ return PyUnicode_FromString(pevent->al.sym->name);
+}
+
+static PyObject *pyrf_sample_event__get_sym_start(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
+ Py_RETURN_NONE;
+
+ return PyLong_FromUnsignedLongLong(pevent->al.sym->start);
+}
+
+static PyObject *pyrf_sample_event__get_sym_end(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.sym)
+ Py_RETURN_NONE;
+
+ return PyLong_FromUnsignedLongLong(pevent->al.sym->end);
+}
+
+static PyObject *pyrf_sample_event__get_raw_buf(struct pyrf_event *pevent,
+ void *closure __maybe_unused)
+{
+ if (pevent->event.header.type != PERF_RECORD_SAMPLE)
+ Py_RETURN_NONE;
+
+ return PyBytes_FromStringAndSize((const char *)pevent->sample.raw_data,
+ pevent->sample.raw_size);
+}
+
+static PyObject *pyrf_sample_event__srccode(PyObject *self, PyObject *args)
+{
+ struct pyrf_event *pevent = (void *)self;
+ u64 addr = pevent->sample.ip;
+ char *srcfile = NULL;
+ char *srccode = NULL;
+ unsigned int line = 0;
+ int len = 0;
+ PyObject *result;
+ struct addr_location al;
+
+ if (!PyArg_ParseTuple(args, "|K", &addr))
+ return NULL;
+
+ if (pyrf_sample_event__resolve_al(pevent) < 0)
+ Py_RETURN_NONE;
+
+ if (addr != pevent->sample.ip) {
+ addr_location__init(&al);
+ thread__find_symbol_fb(pevent->al.thread, pevent->sample.cpumode, addr, &al);
+ } else {
+ addr_location__init(&al);
+ al.thread = thread__get(pevent->al.thread);
+ al.map = map__get(pevent->al.map);
+ al.sym = pevent->al.sym;
+ al.addr = pevent->al.addr;
+ }
+
+ if (al.map) {
+ struct dso *dso = map__dso(al.map);
+
+ if (dso) {
+ srcfile = get_srcline_split(dso, map__rip_2objdump(al.map, addr),
+ &line);
+ }
+ }
+ addr_location__exit(&al);
+
+ if (srcfile) {
+ srccode = find_sourceline(srcfile, line, &len);
+ result = Py_BuildValue("(sIs#)", srcfile, line, srccode, (Py_ssize_t)len);
+ free(srcfile);
+ } else {
+ result = Py_BuildValue("(sIs#)", NULL, 0, NULL, (Py_ssize_t)0);
+ }
+
+ return result;
+}
+
+static PyObject *pyrf_sample_event__insn(PyObject *self, PyObject *args __maybe_unused)
+{
+ struct pyrf_event *pevent = (void *)self;
+ struct thread *thread;
+ struct machine *machine;
+
+ if (pyrf_sample_event__resolve_al(pevent) < 0)
+ Py_RETURN_NONE;
+
+ thread = pevent->al.thread;
+
+ if (!thread || !thread__maps(thread))
+ Py_RETURN_NONE;
+
+ machine = maps__machine(thread__maps(thread));
+ if (!machine)
+ Py_RETURN_NONE;
+
+ if (pevent->sample.ip && !pevent->sample.insn_len)
+ perf_sample__fetch_insn(&pevent->sample, thread, machine);
+
+ if (!pevent->sample.insn_len)
+ Py_RETURN_NONE;
+
+ return PyBytes_FromStringAndSize((const char *)pevent->sample.insn,
+ pevent->sample.insn_len);
+}
+
static PyObject*
pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name)
{
@@ -407,13 +657,102 @@ pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name)
return obj ?: PyObject_GenericGetAttr((PyObject *) pevent, attr_name);
}
+static PyGetSetDef pyrf_sample_event__getset[] = {
+ {
+ .name = "raw_buf",
+ .get = (getter)pyrf_sample_event__get_raw_buf,
+ .set = NULL,
+ .doc = "event raw buffer.",
+ },
+ {
+ .name = "evsel",
+ .get = pyrf_event__get_evsel,
+ .set = NULL,
+ .doc = "tracking event.",
+ },
+ {
+ .name = "dso",
+ .get = (getter)pyrf_sample_event__get_dso,
+ .set = NULL,
+ .doc = "event dso short name.",
+ },
+ {
+ .name = "dso_long_name",
+ .get = (getter)pyrf_sample_event__get_dso_long_name,
+ .set = NULL,
+ .doc = "event dso long name.",
+ },
+ {
+ .name = "dso_bid",
+ .get = (getter)pyrf_sample_event__get_dso_bid,
+ .set = NULL,
+ .doc = "event dso build id.",
+ },
+ {
+ .name = "map_start",
+ .get = (getter)pyrf_sample_event__get_map_start,
+ .set = NULL,
+ .doc = "event map start address.",
+ },
+ {
+ .name = "map_end",
+ .get = (getter)pyrf_sample_event__get_map_end,
+ .set = NULL,
+ .doc = "event map end address.",
+ },
+ {
+ .name = "map_pgoff",
+ .get = (getter)pyrf_sample_event__get_map_pgoff,
+ .set = NULL,
+ .doc = "event map page offset.",
+ },
+ {
+ .name = "symbol",
+ .get = (getter)pyrf_sample_event__get_symbol,
+ .set = NULL,
+ .doc = "event symbol name.",
+ },
+ {
+ .name = "sym_start",
+ .get = (getter)pyrf_sample_event__get_sym_start,
+ .set = NULL,
+ .doc = "event symbol start address.",
+ },
+ {
+ .name = "sym_end",
+ .get = (getter)pyrf_sample_event__get_sym_end,
+ .set = NULL,
+ .doc = "event symbol end address.",
+ },
+ { .name = NULL, },
+};
+
+static PyMethodDef pyrf_sample_event__methods[] = {
+ {
+ .ml_name = "srccode",
+ .ml_meth = (PyCFunction)pyrf_sample_event__srccode,
+ .ml_flags = METH_VARARGS,
+ .ml_doc = PyDoc_STR("Get source code for an address.")
+ },
+ {
+ .ml_name = "insn",
+ .ml_meth = (PyCFunction)pyrf_sample_event__insn,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = PyDoc_STR("Get instruction bytes for a sample.")
+ },
+ { .ml_name = NULL, }
+};
+
static PyTypeObject pyrf_sample_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.sample_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_sample_event__doc,
.tp_members = pyrf_sample_event__members,
+ .tp_getset = pyrf_sample_event__getset,
+ .tp_methods = pyrf_sample_event__methods,
.tp_repr = (reprfunc)pyrf_sample_event__repr,
.tp_getattro = (getattrofunc) pyrf_sample_event__getattro,
};
@@ -449,25 +788,17 @@ static PyTypeObject pyrf_context_switch_event__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.context_switch_event",
.tp_basicsize = sizeof(struct pyrf_event),
+ .tp_dealloc = (destructor)pyrf_event__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_context_switch_event__doc,
.tp_members = pyrf_context_switch_event__members,
+ .tp_getset = pyrf_event__getset,
.tp_repr = (reprfunc)pyrf_context_switch_event__repr,
};
static int pyrf_event__setup_types(void)
{
int err;
- pyrf_mmap_event__type.tp_new =
- pyrf_task_event__type.tp_new =
- pyrf_comm_event__type.tp_new =
- pyrf_lost_event__type.tp_new =
- pyrf_read_event__type.tp_new =
- pyrf_sample_event__type.tp_new =
- pyrf_context_switch_event__type.tp_new =
- pyrf_throttle_event__type.tp_new = PyType_GenericNew;
-
- pyrf_sample_event__type.tp_dealloc = (destructor)pyrf_sample_event__delete,
err = PyType_Ready(&pyrf_mmap_event__type);
if (err < 0)
@@ -511,33 +842,57 @@ static PyTypeObject *pyrf_event__type[] = {
[PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type,
};
-static PyObject *pyrf_event__new(const union perf_event *event)
+static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *evsel)
{
struct pyrf_event *pevent;
- PyTypeObject *ptype;
+ int err;
+ u32 min_size;
+ bool needs_swap;
- if ((event->header.type < PERF_RECORD_MMAP ||
- event->header.type > PERF_RECORD_SAMPLE) &&
- !(event->header.type == PERF_RECORD_SWITCH ||
- event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) {
- PyErr_Format(PyExc_TypeError, "Unexpected header type %u",
+ if (event->header.type >= ARRAY_SIZE(pyrf_event__type) ||
+ pyrf_event__type[event->header.type] == NULL) {
+ return PyErr_Format(PyExc_TypeError, "Unexpected header type %u",
event->header.type);
- return NULL;
}
- // FIXME this better be dynamic or we need to parse everything
- // before calling perf_mmap__consume(), including tracepoint fields.
- if (sizeof(pevent->event) < event->header.size) {
- PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %u",
- sizeof(pevent->event), event->header.size);
- return NULL;
+ if (perf_event__too_small(event, &min_size)) {
+ return PyErr_Format(PyExc_ValueError, "Event size %u too small for type %u",
+ event->header.size, event->header.type);
}
- ptype = pyrf_event__type[event->header.type];
- pevent = PyObject_New(struct pyrf_event, ptype);
- if (pevent != NULL) {
- memcpy(&pevent->event, event, event->header.size);
- perf_sample__init(&pevent->sample, /*all=*/false);
+ size_t copy_size = event->header.size;
+
+ if (copy_size > sizeof(pevent->event)) {
+ return PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %zu",
+ sizeof(pevent->event), copy_size);
+ }
+
+ pevent = PyObject_New(struct pyrf_event, pyrf_event__type[event->header.type]);
+ if (pevent == NULL)
+ return PyErr_NoMemory();
+
+ /* Copy the event for memory safety and initialize variables. */
+ memcpy(&pevent->event, event, copy_size);
+ if (copy_size < sizeof(pevent->event))
+ memset((char *)&pevent->event + copy_size, 0, sizeof(pevent->event) - copy_size);
+
+ perf_sample__init(&pevent->sample, /*all=*/true);
+ pevent->al_resolved = false;
+ addr_location__init(&pevent->al);
+
+ if (!evsel)
+ return (PyObject *)pevent;
+
+ /* Parse the sample again so that pointers are within the copied event. */
+ needs_swap = evsel->needs_swap;
+
+ evsel->needs_swap = false;
+ err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample);
+ evsel->needs_swap = needs_swap;
+ if (err < 0) {
+ Py_DECREF(pevent);
+ return PyErr_Format(PyExc_OSError,
+ "perf: can't parse sample, err=%d", err);
}
return (PyObject *)pevent;
}
@@ -1244,7 +1599,7 @@ static PyObject *pyrf_evsel__str(PyObject *self)
if (!evsel)
return PyUnicode_FromString("evsel(uninitialized)");
- return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel));
+ return PyUnicode_FromFormat("evsel(%s)", evsel__name(evsel));
}
static PyMethodDef pyrf_evsel__methods[] = {
@@ -1878,9 +2233,11 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
{
struct evlist *evlist;
union perf_event *event;
+ struct evsel *evsel;
int sample_id_all = 1, cpu;
static char *kwlist[] = { "cpu", "sample_id_all", NULL };
struct mmap *md;
+ PyObject *pyevent;
int err;
CHECK_INITIALIZED(pevlist->evlist, "evlist");
@@ -1891,44 +2248,33 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
return NULL;
md = get_md(evlist, cpu);
- if (!md) {
- PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu);
- return NULL;
- }
+ if (!md)
+ return PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu);
- if (perf_mmap__read_init(&md->core) < 0)
- goto end;
+ err = perf_mmap__read_init(&md->core);
+ if (err < 0) {
+ if (err == -EAGAIN)
+ Py_RETURN_NONE;
+ return PyErr_Format(PyExc_OSError,
+ "perf: error mmap read init, err=%d", err);
+ }
event = perf_mmap__read_event(&md->core);
- if (event != NULL) {
- PyObject *pyevent = pyrf_event__new(event);
- struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
- struct evsel *evsel;
-
- if (pyevent == NULL)
- return PyErr_NoMemory();
-
- evsel = evlist__event2evsel(evlist, event);
- if (!evsel) {
- Py_DECREF(pyevent);
- Py_INCREF(Py_None);
- return Py_None;
- }
+ if (event == NULL)
+ Py_RETURN_NONE;
+ evsel = evlist__event2evsel(evlist, event);
+ if (!evsel) {
+ /* Unknown evsel. */
perf_mmap__consume(&md->core);
-
- err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample);
- if (err) {
- Py_DECREF(pyevent);
- return PyErr_Format(PyExc_OSError,
- "perf: can't parse sample, err=%d", err);
- }
-
- return pyevent;
+ Py_RETURN_NONE;
}
-end:
- Py_INCREF(Py_None);
- return Py_None;
+ pyevent = pyrf_event__new(event, evsel);
+ perf_mmap__consume(&md->core);
+ if (pyevent == NULL)
+ return PyErr_Occurred() ? NULL : PyErr_NoMemory();
+
+ return pyevent;
}
static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
@@ -2140,10 +2486,7 @@ static PyObject *pyrf_evlist__str(PyObject *self)
evlist__for_each_entry(pevlist->evlist, pos) {
if (!first)
strbuf_addch(&sb, ',');
- if (!pos->pmu)
- strbuf_addstr(&sb, evsel__name(pos));
- else
- strbuf_addf(&sb, "%s/%s/", pos->pmu->name, evsel__name(pos));
+ strbuf_addstr(&sb, evsel__name(pos));
first = false;
}
strbuf_addstr(&sb, "])");
@@ -2225,6 +2568,7 @@ static const struct perf_constant perf__constants[] = {
PERF_CONST(TYPE_BREAKPOINT),
PERF_CONST(COUNT_HW_CPU_CYCLES),
+ PERF_CONST(COUNT_HW_REF_CPU_CYCLES),
PERF_CONST(COUNT_HW_INSTRUCTIONS),
PERF_CONST(COUNT_HW_CACHE_REFERENCES),
PERF_CONST(COUNT_HW_CACHE_MISSES),
@@ -2696,26 +3040,12 @@ static int pyrf_session_tool__sample(const struct perf_tool *tool,
struct machine *machine __maybe_unused)
{
struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool);
- PyObject *pyevent = pyrf_event__new(event);
- struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
+ PyObject *pyevent = pyrf_event__new(event, sample->evsel);
PyObject *ret;
- bool needs_swap;
if (pyevent == NULL)
return -ENOMEM;
- needs_swap = sample->evsel->needs_swap;
-
- memcpy(&pevent->event, event, event->header.size);
- /* The event is already swapped, disable swapping temporarily */
- sample->evsel->needs_swap = false;
- if (evsel__parse_sample(sample->evsel, &pevent->event, &pevent->sample) < 0) {
- sample->evsel->needs_swap = needs_swap;
- Py_DECREF(pyevent);
- return -1;
- }
- sample->evsel->needs_swap = needs_swap;
-
ret = PyObject_CallFunction(psession->sample, "O", pyevent);
if (!ret) {
Py_DECREF(pyevent);
@@ -2989,10 +3319,13 @@ PyMODINIT_FUNC PyInit_perf(void)
page_size = sysconf(_SC_PAGE_SIZE);
Py_INCREF(&pyrf_evlist__type);
- PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
+ PyModule_AddObject(module, "evlist", (PyObject *)&pyrf_evlist__type);
Py_INCREF(&pyrf_evsel__type);
- PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
+ PyModule_AddObject(module, "evsel", (PyObject *)&pyrf_evsel__type);
+
+ Py_INCREF(&pyrf_thread__type);
+ PyModule_AddObject(module, "thread", (PyObject *)&pyrf_thread__type);
Py_INCREF(&pyrf_mmap_event__type);
PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type);