From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7BE2CFED3F0 for ; Fri, 24 Apr 2026 16:49:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:Cc:To:From: Subject:Message-ID:References:Mime-Version:In-Reply-To:Date:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=H9IY0E+jq+4hNA6GFdNP5uVzgQFO0YURBgUe6AG3hGo=; b=VsDnNZdTAWgPKK+TYdNFcDa4D7 136Y9/nczHebF+HXUbrjx1auxznzczutVI3uZtkxF24pnMgcy5VjdpSwnwe4bp+fk+JqmdtY8vVbN HiRglJ4FommCgpnZAT9el6tyFebPFNvp8N21KsHqHKn0rVQRl1tiwIIwFmOXIil6WpenlOc8V52Hn aLbK7oELcEqbpTiPyVidBwxD1iVurefd/GYXPZT3X7brTKsPeWh1fadHKR3BrmZNqkiaOcn2+2psF 6lVoh9hILyMDucMvA+36wQepKuYz1Ky5GiTK9C5VQvGL4DUFnow+sp8AIEyD+qgtc8ga4/4ciuW7x BAWQ0MNQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1wGJhr-0000000DTzr-1Pei; Fri, 24 Apr 2026 16:48:43 +0000 Received: from mail-dy1-x134a.google.com ([2607:f8b0:4864:20::134a]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1wGJhY-0000000DTeE-1uuV for linux-arm-kernel@lists.infradead.org; Fri, 24 Apr 2026 16:48:32 +0000 Received: by mail-dy1-x134a.google.com with SMTP id 5a478bee46e88-2ba9a744f7dso10530935eec.0 for ; Fri, 24 Apr 2026 09:48:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777049303; x=1777654103; darn=lists.infradead.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=H9IY0E+jq+4hNA6GFdNP5uVzgQFO0YURBgUe6AG3hGo=; b=ohvn5CDxkhFgi0TauZnqyTsH3RpUnGns47hRdr7EtWUB3auwzAogo6GE5ChA4pKK4F heKkbsSdMkz3/3j5vWGszffBsxjdHUJRczgPwZb0+MTO+mpLjEl1IXT/iA6qztvldDI3 RGE85eKNJG4KIqqvzbz4zBVPaxwGgJrpHaJNknB7QCEFd3AdhMGcpVQf3sYMyfAMPc9k V2V5PNgZJohwL/6HJksiD72mYptZwOLh28fiXXQXizI2jdANT04pducLZthwCHMwwTev PeXObqQkhD99yKcqbXa9OD5yzhbznUwFNWS7nrVh+xlUpi6bqQA9SRmN+D4CEPvv/RWS kPkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777049303; x=1777654103; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=H9IY0E+jq+4hNA6GFdNP5uVzgQFO0YURBgUe6AG3hGo=; b=oLp0TxCpMXy86pgvB5hJ81eScKYvBHMmekt+U/0bAUtMa4yTfjcwjhtX9Uzp82mvI4 Huh1K6tjn0ZmLwoV4Ko5dXUfmKDKZIaPYMHu8dkjg8l5yR1OrLie4FgTrclJN+jHEmuE /ZpKnVEJlLLSTH09Uu34R6JeHOBVy++Ua/iUta3XWbpsMgg9rmr79RA5iEjDHGGnvyvC 0cQ0rd1+50KVx0+NOfcKSIqv79g4js1rkgX6JxRpMz5R4VVVLBME5PqC1wxQTrsHDOvS Dn0EPIJfv4ujK9ACTAyB2B/gcuYjp7K8+Yt4JBT3US9PLQyHW/IY4izj6Msod4aEk8KT y6Tg== X-Forwarded-Encrypted: i=1; AFNElJ+xR1Gb0iqMNtBUskAZSMAwdX2kyhHUResg7btZrpu7TXKg9IJty9MljqFZDSYhmCssyD9xggoXh2rvcXEQA+nd@lists.infradead.org X-Gm-Message-State: AOJu0YyPgypHdoK0ZO4TpifD/jw3GCf9GY+/4wKw6cA9HT3yH79gV+be TbEgoyvT0zFIWf8aLZYBZFzk65yStUC4J1lGtOkDjWzn7HQyawYW3NtnHwvkdwuHPjHftiZgVmL 6JpKF5M9ZnA== X-Received: from dybvu5.prod.google.com ([2002:a05:7300:f805:b0:2cc:a1bf:2dd9]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:fe88:b0:2e6:9dee:be50 with SMTP id 5a478bee46e88-2e69deec382mr11189699eec.20.1777049302880; Fri, 24 Apr 2026 09:48:22 -0700 (PDT) Date: Fri, 24 Apr 2026 09:46:39 -0700 In-Reply-To: <20260424164721.2229025-1-irogers@google.com> Mime-Version: 1.0 References: <20260423163406.1779809-1-irogers@google.com> <20260424164721.2229025-1-irogers@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260424164721.2229025-18-irogers@google.com> Subject: [PATCH v5 17/58] perf python: Refactor and add accessors to sample event From: Ian Rogers To: acme@kernel.org, adrian.hunter@intel.com, james.clark@linaro.org, leo.yan@linux.dev, namhyung@kernel.org, tmricht@linux.ibm.com Cc: alice.mei.rogers@gmail.com, dapeng1.mi@linux.intel.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, mingo@redhat.com, peterz@infradead.org, Ian Rogers Content-Type: text/plain; charset="UTF-8" X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260424_094824_645149_0B937C22 X-CRM114-Status: GOOD ( 20.02 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add a common field for the evsel of an event. The evsel is derived from the PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER that are potentially present in all events. Move fields, like sample_ip, to only be present in sample events. This avoids errors like getting the sample ip for an mmap event. Add new accessors for sample event raw_buf, dso, dso_long_name, dso_bid, map_start, map_end, map_pgoff, symbol, sym_start, sym_end, srccode and insn. Minor tweaks to pyrf_evlist__str and pyrf_evsel__str. Assisted-by: Gemini:gemini-3.1-pro-preview Signed-off-by: Ian Rogers --- v2: 1. Fixed Uninitialized Memory: In pyrf_event__new , I initialized al_resolved to false and called addr_location__init(&pevent->al) to prevent using garbage memory. 2. Restored sample_time : Added sample_time back to sample_members to avoid breaking scripts that rely on timestamps for non-sample events. 3. Fixed NULL Pointer Dereference: Added a NULL check for pevent->sample.evsel in pyrf_event__get_evsel() . 4. Fixed Memory Leak in Destructor: Added a call to addr_location__exit(&pevent->al) in pyrf_event__delete() to free map and thread references acquired during resolution. 5. Fixed Use-After-Free and Cache Corruption in srccode : Used a local addr_location in pyrf_sample_event__srccode() instead of overwriting pevent->al in place, avoiding dangling pointer issues with the thread reference and preserving the cached info. 6. Fix pyrf_evlist__read_on_cpu so that if an unsupported event type causes an exception a NoMemory error isn't thrown on top of this. --- tools/perf/util/python.c | 396 +++++++++++++++++++++++++++++++++++---- 1 file changed, 361 insertions(+), 35 deletions(-) diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index f240905e07d6..63ee9bc65721 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -8,22 +8,29 @@ #include #include +#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 "dwarf-regs.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 "syscalltbl.h" @@ -32,7 +39,6 @@ #include "tool.h" #include "tp_pmu.h" #include "trace-event.h" -#include "util/sample.h" #ifdef HAVE_LIBTRACEEVENT #include @@ -40,6 +46,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), \ @@ -52,21 +60,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[] = { @@ -105,9 +145,12 @@ static PyTypeObject pyrf_mmap_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.mmap_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .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, }; @@ -140,9 +183,12 @@ static PyTypeObject pyrf_task_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.task_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .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, }; @@ -172,6 +218,7 @@ static PyTypeObject pyrf_comm_event__type = { .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, }; @@ -201,9 +248,12 @@ static PyTypeObject pyrf_throttle_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.throttle_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .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, }; @@ -236,9 +286,12 @@ static PyTypeObject pyrf_lost_event__type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "perf.lost_event", .tp_basicsize = sizeof(struct pyrf_event), + .tp_new = PyType_GenericNew, + .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, }; @@ -269,6 +322,7 @@ static PyTypeObject pyrf_read_event__type = { .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, }; @@ -276,16 +330,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; @@ -373,6 +428,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) { @@ -386,13 +634,103 @@ 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_new = PyType_GenericNew, + .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, }; @@ -428,25 +766,18 @@ 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_new = PyType_GenericNew, + .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) @@ -516,7 +847,9 @@ static PyObject *pyrf_event__new(const union perf_event *event) pevent = PyObject_New(struct pyrf_event, ptype); if (pevent != NULL) { memcpy(&pevent->event, event, event->header.size); - perf_sample__init(&pevent->sample, /*all=*/false); + pevent->sample.evsel = NULL; + pevent->al_resolved = false; + addr_location__init(&pevent->al); } return (PyObject *)pevent; } @@ -1209,7 +1542,7 @@ static PyObject *pyrf_evsel__str(PyObject *self) struct pyrf_evsel *pevsel = (void *)self; struct evsel *evsel = pevsel->evsel; - 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[] = { @@ -1771,10 +2104,8 @@ 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; @@ -1786,13 +2117,12 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, struct evsel *evsel; if (pyevent == NULL) - return PyErr_NoMemory(); + return PyErr_Occurred() ? NULL : PyErr_NoMemory(); evsel = evlist__event2evsel(evlist, event); if (!evsel) { Py_DECREF(pyevent); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } perf_mmap__consume(&md->core); @@ -1807,8 +2137,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, return pyevent; } end: - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, @@ -2003,10 +2332,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, "])"); -- 2.54.0.545.g6539524ca2-goog