[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250313075126.547881-3-gautam@linux.ibm.com>
Date: Thu, 13 Mar 2025 13:21:23 +0530
From: Gautam Menghani <gautam@...ux.ibm.com>
To: peterz@...radead.org, mingo@...hat.com, acme@...nel.org,
namhyung@...nel.org, mark.rutland@....com,
alexander.shishkin@...ux.intel.com, jolsa@...nel.org,
irogers@...gle.com, adrian.hunter@...el.com, kan.liang@...ux.intel.com
Cc: Gautam Menghani <gautam@...ux.ibm.com>, linux-perf-users@...r.kernel.org,
linux-kernel@...r.kernel.org,
Madhavan Srinivasan <maddy@...ux.ibm.com>
Subject: [RFC PATCH 2/3] libperf: Introduce a C extension module for python
Create a C extension module for libperf that will be used by python to
call the libperf functions.
Co-developed-by: Madhavan Srinivasan <maddy@...ux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@...ux.ibm.com>
Signed-off-by: Gautam Menghani <gautam@...ux.ibm.com>
---
tools/lib/perf/Build | 1 +
tools/lib/perf/Makefile | 12 +-
tools/lib/perf/libperf.map | 1 +
tools/lib/perf/py_perf.c | 261 +++++++++++++++++++++++++++++++++++++
4 files changed, 273 insertions(+), 2 deletions(-)
create mode 100644 tools/lib/perf/py_perf.c
diff --git a/tools/lib/perf/Build b/tools/lib/perf/Build
index e8f5b7fb9973..4869da30ffb5 100644
--- a/tools/lib/perf/Build
+++ b/tools/lib/perf/Build
@@ -7,6 +7,7 @@ libperf-y += mmap.o
libperf-y += zalloc.o
libperf-y += xyarray.o
libperf-y += lib.o
+libperf-y += py_perf.o
$(OUTPUT)zalloc.o: ../../lib/zalloc.c FORCE
$(call rule_mkdir)
diff --git a/tools/lib/perf/Makefile b/tools/lib/perf/Makefile
index e9a7ac2c062e..8e16492af882 100644
--- a/tools/lib/perf/Makefile
+++ b/tools/lib/perf/Makefile
@@ -48,20 +48,28 @@ else
CFLAGS := -g -Wall
endif
+# Check Python.h path
+ifeq (,$(shell which python-config))
+ $(error "Consider installing python-dev or python-devel")
+endif
+
+PYTHON_INCLUDE = $(shell python-config --includes)
+
INCLUDES = \
-I$(srctree)/tools/lib/perf/include \
-I$(srctree)/tools/lib/ \
-I$(srctree)/tools/include \
-I$(srctree)/tools/arch/$(SRCARCH)/include/ \
-I$(srctree)/tools/arch/$(SRCARCH)/include/uapi \
--I$(srctree)/tools/include/uapi
+-I$(srctree)/tools/include/uapi \
+-I$(PYTHON_INCLUDE)
# Append required CFLAGS
override CFLAGS += $(EXTRA_WARNINGS)
override CFLAGS += -Werror -Wall
override CFLAGS += -fPIC
override CFLAGS += $(INCLUDES)
-override CFLAGS += -fvisibility=hidden
+override CFLAGS += -fvisibility=hidden -Wno-redundant-decls
all:
diff --git a/tools/lib/perf/libperf.map b/tools/lib/perf/libperf.map
index fdd8304fe9d0..0488c0591404 100644
--- a/tools/lib/perf/libperf.map
+++ b/tools/lib/perf/libperf.map
@@ -57,6 +57,7 @@ LIBPERF_0.0.1 {
perf_mmap__read_done;
perf_mmap__read_event;
perf_counts_values__scale;
+ PyInit_libperf;
local:
*;
};
diff --git a/tools/lib/perf/py_perf.c b/tools/lib/perf/py_perf.c
new file mode 100644
index 000000000000..cf0fcb8cc6c1
--- /dev/null
+++ b/tools/lib/perf/py_perf.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include "include/perf/py_perf.h"
+#include <stdlib.h>
+#include <perf/threadmap.h>
+#include <perf/py_perf.h>
+#include <errno.h>
+#include <internal/threadmap.h>
+
+static PyObject *program_perf_thread_map__new_dummy(PyObject *self, PyObject *args)
+{
+ py_perf_thread_map *pythread_map = PyObject_New(py_perf_thread_map, &py_perf_thread_map_type);
+
+ pythread_map->thread_map = perf_thread_map__new_dummy();
+ if (!pythread_map->thread_map) {
+ Py_DECREF(pythread_map);
+ return Py_None;
+ }
+
+ return Py_BuildValue("O", pythread_map);
+}
+
+static PyObject *program_perf_thread_map__set_pid(PyObject *self, PyObject *args)
+{
+ py_perf_thread_map *pythread_map = NULL;
+ int idx, pid;
+
+ if (!PyArg_ParseTuple(args, "Oii", &pythread_map, &idx, &pid)) {
+ return NULL;
+ }
+
+ perf_thread_map__set_pid(pythread_map->thread_map, idx, pid);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evlist__new(PyObject *self, PyObject *args)
+{
+ py_perf_evlist *pyperf_evlist = PyObject_New(py_perf_evlist, &py_perf_evlist_type);
+
+ pyperf_evlist->evlist = perf_evlist__new();
+ if (!pyperf_evlist->evlist) {
+ Py_DECREF(pyperf_evlist);
+ return Py_None;
+ }
+
+ return Py_BuildValue("O", pyperf_evlist);
+}
+
+static PyObject *program_perf_evsel__new(PyObject *self, PyObject *args)
+{
+ struct perf_event_attr *attr;
+ PyObject *py_attr;
+ py_perf_evsel *pyperf_evsel = PyObject_New(py_perf_evsel, &py_perf_evsel_type);
+
+ if (!PyArg_ParseTuple(args, "O", &py_attr)) {
+ return NULL;
+ }
+
+ attr = (py_attr == Py_None)? NULL: ((py_perf_event_attr *)py_attr)->attr;
+ pyperf_evsel->evsel = perf_evsel__new(attr);
+ if (!pyperf_evsel->evsel) {
+ Py_DECREF(pyperf_evsel);
+ return Py_None;
+ }
+
+ return Py_BuildValue("O", pyperf_evsel);
+}
+
+static PyObject *program_perf_evlist__add(PyObject *self, PyObject *args)
+{
+ struct perf_evsel *evsel;
+ struct perf_evlist *evlist;
+ PyObject *pyevlist, *pyevsel;
+
+ if (!PyArg_ParseTuple(args, "OO", &pyevlist, &pyevsel)) {
+ return NULL;
+ }
+
+ evsel = (pyevsel == Py_None)? NULL: ((py_perf_evsel *)pyevsel)->evsel;
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ perf_evlist__add(evlist, evsel);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evlist__set_maps(PyObject *self, PyObject *args)
+{
+ struct perf_thread_map *thread_map;
+ struct perf_evlist *evlist;
+ struct perf_cpu_map *cpu_map;
+ PyObject *pyevlist, *pythread_map, *pycpu_map;
+
+ if (!PyArg_ParseTuple(args, "OOO", &pyevlist, &pycpu_map, &pythread_map)) {
+ return NULL;
+ }
+
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ cpu_map = (pycpu_map == Py_None)? NULL: ((py_perf_cpu_map *)pycpu_map)->map;
+ thread_map = (pythread_map == Py_None)? NULL: ((py_perf_thread_map *)pythread_map)->thread_map;
+ perf_evlist__set_maps(evlist, cpu_map, thread_map);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evlist__open(PyObject *self, PyObject *args)
+{
+ struct perf_evlist *evlist;
+ PyObject *pyevlist;
+
+ if (!PyArg_ParseTuple(args, "O", &pyevlist)) {
+ return NULL;
+ }
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+
+ return Py_BuildValue("i", perf_evlist__open(evlist));
+}
+
+static PyObject *program_perf_evlist__enable(PyObject *self, PyObject *args)
+{
+ struct perf_evlist *evlist;
+ PyObject *pyevlist;
+
+ if (!PyArg_ParseTuple(args, "O", &pyevlist)) {
+ return NULL;
+ }
+
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ perf_evlist__enable(evlist);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evlist__disable(PyObject *self, PyObject *args)
+{
+ struct perf_evlist *evlist;
+ PyObject *pyevlist;
+
+ if (!PyArg_ParseTuple(args, "O", &pyevlist)) {
+ return NULL;
+ }
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ perf_evlist__disable(evlist);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evsel__read(PyObject *self, PyObject *args)
+{
+ PyObject *pyevsel, *pyperf_counts_values;
+ struct perf_evsel *evsel;
+ struct perf_counts_values *values;
+ int cpu_map_idx, thread;
+
+ if (!PyArg_ParseTuple(args, "OiiO", &pyevsel, &cpu_map_idx, &thread, &pyperf_counts_values)) {
+ return NULL;
+ }
+ evsel = (pyevsel == Py_None)? NULL: ((py_perf_evsel *)pyevsel)->evsel;
+ values = (pyevsel == Py_None)? NULL: ((py_perf_counts_values *)pyperf_counts_values)->values;
+
+ return Py_BuildValue("i", perf_evsel__read(evsel, cpu_map_idx, thread, values));
+}
+
+static PyObject *program_perf_evlist__close(PyObject *self, PyObject *args)
+{
+ struct perf_evlist *evlist;
+ PyObject *pyevlist;
+
+ if (!PyArg_ParseTuple(args, "O", &pyevlist)) {
+ return NULL;
+ }
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ perf_evlist__close(evlist);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_evlist__delete(PyObject *self, PyObject *args)
+{
+ struct perf_evlist *evlist;
+ PyObject *pyevlist;
+
+ if (!PyArg_ParseTuple(args, "O", &pyevlist)) {
+ return NULL;
+ }
+ evlist = (pyevlist == Py_None)? NULL: ((py_perf_evlist *)pyevlist)->evlist;
+ perf_evlist__delete(evlist);
+
+ return Py_None;
+}
+
+static PyObject *program_perf_thread_map__put(PyObject *self, PyObject *args)
+{
+ struct perf_thread_map *map;
+ PyObject *pyperf_thread_map;
+
+ if (!PyArg_ParseTuple(args, "O", &pyperf_thread_map)) {
+ return NULL;
+ }
+ map = (pyperf_thread_map == Py_None)? NULL: ((py_perf_thread_map *)pyperf_thread_map)->thread_map;
+ perf_thread_map__put(map);
+
+ return Py_None;
+}
+
+static int libperf_print(enum libperf_print_level level,
+ const char *fmt, va_list ap)
+{
+ return vfprintf(stderr, fmt, ap);
+}
+
+static PyObject *program_libperf_init(PyObject *self, PyObject *args)
+{
+ libperf_init(libperf_print);
+ return Py_None;
+}
+
+PyMethodDef libperf_methods[] = {
+ {"perf_thread_map__new_dummy", program_perf_thread_map__new_dummy, METH_VARARGS, "Create a dummy thread map function variable"},
+ {"perf_thread_map__set_pid", program_perf_thread_map__set_pid, METH_VARARGS, "Set PID for a thread map"},
+ {"perf_evlist__new", program_perf_evlist__new, METH_VARARGS, "Create a perf evlist"},
+ {"perf_evsel__new", program_perf_evsel__new, METH_VARARGS, "Create a perf evsel"},
+ {"perf_evlist__add", program_perf_evlist__add, METH_VARARGS, "Add evsel to evlist"},
+ {"perf_evlist__set_maps", program_perf_evlist__set_maps, METH_VARARGS, "perf_evlist__set_maps"},
+ {"perf_evlist__open", program_perf_evlist__open, METH_VARARGS, "perf_evlist__set_maps"},
+ {"perf_evlist__enable", program_perf_evlist__enable, METH_VARARGS, "perf_evlist__enable"},
+ {"perf_evlist__disable", program_perf_evlist__disable, METH_VARARGS, "perf_evlist__disable"},
+ {"perf_evsel__read", program_perf_evsel__read, METH_VARARGS, "perf_evsel__read"},
+ {"perf_evlist__close", program_perf_evlist__close, METH_VARARGS, "perf_evlist__close"},
+ {"perf_evlist__delete", program_perf_evlist__delete, METH_VARARGS, "perf_evlist__delete"},
+ {"perf_thread_map__put", program_perf_thread_map__put, METH_VARARGS, "perf_thread_map__put"},
+ {"libperf_init", program_libperf_init, METH_VARARGS, "libperf init"},
+ {NULL, NULL, 0, NULL}
+};
+
+struct PyModuleDef libperf = {
+ PyModuleDef_HEAD_INIT,
+ "libperf",
+ "Extension module to expose libperf to python",
+ -1,
+ libperf_methods
+};
+
+PyMODINIT_FUNC PyInit_libperf(void) {
+ PyObject *m = PyModule_Create(&libperf);
+
+ if (!m)
+ return NULL;
+
+ python_push_type("py_perf_thread_map", m, &py_perf_thread_map_type);
+ python_push_type("py_perf_evlist", m, &py_perf_evlist_type);
+ python_push_type("evlist_iterator", m, &py_perf_evlist_iterator_type);
+ python_push_type("py_perf_evsel", m, &py_perf_evsel_type);
+ python_push_type("py_perf_cpu_map", m, &py_perf_cpu_map_type);
+ python_push_type("py_perf_event_attr", m, &py_perf_event_attr_type);
+ python_push_type("py_perf_counts_values", m, &py_perf_counts_values_type);
+
+ PyModule_AddObject(m, "perf_event_attr", (PyObject *) & py_perf_event_attr_type);
+ PyModule_AddObject(m, "perf_counts_values", (PyObject *) & py_perf_counts_values_type);
+
+ return m;
+}
--
2.47.0
Powered by blists - more mailing lists