mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: irogers@google.com, acme@kernel.org, adrian.hunter@intel.com,
	 alice.mei.rogers@gmail.com, james.clark@linaro.org,
	 linux-perf-users@vger.kernel.org, namhyung@kernel.org
Cc: dapeng1.mi@linux.intel.com, leo.yan@linux.dev,
	 linux-kernel@vger.kernel.org, mingo@redhat.com,
	peterz@infradead.org,  tmricht@linux.ibm.com
Subject: [PATCH v1 08/49] perf python: Expose addr location, transaction, and context_switch
Date: Sat, 19 Sep 2026 22:21:00 -0700	[thread overview]
Message-ID: <b8e1b4ae6cb475a56bcd2c48130ac1f8ca036ddb.1789880842.git.irogers@google.com> (raw)
In-Reply-To: <cover.1789880842.git.irogers@google.com>

Expose destination address location components (addr_dso, addr_symbol,
addr_sym_offset), branch/transaction metrics (branch_type, in_tx,
flags, transaction), machine_pid, vcpu, sym_offset, and context_switch
callbacks directly to the Python extension.

Also include supporting fixes and infrastructure updates in
util/python.c and perf.pyi:
- Support fetching sym_offset on resolved sample symbols.
- Populate sample machine_pid and vcpu from evlist__id2sid() when
  perf_guest is enabled, and resolve samples against the matching guest
  or host machine.
- Expose next_prev_pid and next_prev_tid on switch_event only for
  PERF_RECORD_SWITCH_CPU_WIDE records (returning None otherwise).
- Wire up tracing_data in pyrf_session__new(), use 'static char * const
  kwlist[]', and update perf.pyi type stubs (including srccode() and
  insn() return types).

Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/python/perf.pyi |  22 +++-
 tools/perf/util/python.c   | 249 +++++++++++++++++++++++++++++++++++--
 2 files changed, 253 insertions(+), 18 deletions(-)

diff --git a/tools/perf/python/perf.pyi b/tools/perf/python/perf.pyi
index e5259e9b61dd..7f747eed3eda 100644
--- a/tools/perf/python/perf.pyi
+++ b/tools/perf/python/perf.pyi
@@ -182,6 +182,8 @@ class _sample_members:
     sample_time: int
     sample_id: int
     sample_stream_id: int
+    machine_pid: int
+    vcpu: int
     sample_period: int
     sample_cpu: int
 
@@ -206,10 +208,18 @@ class sample_event(_sample_members):
     symbol: str
     sym_start: int
     sym_end: int
+    sym_offset: Optional[int]
+    addr_dso: Optional[str]
+    addr_symbol: Optional[str]
+    addr_sym_offset: Optional[int]
+    branch_type: int
+    in_tx: int
+    flags: int
+    transaction: int
     brstack: Optional['branch_stack']
     callchain: Optional['callchain']
-    def srccode(self) -> str: ...
-    def insn(self) -> str: ...
+    def srccode(self) -> Optional[tuple[str, int, str]]: ...
+    def insn(self) -> Optional[bytes]: ...
     def __getattr__(self, name: str) -> Any: ...
 
 class mmap_event(_sample_members):
@@ -286,8 +296,9 @@ class read_event(_sample_members):
 class switch_event(_sample_members):
     """Represents a SWITCH or SWITCH_CPU_WIDE record."""
     type: int
-    next_prev_pid: int
-    next_prev_tid: int
+    misc: int
+    next_prev_pid: Optional[int]
+    next_prev_tid: Optional[int]
     evsel: Optional['evsel']
 
 class branch_entry:
@@ -429,7 +440,8 @@ class session:
         self,
         data: data,
         sample: Optional[Callable[[sample_event], None]] = None,
-        stat: Optional[Callable[[Any, Optional[str]], None]] = None
+        stat: Optional[Callable[[Any, Optional[str]], None]] = None,
+        context_switch: Optional[Callable[[switch_event], None]] = None,
     ) -> None:
         """Initialize a perf session.
 
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index fbfa71b1c4b6..49f37198f4b3 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -3,6 +3,7 @@
 #include <Python.h>
 
 #include <inttypes.h>
+#include <stdio.h>
 #include <string.h>
 
 #include <linux/err.h>
@@ -106,6 +107,8 @@ struct pyrf_event {
 	sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"),		 \
 	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(machine_pid, machine_pid, T_UINT, "event machine pid"),	 \
+	sample_member_def(vcpu, vcpu, T_UINT, "event vcpu"),				 \
 	sample_member_def(sample_period, period, T_ULONGLONG, "event period"),		 \
 	sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
 
@@ -581,6 +584,7 @@ static PyMemberDef pyrf_sample_event__members[] = {
 	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"),
+	sample_member_def(flags, flags, T_UINT, "event flags"),
 	member_def(perf_event_header, type, T_UINT, "event type"),
 	{ .name = NULL, },
 };
@@ -679,6 +683,7 @@ 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;
+	struct machine *machine;
 
 	if (pevent->al_resolved)
 		return 0;
@@ -686,8 +691,14 @@ static int pyrf_sample_event__resolve_al(struct pyrf_event *pevent)
 	if (!session)
 		return -1;
 
+	machine = pevent->sample.machine_pid ?
+		machines__find(&session->machines, pevent->sample.machine_pid) :
+		&session->machines.host;
+	if (!machine)
+		machine = &session->machines.host;
+
 	addr_location__init(&pevent->al);
-	if (machine__resolve(&session->machines.host, &pevent->al, &pevent->sample) < 0) {
+	if (machine__resolve(machine, &pevent->al, &pevent->sample) < 0) {
 		addr_location__exit(&pevent->al);
 		return -1;
 	}
@@ -771,6 +782,15 @@ static PyObject *pyrf_sample_event__get_sym_start(struct pyrf_event *pevent,
 	return PyLong_FromUnsignedLongLong(pevent->al.sym->start);
 }
 
+static PyObject *pyrf_sample_event__get_sym_offset(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.addr - pevent->al.sym->start);
+}
+
 static PyObject *pyrf_sample_event__get_sym_end(struct pyrf_event *pevent,
 						void *closure __maybe_unused)
 {
@@ -1166,7 +1186,115 @@ pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name)
 	return obj ?: PyObject_GenericGetAttr((PyObject *) pevent, attr_name);
 }
 
+
+static int pyrf_sample_event__resolve_addr_al(struct pyrf_event *pevent,
+					      struct addr_location *addr_al)
+{
+	addr_location__init(addr_al);
+	if (pyrf_sample_event__resolve_al(pevent) < 0 || !pevent->al.thread)
+		return -1;
+
+	thread__find_symbol_fb(pevent->al.thread, pevent->sample.cpumode,
+			       pevent->sample.addr, addr_al);
+	return 0;
+}
+
+static PyObject *pyrf_sample_event__get_addr_dso(struct pyrf_event *pevent,
+						 void *closure __maybe_unused)
+{
+	struct addr_location addr_al;
+	PyObject *ret = Py_None;
+
+	if (pyrf_sample_event__resolve_addr_al(pevent, &addr_al) == 0 && addr_al.map)
+		ret = PyUnicode_FromString(dso__name(map__dso(addr_al.map)));
+	else
+		Py_INCREF(Py_None);
+
+	addr_location__exit(&addr_al);
+	return ret;
+}
+
+static PyObject *pyrf_sample_event__get_addr_symbol(struct pyrf_event *pevent,
+						    void *closure __maybe_unused)
+{
+	struct addr_location addr_al;
+	PyObject *ret = Py_None;
+
+	if (pyrf_sample_event__resolve_addr_al(pevent, &addr_al) == 0 && addr_al.sym)
+		ret = PyUnicode_FromString(addr_al.sym->name);
+	else
+		Py_INCREF(Py_None);
+
+	addr_location__exit(&addr_al);
+	return ret;
+}
+
+static PyObject *pyrf_sample_event__get_addr_sym_offset(struct pyrf_event *pevent,
+							void *closure __maybe_unused)
+{
+	struct addr_location addr_al;
+	PyObject *ret = Py_None;
+
+	if (pyrf_sample_event__resolve_addr_al(pevent, &addr_al) == 0 && addr_al.sym)
+		ret = PyLong_FromUnsignedLongLong(addr_al.addr - addr_al.sym->start);
+	else
+		Py_INCREF(Py_None);
+
+	addr_location__exit(&addr_al);
+	return ret;
+}
+
+static PyObject *pyrf_sample_event__get_branch_type(struct pyrf_event *pevent,
+						    void *closure __maybe_unused)
+{
+	return PyLong_FromUnsignedLong(pevent->sample.flags & PERF_BRANCH_MASK);
+}
+
+static PyObject *pyrf_sample_event__get_in_tx(struct pyrf_event *pevent,
+					      void *closure __maybe_unused)
+{
+	return PyLong_FromUnsignedLong(!!(pevent->sample.flags & PERF_IP_FLAG_IN_TX));
+}
+
+static PyObject *pyrf_sample_event__get_transaction(struct pyrf_event *pevent,
+						    void *closure __maybe_unused)
+{
+	return PyLong_FromUnsignedLongLong(pevent->sample.transaction);
+}
+
 static PyGetSetDef pyrf_sample_event__getset[] = {
+
+	{
+		.name = "addr_dso",
+		.get = (getter)pyrf_sample_event__get_addr_dso,
+		.doc = "event destination dso.",
+	},
+	{
+		.name = "addr_symbol",
+		.get = (getter)pyrf_sample_event__get_addr_symbol,
+		.doc = "event destination symbol.",
+	},
+	{
+		.name = "addr_sym_offset",
+		.get = (getter)pyrf_sample_event__get_addr_sym_offset,
+		.doc = "event destination symbol offset.",
+	},
+	{
+		.name = "branch_type",
+		.get = (getter)pyrf_sample_event__get_branch_type,
+		.doc = "branch type.",
+	},
+	{
+		.name = "in_tx",
+		.get = (getter)pyrf_sample_event__get_in_tx,
+		.doc = "in transaction flag.",
+	},
+	{
+		.name = "transaction",
+		.get = (getter)pyrf_sample_event__get_transaction,
+		.doc = "transaction execution.",
+	},
+
 	{
 		.name = "callchain",
 		.get = pyrf_sample_event__get_callchain,
@@ -1227,6 +1355,12 @@ static PyGetSetDef pyrf_sample_event__getset[] = {
 		.set = NULL,
 		.doc = "event map page offset.",
 	},
+	{
+		.name = "sym_offset",
+		.get = (getter)pyrf_sample_event__get_sym_offset,
+		.set = NULL,
+		.doc = "event symbol offset.",
+	},
 	{
 		.name = "symbol",
 		.get = (getter)pyrf_sample_event__get_symbol,
@@ -1283,8 +1417,45 @@ static const char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_swi
 static PyMemberDef pyrf_context_switch_event__members[] = {
 	sample_members
 	member_def(perf_event_header, type, T_UINT, "event type"),
-	member_def(perf_record_switch, next_prev_pid, T_UINT, "next/prev pid"),
-	member_def(perf_record_switch, next_prev_tid, T_UINT, "next/prev tid"),
+	member_def(perf_event_header, misc, T_USHORT, "event misc"),
+	{ .name = NULL, },
+};
+
+static PyObject *pyrf_context_switch_event__get_next_prev_pid(const struct pyrf_event *pevent,
+							      void *closure __maybe_unused)
+{
+	if (pevent->event.header.type == PERF_RECORD_SWITCH_CPU_WIDE)
+		return PyLong_FromUnsignedLong(pevent->event.context_switch.next_prev_pid);
+	Py_RETURN_NONE;
+}
+
+static PyObject *pyrf_context_switch_event__get_next_prev_tid(const struct pyrf_event *pevent,
+							      void *closure __maybe_unused)
+{
+	if (pevent->event.header.type == PERF_RECORD_SWITCH_CPU_WIDE)
+		return PyLong_FromUnsignedLong(pevent->event.context_switch.next_prev_tid);
+	Py_RETURN_NONE;
+}
+
+static PyGetSetDef pyrf_context_switch_event__getset[] = {
+	{
+		.name = "evsel",
+		.get = pyrf_event__get_evsel,
+		.set = NULL,
+		.doc = "tracking event.",
+	},
+	{
+		.name = "next_prev_pid",
+		.get = (getter)pyrf_context_switch_event__get_next_prev_pid,
+		.set = NULL,
+		.doc = "next/prev pid for CPU-wide switch, or None.",
+	},
+	{
+		.name = "next_prev_tid",
+		.get = (getter)pyrf_context_switch_event__get_next_prev_tid,
+		.set = NULL,
+		.doc = "next/prev tid for CPU-wide switch, or None.",
+	},
 	{ .name = NULL, },
 };
 
@@ -1292,11 +1463,19 @@ static PyObject *pyrf_context_switch_event__repr(const struct pyrf_event *pevent
 {
 	PyObject *ret;
 	char *s;
-
-	if (asprintf(&s, "{ type: context_switch, next_prev_pid: %u, next_prev_tid: %u, switch_out: %u }",
-		     pevent->event.context_switch.next_prev_pid,
-		     pevent->event.context_switch.next_prev_tid,
-		     !!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT)) < 0) {
+	int res;
+
+	if (pevent->event.header.type == PERF_RECORD_SWITCH_CPU_WIDE) {
+		res = asprintf(&s,
+			"{ type: context_switch, next_prev_pid: %u, next_prev_tid: %u, switch_out: %u }",
+			pevent->event.context_switch.next_prev_pid,
+			pevent->event.context_switch.next_prev_tid,
+			!!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT));
+	} else {
+		res = asprintf(&s, "{ type: context_switch, switch_out: %u }",
+			       !!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT));
+	}
+	if (res < 0) {
 		ret = PyErr_NoMemory();
 	} else {
 		ret = PyUnicode_FromString(s);
@@ -1313,7 +1492,7 @@ static PyTypeObject pyrf_context_switch_event__type = {
 	.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_getset	= pyrf_context_switch_event__getset,
 	.tp_repr	= (reprfunc)pyrf_context_switch_event__repr,
 };
 
@@ -1450,6 +1629,16 @@ static PyObject *pyrf_event__new(const union perf_event *event, struct evsel *ev
 		return PyErr_Format(PyExc_OSError,
 				    "perf: can't parse sample, err=%d", err);
 	}
+	if (session && session->evlist && perf_guest && pevent->sample.id) {
+		struct perf_sample_id *sid = evlist__id2sid(session->evlist, pevent->sample.id);
+
+		if (sid) {
+			pevent->sample.machine_pid = sid->machine_pid;
+			pevent->sample.vcpu = sid->vcpu.cpu;
+		}
+	}
+	if (machine && machine->pid > 0 && !pevent->sample.machine_pid)
+		pevent->sample.machine_pid = machine->pid;
 	sample = &pevent->sample;
 	if (machine && sample->callchain) {
 		struct addr_location al;
@@ -3837,6 +4026,7 @@ struct pyrf_session {
 	struct pyrf_data *pdata;
 	PyObject *sample;
 	PyObject *stat;
+	PyObject *context_switch;
 };
 
 static int pyrf_session_tool__sample(const struct perf_tool *tool,
@@ -3861,6 +4051,33 @@ static int pyrf_session_tool__sample(const struct perf_tool *tool,
 	return 0;
 }
 
+static int pyrf_session_tool__context_switch(const struct perf_tool *tool,
+					     union perf_event *event,
+					     struct perf_sample *sample,
+					     struct machine *machine)
+{
+	struct pyrf_session *psession = container_of(tool, struct pyrf_session, tool);
+	PyObject *pyevent = pyrf_event__new(event, sample->evsel, psession->session, machine);
+	PyObject *ret;
+
+	if (perf_event__process_switch(tool, event, sample, machine) < 0) {
+		Py_XDECREF(pyevent);
+		return -1;
+	}
+
+	if (pyevent == NULL)
+		return -ENOMEM;
+
+	ret = PyObject_CallFunction(psession->context_switch, "O", pyevent);
+	if (!ret) {
+		Py_DECREF(pyevent);
+		return -1;
+	}
+	Py_DECREF(ret);
+	Py_DECREF(pyevent);
+	return 0;
+}
+
 static int pyrf_session_tool__stat(const struct perf_tool *tool,
 				   struct perf_session *session,
 				   union perf_event *event)
@@ -3943,13 +4160,13 @@ static PyObject *pyrf_session__find_thread(struct pyrf_session *psession, PyObje
 static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
 {
 	struct pyrf_data *pdata;
-	PyObject *sample = NULL, *stat = NULL;
-	static char *kwlist[] = { "data", "sample", "stat", NULL };
+	PyObject *sample = NULL, *stat = NULL, *context_switch = NULL;
+	static char * const kwlist[] = { "data", "sample", "stat", "context_switch", NULL };
 	struct pyrf_session *psession;
 	struct perf_session *session;
 
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", kwlist, &pyrf_data__type, &pdata,
-					 &sample, &stat))
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OOO", kwlist, &pyrf_data__type, &pdata,
+					 &sample, &stat, &context_switch))
 		return NULL;
 
 	psession = PyObject_New(struct pyrf_session, type);
@@ -3959,6 +4176,7 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject
 	psession->session = NULL;
 	psession->sample = NULL;
 	psession->stat = NULL;
+	psession->context_switch = NULL;
 	psession->pdata = NULL;
 
 	Py_INCREF(pdata);
@@ -3982,6 +4200,7 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject
 
 	ADD_TOOL(sample);
 	ADD_TOOL(stat);
+	ADD_TOOL(context_switch);
 	#undef ADD_TOOL
 
 	if (stat)
@@ -4000,6 +4219,9 @@ static PyObject *pyrf_session__new(PyTypeObject *type, PyObject *args, PyObject
 	psession->tool.build_id         = perf_event__process_build_id;
 	psession->tool.attr		= perf_event__process_attr;
 	psession->tool.feature		= perf_event__process_feature;
+#ifdef HAVE_LIBTRACEEVENT
+	psession->tool.tracing_data	= perf_event__process_tracing_data;
+#endif
 
 	session = perf_session__new(&pdata->data, &psession->tool);
 	if (IS_ERR(session)) {
@@ -4030,6 +4252,7 @@ static void pyrf_session__delete(struct pyrf_session *psession)
 	Py_XDECREF(psession->pdata);
 	Py_XDECREF(psession->sample);
 	Py_XDECREF(psession->stat);
+	Py_XDECREF(psession->context_switch);
 	Py_TYPE(psession)->tp_free((PyObject *)psession);
 }
 
-- 
2.55.0.1082.g2b9226bbc0-goog


  parent reply	other threads:[~2026-09-20  5:22 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-20  5:20 [PATCH v1 00/49] perf: Complete transition to standalone Python scripts Ian Rogers
2026-09-20  5:20 ` [PATCH v1 01/49] perf python: Update syscall format string to optional positional Ian Rogers
2026-09-20  5:20 ` [PATCH v1 02/49] perf python: Update callchain stubs and session thread lookup Ian Rogers
2026-09-20  5:20 ` [PATCH v1 03/49] perf python: Clean up pylint warnings in ilist.py Ian Rogers
2026-09-20  5:20 ` [PATCH v1 04/49] perf python: Clean up pylint warnings in treport.py Ian Rogers
2026-09-20  5:20 ` [PATCH v1 05/49] perf python: Clean up pylint warnings in tracepoint.py Ian Rogers
2026-09-20  5:20 ` [PATCH v1 06/49] perf python: Clean up pylint warnings in twatch.py Ian Rogers
2026-09-20  5:20 ` [PATCH v1 07/49] perf python: Improve perf script -l descriptions Ian Rogers
2026-09-20  5:21 ` Ian Rogers [this message]
2026-09-20  5:21 ` [PATCH v1 09/49] perf python: Add Intel PT call_return and itrace capability Ian Rogers
2026-09-20  5:21 ` [PATCH v1 10/49] perf python: Allow KeyboardInterrupt to propagate in LiveSession Ian Rogers
2026-09-20  5:21 ` [PATCH v1 11/49] perf pmu-events: Clean up mypy and pylint issues Ian Rogers
2026-09-20  5:21 ` [PATCH v1 12/49] perf test: Clean up mypy and pylint issues in shell test libraries Ian Rogers
2026-09-20  5:21 ` [PATCH v1 13/49] perf build: Make mypy build test opt-out (NO_MYPY=1) Ian Rogers
2026-09-20  5:21 ` [PATCH v1 14/49] perf build: Make pylint build test opt-out (NO_PYLINT=1) Ian Rogers
2026-09-20  5:21 ` [PATCH v1 15/49] perf Makefile: Install standalone Python scripts during transition Ian Rogers
2026-09-20  5:21 ` [PATCH v1 16/49] perf python: Port stat-cpi to perf module Ian Rogers
2026-09-20  5:21 ` [PATCH v1 17/49] perf python: Port mem-phys-addr " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 18/49] perf python: Port stackcollapse " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 19/49] perf python: Port flamegraph " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 20/49] perf python: Port gecko " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 21/49] perf python: Port event_analyzing_sample " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 22/49] perf python: Port syscall-counts " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 23/49] perf python: Port syscall-counts-by-pid " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 24/49] perf python: Port failed-syscalls-by-pid " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 25/49] perf python: Port failed-syscalls from Perl " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 26/49] perf python: Port sctop " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 27/49] perf python: Port rw-by-file from Perl " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 28/49] perf python: Port rw-by-pid " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 29/49] perf python: Port rwtop " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 30/49] perf python: Port futex-contention " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 31/49] perf python: Port task-analyzer " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 32/49] perf python: Port sched-migration and SchedGui " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 33/49] perf python: Port wakeup-latency from Perl " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 34/49] perf python: Port compaction-times " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 35/49] perf python: Port net_dropmonitor " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 36/49] perf python: Port netdev-times " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 37/49] perf python: Port check-perf-trace " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 38/49] perf python: Port arm-cs-trace-disasm " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 39/49] perf python: Port powerpc-hcalls " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 40/49] perf python: Port intel-pt-events and libxed " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 41/49] perf test: Migrate Intel PT virtual LBR test to Python API Ian Rogers
2026-09-20  5:21 ` [PATCH v1 42/49] perf python: Port export-to-sqlite to perf module Ian Rogers
2026-09-20  5:21 ` [PATCH v1 43/49] perf python: Port export-to-postgresql " Ian Rogers
2026-09-20  5:21 ` [PATCH v1 44/49] perf python: Move and clean up exported-sql-viewer.py Ian Rogers
2026-09-20  5:21 ` [PATCH v1 45/49] perf python: Move and clean up parallel-perf.py Ian Rogers
2026-09-20  5:21 ` [PATCH v1 46/49] perf: Remove libpython support and legacy Python scripts Ian Rogers
2026-09-20  5:21 ` [PATCH v1 47/49] perf Makefile: Update Python script installation path Ian Rogers
2026-09-20  5:21 ` [PATCH v1 48/49] perf script: Support standalone scripts and remove embedded scripting Ian Rogers
2026-09-20  5:21 ` [PATCH v1 49/49] perf Documentation: Update for standalone Python scripts Ian Rogers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b8e1b4ae6cb475a56bcd2c48130ac1f8ca036ddb.1789880842.git.irogers@google.com \
    --to=irogers@google.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=alice.mei.rogers@gmail.com \
    --cc=dapeng1.mi@linux.intel.com \
    --cc=james.clark@linaro.org \
    --cc=leo.yan@linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    --cc=tmricht@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®