Allow all events on a PMU to be gathered, similar to how perf list gathers event information. An example usage: ``` $ python Python 3.12.9 (main, Feb 5 2025, 01:31:18) [GCC 14.2.0] on linux >>> import perf >>> for pmu in perf.pmus(): ... print(pmu.events()) ... [{'name': 'mem_load_retired.l3_hit', 'desc': 'Retired load instructions... ```
Unified · Split
| @@ -670,6 +670,71 @@ static PyObject *pyrf_pmu__name(PyObject *self) · 669 unmodified lines | ||
| 670 | 670 | return PyUnicode_FromString(ppmu->pmu->name); |
| 671 | 671 | } |
| 672 | 672 | |
| 673 | +static bool add_to_dict(PyObject *dict, const char *key, const char *value) | |
| 674 | +{ | |
| 675 | + PyObject *pkey, *pvalue; | |
| 676 | + bool ret; | |
| 677 | + | |
| 678 | + if (value == NULL) | |
| 679 | + return true; | |
| 680 | + | |
| 681 | + pkey = PyUnicode_FromString(key); | |
| 682 | + pvalue = PyUnicode_FromString(value); | |
| 683 | + | |
| 684 | + ret = pkey && pvalue && PyDict_SetItem(dict, pkey, pvalue) == 0; | |
| 685 | + Py_XDECREF(pkey); | |
| 686 | + Py_XDECREF(pvalue); | |
| 687 | + return ret; | |
| 688 | +} | |
| 689 | + | |
| 690 | +static int pyrf_pmu__events_cb(void *state, struct pmu_event_info *info) | |
| 691 | +{ | |
| 692 | + PyObject *py_list = state; | |
| 693 | + PyObject *dict = PyDict_New(); | |
| 694 | + | |
| 695 | + if (!dict) | |
| 696 | + return -ENOMEM; | |
| 697 | + | |
| 698 | + if (!add_to_dict(dict, "name", info->name) || | |
| 699 | + !add_to_dict(dict, "alias", info->alias) || | |
| 700 | + !add_to_dict(dict, "scale_unit", info->scale_unit) || | |
| 701 | + !add_to_dict(dict, "desc", info->desc) || | |
| 702 | + !add_to_dict(dict, "long_desc", info->long_desc) || | |
| 703 | + !add_to_dict(dict, "encoding_desc", info->encoding_desc) || | |
| 704 | + !add_to_dict(dict, "topic", info->topic) || | |
| 705 | + !add_to_dict(dict, "event_type_desc", info->event_type_desc) || | |
| 706 | + !add_to_dict(dict, "str", info->str) || | |
| 707 | + !add_to_dict(dict, "deprecated", info->deprecated ? "deprecated" : NULL) || | |
| 708 | + PyList_Append(py_list, dict) != 0) { | |
| 709 | + Py_DECREF(dict); | |
| 710 | + return -ENOMEM; | |
| 711 | + } | |
| 712 | + Py_DECREF(dict); | |
| 713 | + return 0; | |
| 714 | +} | |
| 715 | + | |
| 716 | +static PyObject *pyrf_pmu__events(PyObject *self) | |
| 717 | +{ | |
| 718 | + struct pyrf_pmu *ppmu = (void *)self; | |
| 719 | + PyObject *py_list = PyList_New(0); | |
| 720 | + int ret; | |
| 721 | + | |
| 722 | + if (!py_list) | |
| 723 | + return NULL; | |
| 724 | + | |
| 725 | + ret = perf_pmu__for_each_event(ppmu->pmu, | |
| 726 | + /*skip_duplicate_pmus=*/false, | |
| 727 | + py_list, | |
| 728 | + pyrf_pmu__events_cb); | |
| 729 | + if (ret) { | |
| 730 | + Py_DECREF(py_list); | |
| 731 | + errno = -ret; | |
| 732 | + PyErr_SetFromErrno(PyExc_OSError); | |
| 733 | + return NULL; | |
| 734 | + } | |
| 735 | + return py_list; | |
| 736 | +} | |
| 737 | + | |
| 673 | 738 | static PyObject *pyrf_pmu__repr(PyObject *self) |
| 674 | 739 | { |
| 675 | 740 | struct pyrf_pmu *ppmu = (void *)self; |
| @@ -680,6 +745,12 @@ static PyObject *pyrf_pmu__repr(PyObject *self) · 4 unmodified lines | ||
| 680 | 745 | static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object."); |
| 681 | 746 | |
| 682 | 747 | static PyMethodDef pyrf_pmu__methods[] = { |
| 748 | + { | |
| 749 | + .ml_name = "events", | |
| 750 | + .ml_meth = (PyCFunction)pyrf_pmu__events, | |
| 751 | + .ml_flags = METH_NOARGS, | |
| 752 | + .ml_doc = PyDoc_STR("Returns a sequence of events encoded as a dictionaries.") | |
| 753 | + }, | |
| 683 | 754 | { |
| 684 | 755 | .ml_name = "name", |
| 685 | 756 | .ml_meth = (PyCFunction)pyrf_pmu__name, |