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;  }  | 
