lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ