diff options
Diffstat (limited to 'tools/perf/util/python.c')
-rw-r--r-- | tools/perf/util/python.c | 145 |
1 files changed, 129 insertions, 16 deletions
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 321c333877fa..ea77bea0306f 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -10,6 +10,7 @@ #endif #include <perf/mmap.h> #include "callchain.h" +#include "counts.h" #include "evlist.h" #include "evsel.h" #include "event.h" @@ -18,6 +19,7 @@ #include "strbuf.h" #include "thread_map.h" #include "trace-event.h" +#include "metricgroup.h" #include "mmap.h" #include "util/sample.h" #include <internal/lib.h> @@ -335,7 +337,6 @@ tracepoint_field(const struct pyrf_event *pe, struct tep_format_field *field) static PyObject* get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) { - const char *str = _PyUnicode_AsString(PyObject_Str(attr_name)); struct evsel *evsel = pevent->evsel; struct tep_event *tp_format = evsel__tp_format(evsel); struct tep_format_field *field; @@ -343,7 +344,18 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) if (IS_ERR_OR_NULL(tp_format)) return NULL; + PyObject *obj = PyObject_Str(attr_name); + if (obj == NULL) + return NULL; + + const char *str = PyUnicode_AsUTF8(obj); + if (str == NULL) { + Py_DECREF(obj); + return NULL; + } + field = tep_find_any_field(tp_format, str); + Py_DECREF(obj); return field ? tracepoint_field(pevent, field) : NULL; } #endif /* HAVE_LIBTRACEEVENT */ @@ -527,8 +539,10 @@ static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i) { struct pyrf_cpu_map *pcpus = (void *)obj; - if (i >= perf_cpu_map__nr(pcpus->cpus)) + if (i >= perf_cpu_map__nr(pcpus->cpus)) { + PyErr_SetString(PyExc_IndexError, "Index out of range"); return NULL; + } return Py_BuildValue("i", perf_cpu_map__cpu(pcpus->cpus, i).cpu); } @@ -566,14 +580,14 @@ struct pyrf_thread_map { static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, PyObject *args, PyObject *kwargs) { - static char *kwlist[] = { "pid", "tid", "uid", NULL }; - int pid = -1, tid = -1, uid = UINT_MAX; + static char *kwlist[] = { "pid", "tid", NULL }; + int pid = -1, tid = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii", - kwlist, &pid, &tid, &uid)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", + kwlist, &pid, &tid)) return -1; - pthreads->threads = thread_map__new(pid, tid, uid); + pthreads->threads = thread_map__new(pid, tid); if (pthreads->threads == NULL) return -1; return 0; @@ -596,8 +610,10 @@ static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i) { struct pyrf_thread_map *pthreads = (void *)obj; - if (i >= perf_thread_map__nr(pthreads->threads)) + if (i >= perf_thread_map__nr(pthreads->threads)) { + PyErr_SetString(PyExc_IndexError, "Index out of range"); return NULL; + } return Py_BuildValue("i", perf_thread_map__pid(pthreads->threads, i)); } @@ -888,12 +904,38 @@ static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel) return (PyObject *)pthread_map; } +/* + * Ensure evsel's counts and prev_raw_counts are allocated, the latter + * used by tool PMUs to compute the cumulative count as expected by + * stat's process_counter_values. + */ +static int evsel__ensure_counts(struct evsel *evsel) +{ + int nthreads, ncpus; + + if (evsel->counts != NULL) + return 0; + + nthreads = perf_thread_map__nr(evsel->core.threads); + ncpus = perf_cpu_map__nr(evsel->core.cpus); + + evsel->counts = perf_counts__new(ncpus, nthreads); + if (evsel->counts == NULL) + return -ENOMEM; + + evsel->prev_raw_counts = perf_counts__new(ncpus, nthreads); + if (evsel->prev_raw_counts == NULL) + return -ENOMEM; + + return 0; +} + static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { struct evsel *evsel = &pevsel->evsel; int cpu = 0, cpu_idx, thread = 0, thread_idx; - struct perf_counts_values counts; + struct perf_counts_values *old_count, *new_count; struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values, &pyrf_counts_values__type); @@ -909,13 +951,27 @@ static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel, return NULL; } thread_idx = perf_thread_map__idx(evsel->core.threads, thread); - if (cpu_idx < 0) { + if (thread_idx < 0) { PyErr_Format(PyExc_TypeError, "Thread %d is not part of evsel's threads", thread); return NULL; } - perf_evsel__read(&(evsel->core), cpu_idx, thread_idx, &counts); - count_values->values = counts; + + if (evsel__ensure_counts(evsel)) + return PyErr_NoMemory(); + + /* Set up pointers to the old and newly read counter values. */ + old_count = perf_counts(evsel->prev_raw_counts, cpu_idx, thread_idx); + new_count = perf_counts(evsel->counts, cpu_idx, thread_idx); + /* Update the value in evsel->counts. */ + evsel__read_counter(evsel, cpu_idx, thread_idx); + /* Copy the value and turn it into the delta from old_count. */ + count_values->values = *new_count; + count_values->values.val -= old_count->val; + count_values->values.ena -= old_count->ena; + count_values->values.run -= old_count->run; + /* Save the new count over the old_count for the next read. */ + *old_count = *new_count; return (PyObject *)count_values; } @@ -924,10 +980,7 @@ static PyObject *pyrf_evsel__str(PyObject *self) struct pyrf_evsel *pevsel = (void *)self; struct evsel *evsel = &pevsel->evsel; - if (!evsel->pmu) - return PyUnicode_FromFormat("evsel(%s)", evsel__name(evsel)); - - return PyUnicode_FromFormat("evsel(%s/%s/)", evsel->pmu->name, evsel__name(evsel)); + return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel)); } static PyMethodDef pyrf_evsel__methods[] = { @@ -1529,10 +1582,37 @@ static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel) return (PyObject *)pevsel; } +static int evlist__pos(struct evlist *evlist, struct evsel *evsel) +{ + struct evsel *pos; + int idx = 0; + + evlist__for_each_entry(evlist, pos) { + if (evsel == pos) + return idx; + idx++; + } + return -1; +} + +static struct evsel *evlist__at(struct evlist *evlist, int idx) +{ + struct evsel *pos; + int idx2 = 0; + + evlist__for_each_entry(evlist, pos) { + if (idx == idx2) + return pos; + idx2++; + } + return NULL; +} + static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist) { struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type); struct evsel *pos; + struct rb_node *node; if (!pevlist) return NULL; @@ -1544,6 +1624,39 @@ static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist) evlist__add(&pevlist->evlist, &pevsel->evsel); } + evlist__for_each_entry(&pevlist->evlist, pos) { + struct evsel *leader = evsel__leader(pos); + + if (pos != leader) { + int idx = evlist__pos(evlist, leader); + + if (idx >= 0) + evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx)); + else if (leader == NULL) + evsel__set_leader(pos, pos); + } + } + metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL, + &pevlist->evlist.metric_events, + &evlist->metric_events); + for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node; + node = rb_next(node)) { + struct metric_event *me = container_of(node, struct metric_event, nd); + struct list_head *mpos; + int idx = evlist__pos(evlist, me->evsel); + + if (idx >= 0) + me->evsel = evlist__at(&pevlist->evlist, idx); + list_for_each(mpos, &me->head) { + struct metric_expr *e = container_of(mpos, struct metric_expr, nd); + + for (int j = 0; e->metric_events[j]; j++) { + idx = evlist__pos(evlist, e->metric_events[j]); + if (idx >= 0) + e->metric_events[j] = evlist__at(&pevlist->evlist, idx); + } + } + } return (PyObject *)pevlist; } |