The metrics function returns a list dictionaries describing metrics as
strings mapping to strings, except for metric groups that are a string
mapping to a list of strings. For example:
```
>>> import perf
>>> perf.metrics()[0]
{'MetricGroup': ['Power'], 'MetricName': 'C10_Pkg_Residency',
'PMU': 'default_core', 'MetricExpr': 'cstate_pkg@c10\\-residency@ / TSC',
'ScaleUnit': '100%', 'BriefDescription': 'C10 residency percent per package'}
```
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
tools/perf/util/python.c | 83 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index bee7c8a69bad..a8ba1379cf21 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -2073,7 +2073,90 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
return result;
}
+static PyObject *pyrf__metrics_groups(const struct pmu_metric *pm)
+{
+ PyObject *groups = PyList_New(/*len=*/0);
+ const char *mg = pm->metric_group;
+
+ if (!groups)
+ return NULL;
+
+ while (mg) {
+ PyObject *val = NULL;
+ const char *sep = strchr(mg, ';');
+ size_t len = sep ? (size_t)(sep - mg) : strlen(mg);
+
+ if (len > 0) {
+ val = PyUnicode_FromStringAndSize(mg, len);
+ if (val)
+ PyList_Append(groups, val);
+
+ Py_XDECREF(val);
+ }
+ mg = sep ? sep + 1 : NULL;
+ }
+ return groups;
+}
+
+static int pyrf__metrics_cb(const struct pmu_metric *pm,
+ const struct pmu_metrics_table *table __maybe_unused,
+ void *vdata)
+{
+ PyObject *py_list = vdata;
+ PyObject *dict = PyDict_New();
+ PyObject *key = dict ? PyUnicode_FromString("MetricGroup") : NULL;
+ PyObject *value = key ? pyrf__metrics_groups(pm) : NULL;
+
+ if (!value || PyDict_SetItem(dict, key, value) != 0) {
+ Py_XDECREF(key);
+ Py_XDECREF(value);
+ Py_XDECREF(dict);
+ return -ENOMEM;
+ }
+
+ if (!add_to_dict(dict, "MetricName", pm->metric_name) ||
+ !add_to_dict(dict, "PMU", pm->pmu) ||
+ !add_to_dict(dict, "MetricExpr", pm->metric_expr) ||
+ !add_to_dict(dict, "MetricThreshold", pm->metric_threshold) ||
+ !add_to_dict(dict, "ScaleUnit", pm->unit) ||
+ !add_to_dict(dict, "Compat", pm->compat) ||
+ !add_to_dict(dict, "BriefDescription", pm->desc) ||
+ !add_to_dict(dict, "PublicDescription", pm->long_desc) ||
+ PyList_Append(py_list, dict) != 0) {
+ Py_DECREF(dict);
+ return -ENOMEM;
+ }
+ Py_DECREF(dict);
+ return 0;
+}
+
+static PyObject *pyrf__metrics(PyObject *self, PyObject *args)
+{
+ const struct pmu_metrics_table *table = pmu_metrics_table__find();
+ PyObject *list = PyList_New(/*len=*/0);
+ int ret;
+
+ if (!list)
+ return NULL;
+
+ ret = pmu_metrics_table__for_each_metric(table, pyrf__metrics_cb, list);
+ if (ret) {
+ Py_DECREF(list);
+ errno = -ret;
+ PyErr_SetFromErrno(PyExc_OSError);
+ return NULL;
+ }
+ return list;
+}
+
static PyMethodDef perf__methods[] = {
+ {
+ .ml_name = "metrics",
+ .ml_meth = (PyCFunction) pyrf__metrics,
+ .ml_flags = METH_NOARGS,
+ .ml_doc = PyDoc_STR(
+ "Returns a list of metrics represented as string values in dictionaries.")
+ },
{
.ml_name = "tracepoint",
.ml_meth = (PyCFunction) pyrf__tracepoint,
--
2.50.0.727.gbf7dc18ff4-goog
Hi Ian, On Wed, Jul 23, 2025 at 04:22:16PM -0700, Ian Rogers wrote: > The metrics function returns a list dictionaries describing metrics as > strings mapping to strings, except for metric groups that are a string > mapping to a list of strings. For example: > ``` > >>> import perf > >>> perf.metrics()[0] > {'MetricGroup': ['Power'], 'MetricName': 'C10_Pkg_Residency', > 'PMU': 'default_core', 'MetricExpr': 'cstate_pkg@c10\\-residency@ / TSC', > 'ScaleUnit': '100%', 'BriefDescription': 'C10 residency percent per package'} > ``` > > Signed-off-by: Ian Rogers <irogers@google.com> > Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> > --- > tools/perf/util/python.c | 83 ++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 83 insertions(+) > > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c > index bee7c8a69bad..a8ba1379cf21 100644 > --- a/tools/perf/util/python.c > +++ b/tools/perf/util/python.c > @@ -2073,7 +2073,90 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) > return result; > } > > +static PyObject *pyrf__metrics_groups(const struct pmu_metric *pm) > +{ > + PyObject *groups = PyList_New(/*len=*/0); > + const char *mg = pm->metric_group; > + > + if (!groups) > + return NULL; > + > + while (mg) { > + PyObject *val = NULL; > + const char *sep = strchr(mg, ';'); > + size_t len = sep ? (size_t)(sep - mg) : strlen(mg); > + > + if (len > 0) { > + val = PyUnicode_FromStringAndSize(mg, len); > + if (val) > + PyList_Append(groups, val); > + > + Py_XDECREF(val); > + } > + mg = sep ? sep + 1 : NULL; > + } > + return groups; > +} > + > +static int pyrf__metrics_cb(const struct pmu_metric *pm, > + const struct pmu_metrics_table *table __maybe_unused, > + void *vdata) > +{ > + PyObject *py_list = vdata; > + PyObject *dict = PyDict_New(); > + PyObject *key = dict ? PyUnicode_FromString("MetricGroup") : NULL; > + PyObject *value = key ? pyrf__metrics_groups(pm) : NULL; > + > + if (!value || PyDict_SetItem(dict, key, value) != 0) { > + Py_XDECREF(key); > + Py_XDECREF(value); > + Py_XDECREF(dict); > + return -ENOMEM; > + } > + > + if (!add_to_dict(dict, "MetricName", pm->metric_name) || > + !add_to_dict(dict, "PMU", pm->pmu) || > + !add_to_dict(dict, "MetricExpr", pm->metric_expr) || > + !add_to_dict(dict, "MetricThreshold", pm->metric_threshold) || > + !add_to_dict(dict, "ScaleUnit", pm->unit) || > + !add_to_dict(dict, "Compat", pm->compat) || > + !add_to_dict(dict, "BriefDescription", pm->desc) || > + !add_to_dict(dict, "PublicDescription", pm->long_desc) || > + PyList_Append(py_list, dict) != 0) { > + Py_DECREF(dict); > + return -ENOMEM; > + } > + Py_DECREF(dict); > + return 0; > +} > + > +static PyObject *pyrf__metrics(PyObject *self, PyObject *args) > +{ > + const struct pmu_metrics_table *table = pmu_metrics_table__find(); > + PyObject *list = PyList_New(/*len=*/0); > + int ret; > + > + if (!list) > + return NULL; > + > + ret = pmu_metrics_table__for_each_metric(table, pyrf__metrics_cb, list); > + if (ret) { > + Py_DECREF(list); > + errno = -ret; > + PyErr_SetFromErrno(PyExc_OSError); > + return NULL; > + } Could the system metric be supported? I notice that "perf list metric" shows some system metrics, but this python binding doesn't show these metrics: root@imx93evk:~/python# perf list metric List of pre-defined events (to be used in -e or -M): Metrics: imx93_bandwidth_usage.lpddr4x [bandwidth usage for lpddr4x evk board] imx93_ddr_read.all [bytes all masters read from ddr] imx93_ddr_write.all [bytes all masters write to ddr] root@imx93evk:~/python# python3 >>> import perf >>> perf.metrics() [] >>> If I add below code here, it can be shown too. pmu_for_each_sys_metric(pyrf__metrics_cb, list); Thanks, Xu Yang > + return list; > +} > + > static PyMethodDef perf__methods[] = { > + { > + .ml_name = "metrics", > + .ml_meth = (PyCFunction) pyrf__metrics, > + .ml_flags = METH_NOARGS, > + .ml_doc = PyDoc_STR( > + "Returns a list of metrics represented as string values in dictionaries.") > + }, > { > .ml_name = "tracepoint", > .ml_meth = (PyCFunction) pyrf__tracepoint, > -- > 2.50.0.727.gbf7dc18ff4-goog >
On Thu, Jul 24, 2025 at 10:48 PM Xu Yang <xu.yang_2@nxp.com> wrote: > > Hi Ian, > > On Wed, Jul 23, 2025 at 04:22:16PM -0700, Ian Rogers wrote: > > The metrics function returns a list dictionaries describing metrics as > > strings mapping to strings, except for metric groups that are a string > > mapping to a list of strings. For example: > > ``` > > >>> import perf > > >>> perf.metrics()[0] > > {'MetricGroup': ['Power'], 'MetricName': 'C10_Pkg_Residency', > > 'PMU': 'default_core', 'MetricExpr': 'cstate_pkg@c10\\-residency@ / TSC', > > 'ScaleUnit': '100%', 'BriefDescription': 'C10 residency percent per package'} > > ``` > > > > Signed-off-by: Ian Rogers <irogers@google.com> > > Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> > > --- > > tools/perf/util/python.c | 83 ++++++++++++++++++++++++++++++++++++++++ > > 1 file changed, 83 insertions(+) > > > > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c > > index bee7c8a69bad..a8ba1379cf21 100644 > > --- a/tools/perf/util/python.c > > +++ b/tools/perf/util/python.c > > @@ -2073,7 +2073,90 @@ static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args) > > return result; > > } > > > > +static PyObject *pyrf__metrics_groups(const struct pmu_metric *pm) > > +{ > > + PyObject *groups = PyList_New(/*len=*/0); > > + const char *mg = pm->metric_group; > > + > > + if (!groups) > > + return NULL; > > + > > + while (mg) { > > + PyObject *val = NULL; > > + const char *sep = strchr(mg, ';'); > > + size_t len = sep ? (size_t)(sep - mg) : strlen(mg); > > + > > + if (len > 0) { > > + val = PyUnicode_FromStringAndSize(mg, len); > > + if (val) > > + PyList_Append(groups, val); > > + > > + Py_XDECREF(val); > > + } > > + mg = sep ? sep + 1 : NULL; > > + } > > + return groups; > > +} > > + > > +static int pyrf__metrics_cb(const struct pmu_metric *pm, > > + const struct pmu_metrics_table *table __maybe_unused, > > + void *vdata) > > +{ > > + PyObject *py_list = vdata; > > + PyObject *dict = PyDict_New(); > > + PyObject *key = dict ? PyUnicode_FromString("MetricGroup") : NULL; > > + PyObject *value = key ? pyrf__metrics_groups(pm) : NULL; > > + > > + if (!value || PyDict_SetItem(dict, key, value) != 0) { > > + Py_XDECREF(key); > > + Py_XDECREF(value); > > + Py_XDECREF(dict); > > + return -ENOMEM; > > + } > > + > > + if (!add_to_dict(dict, "MetricName", pm->metric_name) || > > + !add_to_dict(dict, "PMU", pm->pmu) || > > + !add_to_dict(dict, "MetricExpr", pm->metric_expr) || > > + !add_to_dict(dict, "MetricThreshold", pm->metric_threshold) || > > + !add_to_dict(dict, "ScaleUnit", pm->unit) || > > + !add_to_dict(dict, "Compat", pm->compat) || > > + !add_to_dict(dict, "BriefDescription", pm->desc) || > > + !add_to_dict(dict, "PublicDescription", pm->long_desc) || > > + PyList_Append(py_list, dict) != 0) { > > + Py_DECREF(dict); > > + return -ENOMEM; > > + } > > + Py_DECREF(dict); > > + return 0; > > +} > > + > > +static PyObject *pyrf__metrics(PyObject *self, PyObject *args) > > +{ > > + const struct pmu_metrics_table *table = pmu_metrics_table__find(); > > + PyObject *list = PyList_New(/*len=*/0); > > + int ret; > > + > > + if (!list) > > + return NULL; > > + > > + ret = pmu_metrics_table__for_each_metric(table, pyrf__metrics_cb, list); > > + if (ret) { > > + Py_DECREF(list); > > + errno = -ret; > > + PyErr_SetFromErrno(PyExc_OSError); > > + return NULL; > > + } > > Could the system metric be supported? > > I notice that "perf list metric" shows some system metrics, but this python > binding doesn't show these metrics: > > root@imx93evk:~/python# perf list metric > > List of pre-defined events (to be used in -e or -M): > > Metrics: > > imx93_bandwidth_usage.lpddr4x > [bandwidth usage for lpddr4x evk board] > imx93_ddr_read.all > [bytes all masters read from ddr] > imx93_ddr_write.all > [bytes all masters write to ddr] > > root@imx93evk:~/python# python3 > >>> import perf > >>> perf.metrics() > [] > >>> > > If I add below code here, it can be shown too. > > pmu_for_each_sys_metric(pyrf__metrics_cb, list); Good suggestion, I'll check it out and add for v9. Thanks, Ian > Thanks, > Xu Yang > > > + return list; > > +} > > + > > static PyMethodDef perf__methods[] = { > > + { > > + .ml_name = "metrics", > > + .ml_meth = (PyCFunction) pyrf__metrics, > > + .ml_flags = METH_NOARGS, > > + .ml_doc = PyDoc_STR( > > + "Returns a list of metrics represented as string values in dictionaries.") > > + }, > > { > > .ml_name = "tracepoint", > > .ml_meth = (PyCFunction) pyrf__tracepoint, > > -- > > 2.50.0.727.gbf7dc18ff4-goog > >
© 2016 - 2025 Red Hat, Inc.