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 | return PyUnicode_FromString(ppmu->pmu->name); | 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 | static PyObject *pyrf_pmu__repr(PyObject *self) | 738 | static PyObject *pyrf_pmu__repr(PyObject *self) |
| 674 | { | 739 | { |
| 675 | struct pyrf_pmu *ppmu = (void *)self; | 740 | struct pyrf_pmu *ppmu = (void *)self; |
| @@ -680,6 +745,12 @@ static PyObject *pyrf_pmu__repr(PyObject *self) · 4 unmodified lines | |||
| 680 | static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object."); | 745 | static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object."); |
| 681 | 746 | ||
| 682 | static PyMethodDef pyrf_pmu__methods[] = { | 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 | .ml_name = "name", | 755 | .ml_name = "name", |
| 685 | .ml_meth = (PyCFunction)pyrf_pmu__name, | 756 | .ml_meth = (PyCFunction)pyrf_pmu__name, |