perf python: Add wrapper for perf_data file abstraction

The perf_data struct is needed for session support.

Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Gemini:gemini-3.1-pro-preview
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>
This commit is contained in:
Ian Rogers
2026-06-15 18:15:31 -07:00
committed by Namhyung Kim
parent 674ca42f13
commit 27e59401c7

View File

@@ -6,6 +6,7 @@
#include <linux/err.h>
#include <poll.h>
#include <unistd.h>
#include <internal/lib.h>
#include <perf/cpumap.h>
@@ -14,6 +15,7 @@
#include "callchain.h"
#include "counts.h"
#include "data.h"
#include "event.h"
#include "evlist.h"
#include "evsel.h"
@@ -2462,6 +2464,121 @@ static PyObject *pyrf__metrics(PyObject *self, PyObject *args)
return list;
}
struct pyrf_data {
PyObject_HEAD
struct perf_data data;
};
static int pyrf_data__init(struct pyrf_data *pdata, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "path", "fd", NULL };
char *path = NULL;
int fd = -1;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|si", kwlist, &path, &fd))
return -1;
if (pdata->data.open)
perf_data__close(&pdata->data);
free((char *)pdata->data.path);
pdata->data.path = NULL;
if (fd != -1) {
struct stat st;
if (fstat(fd, &st) < 0 || !S_ISFIFO(st.st_mode)) {
PyErr_SetString(PyExc_ValueError,
"fd argument is only supported for pipes");
return -1;
}
if (!path)
path = "-";
else if (strcmp(path, "-") != 0) {
PyErr_SetString(PyExc_ValueError,
"path must be '-' when fd is provided");
return -1;
}
fd = dup(fd);
if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
} else if (path && strcmp(path, "-") == 0) {
fd = dup(0);
if (fd < 0) {
PyErr_SetFromErrno(PyExc_OSError);
return -1;
}
}
if (!path)
path = "perf.data";
pdata->data.path = strdup(path);
if (!pdata->data.path) {
if (fd != -1)
close(fd);
PyErr_NoMemory();
return -1;
}
pdata->data.mode = PERF_DATA_MODE_READ;
pdata->data.file.fd = fd;
if (perf_data__open(&pdata->data) < 0) {
PyErr_Format(PyExc_IOError, "Failed to open perf data: %s",
pdata->data.path ? pdata->data.path : "perf.data");
return -1;
}
return 0;
}
static void pyrf_data__delete(struct pyrf_data *pdata)
{
perf_data__close(&pdata->data);
free((char *)pdata->data.path);
Py_TYPE(pdata)->tp_free((PyObject *)pdata);
}
static PyObject *pyrf_data__str(PyObject *self)
{
const struct pyrf_data *pdata = (const struct pyrf_data *)self;
if (!pdata->data.path)
return PyUnicode_FromString("[uninitialized]");
return PyUnicode_FromString(pdata->data.path);
}
static PyObject *pyrf_data__new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
struct pyrf_data *pdata;
pdata = (struct pyrf_data *)PyType_GenericNew(type, args, kwargs);
if (pdata)
memset(&pdata->data, 0, sizeof(pdata->data));
return (PyObject *)pdata;
}
static const char pyrf_data__doc[] = PyDoc_STR("perf data file object.");
static PyTypeObject pyrf_data__type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "perf.data",
.tp_basicsize = sizeof(struct pyrf_data),
.tp_dealloc = (destructor)pyrf_data__delete,
.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
.tp_doc = pyrf_data__doc,
.tp_init = (initproc)pyrf_data__init,
.tp_repr = pyrf_data__str,
.tp_str = pyrf_data__str,
};
static int pyrf_data__setup_types(void)
{
pyrf_data__type.tp_new = pyrf_data__new;
return PyType_Ready(&pyrf_data__type);
}
static PyMethodDef perf__methods[] = {
{
.ml_name = "metrics",
@@ -2524,7 +2641,8 @@ PyMODINIT_FUNC PyInit_perf(void)
pyrf_cpu_map__setup_types() < 0 ||
pyrf_pmu_iterator__setup_types() < 0 ||
pyrf_pmu__setup_types() < 0 ||
pyrf_counts_values__setup_types() < 0)
pyrf_counts_values__setup_types() < 0 ||
pyrf_data__setup_types() < 0)
return module;
/* The page_size is placed in util object. */
@@ -2572,6 +2690,9 @@ PyMODINIT_FUNC PyInit_perf(void)
Py_INCREF(&pyrf_counts_values__type);
PyModule_AddObject(module, "counts_values", (PyObject *)&pyrf_counts_values__type);
Py_INCREF(&pyrf_data__type);
PyModule_AddObject(module, "data", (PyObject *)&pyrf_data__type);
dict = PyModule_GetDict(module);
if (dict == NULL)
goto error;