1 // SPDX-License-Identifier: GPL-2.0
2 #include <Python.h>
3 #include <structmember.h>
4 #include <inttypes.h>
5 #include <poll.h>
6 #include <linux/err.h>
7 #include <perf/cpumap.h>
8 #ifdef HAVE_LIBTRACEEVENT
9 #include <event-parse.h>
10 #endif
11 #include <perf/mmap.h>
12 #include "callchain.h"
13 #include "counts.h"
14 #include "evlist.h"
15 #include "evsel.h"
16 #include "event.h"
17 #include "expr.h"
18 #include "print_binary.h"
19 #include "record.h"
20 #include "strbuf.h"
21 #include "thread_map.h"
22 #include "tp_pmu.h"
23 #include "trace-event.h"
24 #include "metricgroup.h"
25 #include "mmap.h"
26 #include "util/sample.h"
27 #include <internal/lib.h>
28
29 PyMODINIT_FUNC PyInit_perf(void);
30
31 #define member_def(type, member, ptype, help) \
32 { #member, ptype, \
33 offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
34 0, help }
35
36 #define sample_member_def(name, member, ptype, help) \
37 { #name, ptype, \
38 offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \
39 0, help }
40
41 struct pyrf_event {
42 PyObject_HEAD
43 struct evsel *evsel;
44 struct perf_sample sample;
45 union perf_event event;
46 };
47
48 #define sample_members \
49 sample_member_def(sample_ip, ip, T_ULONGLONG, "event ip"), \
50 sample_member_def(sample_pid, pid, T_INT, "event pid"), \
51 sample_member_def(sample_tid, tid, T_INT, "event tid"), \
52 sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"), \
53 sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), \
54 sample_member_def(sample_id, id, T_ULONGLONG, "event id"), \
55 sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \
56 sample_member_def(sample_period, period, T_ULONGLONG, "event period"), \
57 sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
58
59 static const char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
60
61 static PyMemberDef pyrf_mmap_event__members[] = {
62 sample_members
63 member_def(perf_event_header, type, T_UINT, "event type"),
64 member_def(perf_event_header, misc, T_UINT, "event misc"),
65 member_def(perf_record_mmap, pid, T_UINT, "event pid"),
66 member_def(perf_record_mmap, tid, T_UINT, "event tid"),
67 member_def(perf_record_mmap, start, T_ULONGLONG, "start of the map"),
68 member_def(perf_record_mmap, len, T_ULONGLONG, "map length"),
69 member_def(perf_record_mmap, pgoff, T_ULONGLONG, "page offset"),
70 member_def(perf_record_mmap, filename, T_STRING_INPLACE, "backing store"),
71 { .name = NULL, },
72 };
73
pyrf_mmap_event__repr(const struct pyrf_event * pevent)74 static PyObject *pyrf_mmap_event__repr(const struct pyrf_event *pevent)
75 {
76 PyObject *ret;
77 char *s;
78
79 if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRI_lx64 ", "
80 "length: %#" PRI_lx64 ", offset: %#" PRI_lx64 ", "
81 "filename: %s }",
82 pevent->event.mmap.pid, pevent->event.mmap.tid,
83 pevent->event.mmap.start, pevent->event.mmap.len,
84 pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) {
85 ret = PyErr_NoMemory();
86 } else {
87 ret = PyUnicode_FromString(s);
88 free(s);
89 }
90 return ret;
91 }
92
93 static PyTypeObject pyrf_mmap_event__type = {
94 PyVarObject_HEAD_INIT(NULL, 0)
95 .tp_name = "perf.mmap_event",
96 .tp_basicsize = sizeof(struct pyrf_event),
97 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
98 .tp_doc = pyrf_mmap_event__doc,
99 .tp_members = pyrf_mmap_event__members,
100 .tp_repr = (reprfunc)pyrf_mmap_event__repr,
101 };
102
103 static const char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object.");
104
105 static PyMemberDef pyrf_task_event__members[] = {
106 sample_members
107 member_def(perf_event_header, type, T_UINT, "event type"),
108 member_def(perf_record_fork, pid, T_UINT, "event pid"),
109 member_def(perf_record_fork, ppid, T_UINT, "event ppid"),
110 member_def(perf_record_fork, tid, T_UINT, "event tid"),
111 member_def(perf_record_fork, ptid, T_UINT, "event ptid"),
112 member_def(perf_record_fork, time, T_ULONGLONG, "timestamp"),
113 { .name = NULL, },
114 };
115
pyrf_task_event__repr(const struct pyrf_event * pevent)116 static PyObject *pyrf_task_event__repr(const struct pyrf_event *pevent)
117 {
118 return PyUnicode_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
119 "ptid: %u, time: %" PRI_lu64 "}",
120 pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit",
121 pevent->event.fork.pid,
122 pevent->event.fork.ppid,
123 pevent->event.fork.tid,
124 pevent->event.fork.ptid,
125 pevent->event.fork.time);
126 }
127
128 static PyTypeObject pyrf_task_event__type = {
129 PyVarObject_HEAD_INIT(NULL, 0)
130 .tp_name = "perf.task_event",
131 .tp_basicsize = sizeof(struct pyrf_event),
132 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
133 .tp_doc = pyrf_task_event__doc,
134 .tp_members = pyrf_task_event__members,
135 .tp_repr = (reprfunc)pyrf_task_event__repr,
136 };
137
138 static const char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object.");
139
140 static PyMemberDef pyrf_comm_event__members[] = {
141 sample_members
142 member_def(perf_event_header, type, T_UINT, "event type"),
143 member_def(perf_record_comm, pid, T_UINT, "event pid"),
144 member_def(perf_record_comm, tid, T_UINT, "event tid"),
145 member_def(perf_record_comm, comm, T_STRING_INPLACE, "process name"),
146 { .name = NULL, },
147 };
148
pyrf_comm_event__repr(const struct pyrf_event * pevent)149 static PyObject *pyrf_comm_event__repr(const struct pyrf_event *pevent)
150 {
151 return PyUnicode_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
152 pevent->event.comm.pid,
153 pevent->event.comm.tid,
154 pevent->event.comm.comm);
155 }
156
157 static PyTypeObject pyrf_comm_event__type = {
158 PyVarObject_HEAD_INIT(NULL, 0)
159 .tp_name = "perf.comm_event",
160 .tp_basicsize = sizeof(struct pyrf_event),
161 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
162 .tp_doc = pyrf_comm_event__doc,
163 .tp_members = pyrf_comm_event__members,
164 .tp_repr = (reprfunc)pyrf_comm_event__repr,
165 };
166
167 static const char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object.");
168
169 static PyMemberDef pyrf_throttle_event__members[] = {
170 sample_members
171 member_def(perf_event_header, type, T_UINT, "event type"),
172 member_def(perf_record_throttle, time, T_ULONGLONG, "timestamp"),
173 member_def(perf_record_throttle, id, T_ULONGLONG, "event id"),
174 member_def(perf_record_throttle, stream_id, T_ULONGLONG, "event stream id"),
175 { .name = NULL, },
176 };
177
pyrf_throttle_event__repr(const struct pyrf_event * pevent)178 static PyObject *pyrf_throttle_event__repr(const struct pyrf_event *pevent)
179 {
180 const struct perf_record_throttle *te = (const struct perf_record_throttle *)
181 (&pevent->event.header + 1);
182
183 return PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRI_lu64 ", id: %" PRI_lu64
184 ", stream_id: %" PRI_lu64 " }",
185 pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un",
186 te->time, te->id, te->stream_id);
187 }
188
189 static PyTypeObject pyrf_throttle_event__type = {
190 PyVarObject_HEAD_INIT(NULL, 0)
191 .tp_name = "perf.throttle_event",
192 .tp_basicsize = sizeof(struct pyrf_event),
193 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
194 .tp_doc = pyrf_throttle_event__doc,
195 .tp_members = pyrf_throttle_event__members,
196 .tp_repr = (reprfunc)pyrf_throttle_event__repr,
197 };
198
199 static const char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object.");
200
201 static PyMemberDef pyrf_lost_event__members[] = {
202 sample_members
203 member_def(perf_record_lost, id, T_ULONGLONG, "event id"),
204 member_def(perf_record_lost, lost, T_ULONGLONG, "number of lost events"),
205 { .name = NULL, },
206 };
207
pyrf_lost_event__repr(const struct pyrf_event * pevent)208 static PyObject *pyrf_lost_event__repr(const struct pyrf_event *pevent)
209 {
210 PyObject *ret;
211 char *s;
212
213 if (asprintf(&s, "{ type: lost, id: %#" PRI_lx64 ", "
214 "lost: %#" PRI_lx64 " }",
215 pevent->event.lost.id, pevent->event.lost.lost) < 0) {
216 ret = PyErr_NoMemory();
217 } else {
218 ret = PyUnicode_FromString(s);
219 free(s);
220 }
221 return ret;
222 }
223
224 static PyTypeObject pyrf_lost_event__type = {
225 PyVarObject_HEAD_INIT(NULL, 0)
226 .tp_name = "perf.lost_event",
227 .tp_basicsize = sizeof(struct pyrf_event),
228 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
229 .tp_doc = pyrf_lost_event__doc,
230 .tp_members = pyrf_lost_event__members,
231 .tp_repr = (reprfunc)pyrf_lost_event__repr,
232 };
233
234 static const char pyrf_read_event__doc[] = PyDoc_STR("perf read event object.");
235
236 static PyMemberDef pyrf_read_event__members[] = {
237 sample_members
238 member_def(perf_record_read, pid, T_UINT, "event pid"),
239 member_def(perf_record_read, tid, T_UINT, "event tid"),
240 { .name = NULL, },
241 };
242
pyrf_read_event__repr(const struct pyrf_event * pevent)243 static PyObject *pyrf_read_event__repr(const struct pyrf_event *pevent)
244 {
245 return PyUnicode_FromFormat("{ type: read, pid: %u, tid: %u }",
246 pevent->event.read.pid,
247 pevent->event.read.tid);
248 /*
249 * FIXME: return the array of read values,
250 * making this method useful ;-)
251 */
252 }
253
254 static PyTypeObject pyrf_read_event__type = {
255 PyVarObject_HEAD_INIT(NULL, 0)
256 .tp_name = "perf.read_event",
257 .tp_basicsize = sizeof(struct pyrf_event),
258 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
259 .tp_doc = pyrf_read_event__doc,
260 .tp_members = pyrf_read_event__members,
261 .tp_repr = (reprfunc)pyrf_read_event__repr,
262 };
263
264 static const char pyrf_sample_event__doc[] = PyDoc_STR("perf sample event object.");
265
266 static PyMemberDef pyrf_sample_event__members[] = {
267 sample_members
268 member_def(perf_event_header, type, T_UINT, "event type"),
269 { .name = NULL, },
270 };
271
pyrf_sample_event__delete(struct pyrf_event * pevent)272 static void pyrf_sample_event__delete(struct pyrf_event *pevent)
273 {
274 perf_sample__exit(&pevent->sample);
275 Py_TYPE(pevent)->tp_free((PyObject*)pevent);
276 }
277
pyrf_sample_event__repr(const struct pyrf_event * pevent)278 static PyObject *pyrf_sample_event__repr(const struct pyrf_event *pevent)
279 {
280 PyObject *ret;
281 char *s;
282
283 if (asprintf(&s, "{ type: sample }") < 0) {
284 ret = PyErr_NoMemory();
285 } else {
286 ret = PyUnicode_FromString(s);
287 free(s);
288 }
289 return ret;
290 }
291
292 #ifdef HAVE_LIBTRACEEVENT
is_tracepoint(const struct pyrf_event * pevent)293 static bool is_tracepoint(const struct pyrf_event *pevent)
294 {
295 return pevent->evsel->core.attr.type == PERF_TYPE_TRACEPOINT;
296 }
297
298 static PyObject*
tracepoint_field(const struct pyrf_event * pe,struct tep_format_field * field)299 tracepoint_field(const struct pyrf_event *pe, struct tep_format_field *field)
300 {
301 struct tep_handle *pevent = field->event->tep;
302 void *data = pe->sample.raw_data;
303 PyObject *ret = NULL;
304 unsigned long long val;
305 unsigned int offset, len;
306
307 if (field->flags & TEP_FIELD_IS_ARRAY) {
308 offset = field->offset;
309 len = field->size;
310 if (field->flags & TEP_FIELD_IS_DYNAMIC) {
311 val = tep_read_number(pevent, data + offset, len);
312 offset = val;
313 len = offset >> 16;
314 offset &= 0xffff;
315 if (tep_field_is_relative(field->flags))
316 offset += field->offset + field->size;
317 }
318 if (field->flags & TEP_FIELD_IS_STRING &&
319 is_printable_array(data + offset, len)) {
320 ret = PyUnicode_FromString((char *)data + offset);
321 } else {
322 ret = PyByteArray_FromStringAndSize((const char *) data + offset, len);
323 field->flags &= ~TEP_FIELD_IS_STRING;
324 }
325 } else {
326 val = tep_read_number(pevent, data + field->offset,
327 field->size);
328 if (field->flags & TEP_FIELD_IS_POINTER)
329 ret = PyLong_FromUnsignedLong((unsigned long) val);
330 else if (field->flags & TEP_FIELD_IS_SIGNED)
331 ret = PyLong_FromLong((long) val);
332 else
333 ret = PyLong_FromUnsignedLong((unsigned long) val);
334 }
335
336 return ret;
337 }
338
339 static PyObject*
get_tracepoint_field(struct pyrf_event * pevent,PyObject * attr_name)340 get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
341 {
342 struct evsel *evsel = pevent->evsel;
343 struct tep_event *tp_format = evsel__tp_format(evsel);
344 struct tep_format_field *field;
345
346 if (IS_ERR_OR_NULL(tp_format))
347 return NULL;
348
349 PyObject *obj = PyObject_Str(attr_name);
350 if (obj == NULL)
351 return NULL;
352
353 const char *str = PyUnicode_AsUTF8(obj);
354 if (str == NULL) {
355 Py_DECREF(obj);
356 return NULL;
357 }
358
359 field = tep_find_any_field(tp_format, str);
360 Py_DECREF(obj);
361 return field ? tracepoint_field(pevent, field) : NULL;
362 }
363 #endif /* HAVE_LIBTRACEEVENT */
364
365 static PyObject*
pyrf_sample_event__getattro(struct pyrf_event * pevent,PyObject * attr_name)366 pyrf_sample_event__getattro(struct pyrf_event *pevent, PyObject *attr_name)
367 {
368 PyObject *obj = NULL;
369
370 #ifdef HAVE_LIBTRACEEVENT
371 if (is_tracepoint(pevent))
372 obj = get_tracepoint_field(pevent, attr_name);
373 #endif
374
375 return obj ?: PyObject_GenericGetAttr((PyObject *) pevent, attr_name);
376 }
377
378 static PyTypeObject pyrf_sample_event__type = {
379 PyVarObject_HEAD_INIT(NULL, 0)
380 .tp_name = "perf.sample_event",
381 .tp_basicsize = sizeof(struct pyrf_event),
382 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
383 .tp_doc = pyrf_sample_event__doc,
384 .tp_members = pyrf_sample_event__members,
385 .tp_repr = (reprfunc)pyrf_sample_event__repr,
386 .tp_getattro = (getattrofunc) pyrf_sample_event__getattro,
387 };
388
389 static const char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_switch event object.");
390
391 static PyMemberDef pyrf_context_switch_event__members[] = {
392 sample_members
393 member_def(perf_event_header, type, T_UINT, "event type"),
394 member_def(perf_record_switch, next_prev_pid, T_UINT, "next/prev pid"),
395 member_def(perf_record_switch, next_prev_tid, T_UINT, "next/prev tid"),
396 { .name = NULL, },
397 };
398
pyrf_context_switch_event__repr(const struct pyrf_event * pevent)399 static PyObject *pyrf_context_switch_event__repr(const struct pyrf_event *pevent)
400 {
401 PyObject *ret;
402 char *s;
403
404 if (asprintf(&s, "{ type: context_switch, next_prev_pid: %u, next_prev_tid: %u, switch_out: %u }",
405 pevent->event.context_switch.next_prev_pid,
406 pevent->event.context_switch.next_prev_tid,
407 !!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT)) < 0) {
408 ret = PyErr_NoMemory();
409 } else {
410 ret = PyUnicode_FromString(s);
411 free(s);
412 }
413 return ret;
414 }
415
416 static PyTypeObject pyrf_context_switch_event__type = {
417 PyVarObject_HEAD_INIT(NULL, 0)
418 .tp_name = "perf.context_switch_event",
419 .tp_basicsize = sizeof(struct pyrf_event),
420 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
421 .tp_doc = pyrf_context_switch_event__doc,
422 .tp_members = pyrf_context_switch_event__members,
423 .tp_repr = (reprfunc)pyrf_context_switch_event__repr,
424 };
425
pyrf_event__setup_types(void)426 static int pyrf_event__setup_types(void)
427 {
428 int err;
429 pyrf_mmap_event__type.tp_new =
430 pyrf_task_event__type.tp_new =
431 pyrf_comm_event__type.tp_new =
432 pyrf_lost_event__type.tp_new =
433 pyrf_read_event__type.tp_new =
434 pyrf_sample_event__type.tp_new =
435 pyrf_context_switch_event__type.tp_new =
436 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
437
438 pyrf_sample_event__type.tp_dealloc = (destructor)pyrf_sample_event__delete,
439
440 err = PyType_Ready(&pyrf_mmap_event__type);
441 if (err < 0)
442 goto out;
443 err = PyType_Ready(&pyrf_lost_event__type);
444 if (err < 0)
445 goto out;
446 err = PyType_Ready(&pyrf_task_event__type);
447 if (err < 0)
448 goto out;
449 err = PyType_Ready(&pyrf_comm_event__type);
450 if (err < 0)
451 goto out;
452 err = PyType_Ready(&pyrf_throttle_event__type);
453 if (err < 0)
454 goto out;
455 err = PyType_Ready(&pyrf_read_event__type);
456 if (err < 0)
457 goto out;
458 err = PyType_Ready(&pyrf_sample_event__type);
459 if (err < 0)
460 goto out;
461 err = PyType_Ready(&pyrf_context_switch_event__type);
462 if (err < 0)
463 goto out;
464 out:
465 return err;
466 }
467
468 static PyTypeObject *pyrf_event__type[] = {
469 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
470 [PERF_RECORD_LOST] = &pyrf_lost_event__type,
471 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
472 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
473 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
474 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
475 [PERF_RECORD_FORK] = &pyrf_task_event__type,
476 [PERF_RECORD_READ] = &pyrf_read_event__type,
477 [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type,
478 [PERF_RECORD_SWITCH] = &pyrf_context_switch_event__type,
479 [PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type,
480 };
481
pyrf_event__new(const union perf_event * event)482 static PyObject *pyrf_event__new(const union perf_event *event)
483 {
484 struct pyrf_event *pevent;
485 PyTypeObject *ptype;
486
487 if ((event->header.type < PERF_RECORD_MMAP ||
488 event->header.type > PERF_RECORD_SAMPLE) &&
489 !(event->header.type == PERF_RECORD_SWITCH ||
490 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) {
491 PyErr_Format(PyExc_TypeError, "Unexpected header type %u",
492 event->header.type);
493 return NULL;
494 }
495
496 // FIXME this better be dynamic or we need to parse everything
497 // before calling perf_mmap__consume(), including tracepoint fields.
498 if (sizeof(pevent->event) < event->header.size) {
499 PyErr_Format(PyExc_TypeError, "Unexpected event size: %zd < %u",
500 sizeof(pevent->event), event->header.size);
501 return NULL;
502 }
503
504 ptype = pyrf_event__type[event->header.type];
505 pevent = PyObject_New(struct pyrf_event, ptype);
506 if (pevent != NULL)
507 memcpy(&pevent->event, event, event->header.size);
508 return (PyObject *)pevent;
509 }
510
511 struct pyrf_cpu_map {
512 PyObject_HEAD
513
514 struct perf_cpu_map *cpus;
515 };
516
pyrf_cpu_map__init(struct pyrf_cpu_map * pcpus,PyObject * args,PyObject * kwargs)517 static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
518 PyObject *args, PyObject *kwargs)
519 {
520 static char *kwlist[] = { "cpustr", NULL };
521 char *cpustr = NULL;
522
523 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
524 kwlist, &cpustr))
525 return -1;
526
527 pcpus->cpus = perf_cpu_map__new(cpustr);
528 if (pcpus->cpus == NULL)
529 return -1;
530 return 0;
531 }
532
pyrf_cpu_map__delete(struct pyrf_cpu_map * pcpus)533 static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
534 {
535 perf_cpu_map__put(pcpus->cpus);
536 Py_TYPE(pcpus)->tp_free((PyObject*)pcpus);
537 }
538
pyrf_cpu_map__length(PyObject * obj)539 static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
540 {
541 struct pyrf_cpu_map *pcpus = (void *)obj;
542
543 return perf_cpu_map__nr(pcpus->cpus);
544 }
545
pyrf_cpu_map__item(PyObject * obj,Py_ssize_t i)546 static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i)
547 {
548 struct pyrf_cpu_map *pcpus = (void *)obj;
549
550 if (i >= perf_cpu_map__nr(pcpus->cpus)) {
551 PyErr_SetString(PyExc_IndexError, "Index out of range");
552 return NULL;
553 }
554
555 return Py_BuildValue("i", perf_cpu_map__cpu(pcpus->cpus, i).cpu);
556 }
557
558 static PySequenceMethods pyrf_cpu_map__sequence_methods = {
559 .sq_length = pyrf_cpu_map__length,
560 .sq_item = pyrf_cpu_map__item,
561 };
562
563 static const char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object.");
564
565 static PyTypeObject pyrf_cpu_map__type = {
566 PyVarObject_HEAD_INIT(NULL, 0)
567 .tp_name = "perf.cpu_map",
568 .tp_basicsize = sizeof(struct pyrf_cpu_map),
569 .tp_dealloc = (destructor)pyrf_cpu_map__delete,
570 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
571 .tp_doc = pyrf_cpu_map__doc,
572 .tp_as_sequence = &pyrf_cpu_map__sequence_methods,
573 .tp_init = (initproc)pyrf_cpu_map__init,
574 };
575
pyrf_cpu_map__setup_types(void)576 static int pyrf_cpu_map__setup_types(void)
577 {
578 pyrf_cpu_map__type.tp_new = PyType_GenericNew;
579 return PyType_Ready(&pyrf_cpu_map__type);
580 }
581
582 struct pyrf_thread_map {
583 PyObject_HEAD
584
585 struct perf_thread_map *threads;
586 };
587
pyrf_thread_map__init(struct pyrf_thread_map * pthreads,PyObject * args,PyObject * kwargs)588 static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
589 PyObject *args, PyObject *kwargs)
590 {
591 static char *kwlist[] = { "pid", "tid", NULL };
592 int pid = -1, tid = -1;
593
594 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
595 kwlist, &pid, &tid))
596 return -1;
597
598 pthreads->threads = thread_map__new(pid, tid);
599 if (pthreads->threads == NULL)
600 return -1;
601 return 0;
602 }
603
pyrf_thread_map__delete(struct pyrf_thread_map * pthreads)604 static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
605 {
606 perf_thread_map__put(pthreads->threads);
607 Py_TYPE(pthreads)->tp_free((PyObject*)pthreads);
608 }
609
pyrf_thread_map__length(PyObject * obj)610 static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
611 {
612 struct pyrf_thread_map *pthreads = (void *)obj;
613
614 return perf_thread_map__nr(pthreads->threads);
615 }
616
pyrf_thread_map__item(PyObject * obj,Py_ssize_t i)617 static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i)
618 {
619 struct pyrf_thread_map *pthreads = (void *)obj;
620
621 if (i >= perf_thread_map__nr(pthreads->threads)) {
622 PyErr_SetString(PyExc_IndexError, "Index out of range");
623 return NULL;
624 }
625
626 return Py_BuildValue("i", perf_thread_map__pid(pthreads->threads, i));
627 }
628
629 static PySequenceMethods pyrf_thread_map__sequence_methods = {
630 .sq_length = pyrf_thread_map__length,
631 .sq_item = pyrf_thread_map__item,
632 };
633
634 static const char pyrf_thread_map__doc[] = PyDoc_STR("thread map object.");
635
636 static PyTypeObject pyrf_thread_map__type = {
637 PyVarObject_HEAD_INIT(NULL, 0)
638 .tp_name = "perf.thread_map",
639 .tp_basicsize = sizeof(struct pyrf_thread_map),
640 .tp_dealloc = (destructor)pyrf_thread_map__delete,
641 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
642 .tp_doc = pyrf_thread_map__doc,
643 .tp_as_sequence = &pyrf_thread_map__sequence_methods,
644 .tp_init = (initproc)pyrf_thread_map__init,
645 };
646
pyrf_thread_map__setup_types(void)647 static int pyrf_thread_map__setup_types(void)
648 {
649 pyrf_thread_map__type.tp_new = PyType_GenericNew;
650 return PyType_Ready(&pyrf_thread_map__type);
651 }
652
653 /**
654 * A python wrapper for perf_pmus that are globally owned by the pmus.c code.
655 */
656 struct pyrf_pmu {
657 PyObject_HEAD
658
659 struct perf_pmu *pmu;
660 };
661
pyrf_pmu__delete(struct pyrf_pmu * ppmu)662 static void pyrf_pmu__delete(struct pyrf_pmu *ppmu)
663 {
664 Py_TYPE(ppmu)->tp_free((PyObject *)ppmu);
665 }
666
pyrf_pmu__name(PyObject * self)667 static PyObject *pyrf_pmu__name(PyObject *self)
668 {
669 struct pyrf_pmu *ppmu = (void *)self;
670
671 return PyUnicode_FromString(ppmu->pmu->name);
672 }
673
add_to_dict(PyObject * dict,const char * key,const char * value)674 static bool add_to_dict(PyObject *dict, const char *key, const char *value)
675 {
676 PyObject *pkey, *pvalue;
677 bool ret;
678
679 if (value == NULL)
680 return true;
681
682 pkey = PyUnicode_FromString(key);
683 pvalue = PyUnicode_FromString(value);
684
685 ret = pkey && pvalue && PyDict_SetItem(dict, pkey, pvalue) == 0;
686 Py_XDECREF(pkey);
687 Py_XDECREF(pvalue);
688 return ret;
689 }
690
pyrf_pmu__events_cb(void * state,struct pmu_event_info * info)691 static int pyrf_pmu__events_cb(void *state, struct pmu_event_info *info)
692 {
693 PyObject *py_list = state;
694 PyObject *dict = PyDict_New();
695
696 if (!dict)
697 return -ENOMEM;
698
699 if (!add_to_dict(dict, "name", info->name) ||
700 !add_to_dict(dict, "alias", info->alias) ||
701 !add_to_dict(dict, "scale_unit", info->scale_unit) ||
702 !add_to_dict(dict, "desc", info->desc) ||
703 !add_to_dict(dict, "long_desc", info->long_desc) ||
704 !add_to_dict(dict, "encoding_desc", info->encoding_desc) ||
705 !add_to_dict(dict, "topic", info->topic) ||
706 !add_to_dict(dict, "event_type_desc", info->event_type_desc) ||
707 !add_to_dict(dict, "str", info->str) ||
708 !add_to_dict(dict, "deprecated", info->deprecated ? "deprecated" : NULL) ||
709 PyList_Append(py_list, dict) != 0) {
710 Py_DECREF(dict);
711 return -ENOMEM;
712 }
713 Py_DECREF(dict);
714 return 0;
715 }
716
pyrf_pmu__events(PyObject * self)717 static PyObject *pyrf_pmu__events(PyObject *self)
718 {
719 struct pyrf_pmu *ppmu = (void *)self;
720 PyObject *py_list = PyList_New(0);
721 int ret;
722
723 if (!py_list)
724 return NULL;
725
726 ret = perf_pmu__for_each_event(ppmu->pmu,
727 /*skip_duplicate_pmus=*/false,
728 py_list,
729 pyrf_pmu__events_cb);
730 if (ret) {
731 Py_DECREF(py_list);
732 errno = -ret;
733 PyErr_SetFromErrno(PyExc_OSError);
734 return NULL;
735 }
736 return py_list;
737 }
738
pyrf_pmu__repr(PyObject * self)739 static PyObject *pyrf_pmu__repr(PyObject *self)
740 {
741 struct pyrf_pmu *ppmu = (void *)self;
742
743 return PyUnicode_FromFormat("pmu(%s)", ppmu->pmu->name);
744 }
745
746 static const char pyrf_pmu__doc[] = PyDoc_STR("perf Performance Monitoring Unit (PMU) object.");
747
748 static PyMethodDef pyrf_pmu__methods[] = {
749 {
750 .ml_name = "events",
751 .ml_meth = (PyCFunction)pyrf_pmu__events,
752 .ml_flags = METH_NOARGS,
753 .ml_doc = PyDoc_STR("Returns a sequence of events encoded as a dictionaries.")
754 },
755 {
756 .ml_name = "name",
757 .ml_meth = (PyCFunction)pyrf_pmu__name,
758 .ml_flags = METH_NOARGS,
759 .ml_doc = PyDoc_STR("Name of the PMU including suffixes.")
760 },
761 { .ml_name = NULL, }
762 };
763
764 /** The python type for a perf.pmu. */
765 static PyTypeObject pyrf_pmu__type = {
766 PyVarObject_HEAD_INIT(NULL, 0)
767 .tp_name = "perf.pmu",
768 .tp_basicsize = sizeof(struct pyrf_pmu),
769 .tp_dealloc = (destructor)pyrf_pmu__delete,
770 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
771 .tp_doc = pyrf_pmu__doc,
772 .tp_methods = pyrf_pmu__methods,
773 .tp_str = pyrf_pmu__name,
774 .tp_repr = pyrf_pmu__repr,
775 };
776
pyrf_pmu__setup_types(void)777 static int pyrf_pmu__setup_types(void)
778 {
779 pyrf_pmu__type.tp_new = PyType_GenericNew;
780 return PyType_Ready(&pyrf_pmu__type);
781 }
782
783
784 /** A python iterator for pmus that has no equivalent in the C code. */
785 struct pyrf_pmu_iterator {
786 PyObject_HEAD
787 struct perf_pmu *pmu;
788 };
789
pyrf_pmu_iterator__dealloc(struct pyrf_pmu_iterator * self)790 static void pyrf_pmu_iterator__dealloc(struct pyrf_pmu_iterator *self)
791 {
792 Py_TYPE(self)->tp_free((PyObject *) self);
793 }
794
pyrf_pmu_iterator__new(PyTypeObject * type,PyObject * args __maybe_unused,PyObject * kwds __maybe_unused)795 static PyObject *pyrf_pmu_iterator__new(PyTypeObject *type, PyObject *args __maybe_unused,
796 PyObject *kwds __maybe_unused)
797 {
798 struct pyrf_pmu_iterator *itr = (void *)type->tp_alloc(type, 0);
799
800 if (itr != NULL)
801 itr->pmu = perf_pmus__scan(/*pmu=*/NULL);
802
803 return (PyObject *) itr;
804 }
805
pyrf_pmu_iterator__iter(PyObject * self)806 static PyObject *pyrf_pmu_iterator__iter(PyObject *self)
807 {
808 Py_INCREF(self);
809 return self;
810 }
811
pyrf_pmu_iterator__iternext(PyObject * self)812 static PyObject *pyrf_pmu_iterator__iternext(PyObject *self)
813 {
814 struct pyrf_pmu_iterator *itr = (void *)self;
815 struct pyrf_pmu *ppmu;
816
817 if (itr->pmu == NULL) {
818 PyErr_SetNone(PyExc_StopIteration);
819 return NULL;
820 }
821 // Create object to return.
822 ppmu = PyObject_New(struct pyrf_pmu, &pyrf_pmu__type);
823 if (ppmu) {
824 ppmu->pmu = itr->pmu;
825 // Advance iterator.
826 itr->pmu = perf_pmus__scan(itr->pmu);
827 }
828 return (PyObject *)ppmu;
829 }
830
831 /** The python type for the PMU iterator. */
832 static PyTypeObject pyrf_pmu_iterator__type = {
833 PyVarObject_HEAD_INIT(NULL, 0)
834 .tp_name = "pmus.iterator",
835 .tp_doc = "Iterator for the pmus string sequence.",
836 .tp_basicsize = sizeof(struct pyrf_pmu_iterator),
837 .tp_itemsize = 0,
838 .tp_flags = Py_TPFLAGS_DEFAULT,
839 .tp_new = pyrf_pmu_iterator__new,
840 .tp_dealloc = (destructor) pyrf_pmu_iterator__dealloc,
841 .tp_iter = pyrf_pmu_iterator__iter,
842 .tp_iternext = pyrf_pmu_iterator__iternext,
843 };
844
pyrf_pmu_iterator__setup_types(void)845 static int pyrf_pmu_iterator__setup_types(void)
846 {
847 return PyType_Ready(&pyrf_pmu_iterator__type);
848 }
849
pyrf__pmus(PyObject * self,PyObject * args)850 static PyObject *pyrf__pmus(PyObject *self, PyObject *args)
851 {
852 // Calling the class creates an instance of the iterator.
853 return PyObject_CallObject((PyObject *) &pyrf_pmu_iterator__type, /*args=*/NULL);
854 }
855
856 struct pyrf_counts_values {
857 PyObject_HEAD
858
859 struct perf_counts_values values;
860 };
861
862 static const char pyrf_counts_values__doc[] = PyDoc_STR("perf counts values object.");
863
pyrf_counts_values__delete(struct pyrf_counts_values * pcounts_values)864 static void pyrf_counts_values__delete(struct pyrf_counts_values *pcounts_values)
865 {
866 Py_TYPE(pcounts_values)->tp_free((PyObject *)pcounts_values);
867 }
868
869 #define counts_values_member_def(member, ptype, help) \
870 { #member, ptype, \
871 offsetof(struct pyrf_counts_values, values.member), \
872 0, help }
873
874 static PyMemberDef pyrf_counts_values_members[] = {
875 counts_values_member_def(val, T_ULONG, "Value of event"),
876 counts_values_member_def(ena, T_ULONG, "Time for which enabled"),
877 counts_values_member_def(run, T_ULONG, "Time for which running"),
878 counts_values_member_def(id, T_ULONG, "Unique ID for an event"),
879 counts_values_member_def(lost, T_ULONG, "Num of lost samples"),
880 { .name = NULL, },
881 };
882
pyrf_counts_values_get_values(struct pyrf_counts_values * self,void * closure)883 static PyObject *pyrf_counts_values_get_values(struct pyrf_counts_values *self, void *closure)
884 {
885 PyObject *vals = PyList_New(5);
886
887 if (!vals)
888 return NULL;
889 for (int i = 0; i < 5; i++)
890 PyList_SetItem(vals, i, PyLong_FromLong(self->values.values[i]));
891
892 return vals;
893 }
894
pyrf_counts_values_set_values(struct pyrf_counts_values * self,PyObject * list,void * closure)895 static int pyrf_counts_values_set_values(struct pyrf_counts_values *self, PyObject *list,
896 void *closure)
897 {
898 Py_ssize_t size;
899 PyObject *item = NULL;
900
901 if (!PyList_Check(list)) {
902 PyErr_SetString(PyExc_TypeError, "Value assigned must be a list");
903 return -1;
904 }
905
906 size = PyList_Size(list);
907 for (Py_ssize_t i = 0; i < size; i++) {
908 item = PyList_GetItem(list, i);
909 if (!PyLong_Check(item)) {
910 PyErr_SetString(PyExc_TypeError, "List members should be numbers");
911 return -1;
912 }
913 self->values.values[i] = PyLong_AsLong(item);
914 }
915
916 return 0;
917 }
918
919 static PyGetSetDef pyrf_counts_values_getset[] = {
920 {"values", (getter)pyrf_counts_values_get_values, (setter)pyrf_counts_values_set_values,
921 "Name field", NULL},
922 { .name = NULL, },
923 };
924
925 static PyTypeObject pyrf_counts_values__type = {
926 PyVarObject_HEAD_INIT(NULL, 0)
927 .tp_name = "perf.counts_values",
928 .tp_basicsize = sizeof(struct pyrf_counts_values),
929 .tp_dealloc = (destructor)pyrf_counts_values__delete,
930 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
931 .tp_doc = pyrf_counts_values__doc,
932 .tp_members = pyrf_counts_values_members,
933 .tp_getset = pyrf_counts_values_getset,
934 };
935
pyrf_counts_values__setup_types(void)936 static int pyrf_counts_values__setup_types(void)
937 {
938 pyrf_counts_values__type.tp_new = PyType_GenericNew;
939 return PyType_Ready(&pyrf_counts_values__type);
940 }
941
942 struct pyrf_evsel {
943 PyObject_HEAD
944
945 struct evsel evsel;
946 };
947
pyrf_evsel__init(struct pyrf_evsel * pevsel,PyObject * args,PyObject * kwargs)948 static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
949 PyObject *args, PyObject *kwargs)
950 {
951 struct perf_event_attr attr = {
952 .type = PERF_TYPE_HARDWARE,
953 .config = PERF_COUNT_HW_CPU_CYCLES,
954 .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID,
955 };
956 static char *kwlist[] = {
957 "type",
958 "config",
959 "sample_freq",
960 "sample_period",
961 "sample_type",
962 "read_format",
963 "disabled",
964 "inherit",
965 "pinned",
966 "exclusive",
967 "exclude_user",
968 "exclude_kernel",
969 "exclude_hv",
970 "exclude_idle",
971 "mmap",
972 "context_switch",
973 "comm",
974 "freq",
975 "inherit_stat",
976 "enable_on_exec",
977 "task",
978 "watermark",
979 "precise_ip",
980 "mmap_data",
981 "sample_id_all",
982 "wakeup_events",
983 "bp_type",
984 "bp_addr",
985 "bp_len",
986 NULL
987 };
988 u64 sample_period = 0;
989 u32 disabled = 0,
990 inherit = 0,
991 pinned = 0,
992 exclusive = 0,
993 exclude_user = 0,
994 exclude_kernel = 0,
995 exclude_hv = 0,
996 exclude_idle = 0,
997 mmap = 0,
998 context_switch = 0,
999 comm = 0,
1000 freq = 1,
1001 inherit_stat = 0,
1002 enable_on_exec = 0,
1003 task = 0,
1004 watermark = 0,
1005 precise_ip = 0,
1006 mmap_data = 0,
1007 sample_id_all = 1;
1008 int idx = 0;
1009
1010 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
1011 "|iKiKKiiiiiiiiiiiiiiiiiiiiiiKK", kwlist,
1012 &attr.type, &attr.config, &attr.sample_freq,
1013 &sample_period, &attr.sample_type,
1014 &attr.read_format, &disabled, &inherit,
1015 &pinned, &exclusive, &exclude_user,
1016 &exclude_kernel, &exclude_hv, &exclude_idle,
1017 &mmap, &context_switch, &comm, &freq, &inherit_stat,
1018 &enable_on_exec, &task, &watermark,
1019 &precise_ip, &mmap_data, &sample_id_all,
1020 &attr.wakeup_events, &attr.bp_type,
1021 &attr.bp_addr, &attr.bp_len, &idx))
1022 return -1;
1023
1024 /* union... */
1025 if (sample_period != 0) {
1026 if (attr.sample_freq != 0)
1027 return -1; /* FIXME: throw right exception */
1028 attr.sample_period = sample_period;
1029 }
1030
1031 /* Bitfields */
1032 attr.disabled = disabled;
1033 attr.inherit = inherit;
1034 attr.pinned = pinned;
1035 attr.exclusive = exclusive;
1036 attr.exclude_user = exclude_user;
1037 attr.exclude_kernel = exclude_kernel;
1038 attr.exclude_hv = exclude_hv;
1039 attr.exclude_idle = exclude_idle;
1040 attr.mmap = mmap;
1041 attr.context_switch = context_switch;
1042 attr.comm = comm;
1043 attr.freq = freq;
1044 attr.inherit_stat = inherit_stat;
1045 attr.enable_on_exec = enable_on_exec;
1046 attr.task = task;
1047 attr.watermark = watermark;
1048 attr.precise_ip = precise_ip;
1049 attr.mmap_data = mmap_data;
1050 attr.sample_id_all = sample_id_all;
1051 attr.size = sizeof(attr);
1052
1053 evsel__init(&pevsel->evsel, &attr, idx);
1054 return 0;
1055 }
1056
pyrf_evsel__delete(struct pyrf_evsel * pevsel)1057 static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
1058 {
1059 evsel__exit(&pevsel->evsel);
1060 Py_TYPE(pevsel)->tp_free((PyObject*)pevsel);
1061 }
1062
pyrf_evsel__open(struct pyrf_evsel * pevsel,PyObject * args,PyObject * kwargs)1063 static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
1064 PyObject *args, PyObject *kwargs)
1065 {
1066 struct evsel *evsel = &pevsel->evsel;
1067 struct perf_cpu_map *cpus = NULL;
1068 struct perf_thread_map *threads = NULL;
1069 PyObject *pcpus = NULL, *pthreads = NULL;
1070 int group = 0, inherit = 0;
1071 static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL };
1072
1073 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
1074 &pcpus, &pthreads, &group, &inherit))
1075 return NULL;
1076
1077 if (pthreads != NULL)
1078 threads = ((struct pyrf_thread_map *)pthreads)->threads;
1079
1080 if (pcpus != NULL)
1081 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
1082
1083 evsel->core.attr.inherit = inherit;
1084 /*
1085 * This will group just the fds for this single evsel, to group
1086 * multiple events, use evlist.open().
1087 */
1088 if (evsel__open(evsel, cpus, threads) < 0) {
1089 PyErr_SetFromErrno(PyExc_OSError);
1090 return NULL;
1091 }
1092
1093 Py_INCREF(Py_None);
1094 return Py_None;
1095 }
1096
pyrf_evsel__cpus(struct pyrf_evsel * pevsel)1097 static PyObject *pyrf_evsel__cpus(struct pyrf_evsel *pevsel)
1098 {
1099 struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
1100
1101 if (pcpu_map)
1102 pcpu_map->cpus = perf_cpu_map__get(pevsel->evsel.core.cpus);
1103
1104 return (PyObject *)pcpu_map;
1105 }
1106
pyrf_evsel__threads(struct pyrf_evsel * pevsel)1107 static PyObject *pyrf_evsel__threads(struct pyrf_evsel *pevsel)
1108 {
1109 struct pyrf_thread_map *pthread_map =
1110 PyObject_New(struct pyrf_thread_map, &pyrf_thread_map__type);
1111
1112 if (pthread_map)
1113 pthread_map->threads = perf_thread_map__get(pevsel->evsel.core.threads);
1114
1115 return (PyObject *)pthread_map;
1116 }
1117
1118 /*
1119 * Ensure evsel's counts and prev_raw_counts are allocated, the latter
1120 * used by tool PMUs to compute the cumulative count as expected by
1121 * stat's process_counter_values.
1122 */
evsel__ensure_counts(struct evsel * evsel)1123 static int evsel__ensure_counts(struct evsel *evsel)
1124 {
1125 int nthreads, ncpus;
1126
1127 if (evsel->counts != NULL)
1128 return 0;
1129
1130 nthreads = perf_thread_map__nr(evsel->core.threads);
1131 ncpus = perf_cpu_map__nr(evsel->core.cpus);
1132
1133 evsel->counts = perf_counts__new(ncpus, nthreads);
1134 if (evsel->counts == NULL)
1135 return -ENOMEM;
1136
1137 evsel->prev_raw_counts = perf_counts__new(ncpus, nthreads);
1138 if (evsel->prev_raw_counts == NULL)
1139 return -ENOMEM;
1140
1141 return 0;
1142 }
1143
pyrf_evsel__read(struct pyrf_evsel * pevsel,PyObject * args,PyObject * kwargs)1144 static PyObject *pyrf_evsel__read(struct pyrf_evsel *pevsel,
1145 PyObject *args, PyObject *kwargs)
1146 {
1147 struct evsel *evsel = &pevsel->evsel;
1148 int cpu = 0, cpu_idx, thread = 0, thread_idx;
1149 struct perf_counts_values *old_count, *new_count;
1150 struct pyrf_counts_values *count_values = PyObject_New(struct pyrf_counts_values,
1151 &pyrf_counts_values__type);
1152
1153 if (!count_values)
1154 return NULL;
1155
1156 if (!PyArg_ParseTuple(args, "ii", &cpu, &thread))
1157 return NULL;
1158
1159 cpu_idx = perf_cpu_map__idx(evsel->core.cpus, (struct perf_cpu){.cpu = cpu});
1160 if (cpu_idx < 0) {
1161 PyErr_Format(PyExc_TypeError, "CPU %d is not part of evsel's CPUs", cpu);
1162 return NULL;
1163 }
1164 thread_idx = perf_thread_map__idx(evsel->core.threads, thread);
1165 if (thread_idx < 0) {
1166 PyErr_Format(PyExc_TypeError, "Thread %d is not part of evsel's threads",
1167 thread);
1168 return NULL;
1169 }
1170
1171 if (evsel__ensure_counts(evsel))
1172 return PyErr_NoMemory();
1173
1174 /* Set up pointers to the old and newly read counter values. */
1175 old_count = perf_counts(evsel->prev_raw_counts, cpu_idx, thread_idx);
1176 new_count = perf_counts(evsel->counts, cpu_idx, thread_idx);
1177 /* Update the value in evsel->counts. */
1178 evsel__read_counter(evsel, cpu_idx, thread_idx);
1179 /* Copy the value and turn it into the delta from old_count. */
1180 count_values->values = *new_count;
1181 count_values->values.val -= old_count->val;
1182 count_values->values.ena -= old_count->ena;
1183 count_values->values.run -= old_count->run;
1184 /* Save the new count over the old_count for the next read. */
1185 *old_count = *new_count;
1186 return (PyObject *)count_values;
1187 }
1188
pyrf_evsel__str(PyObject * self)1189 static PyObject *pyrf_evsel__str(PyObject *self)
1190 {
1191 struct pyrf_evsel *pevsel = (void *)self;
1192 struct evsel *evsel = &pevsel->evsel;
1193
1194 return PyUnicode_FromFormat("evsel(%s/%s/)", evsel__pmu_name(evsel), evsel__name(evsel));
1195 }
1196
1197 static PyMethodDef pyrf_evsel__methods[] = {
1198 {
1199 .ml_name = "open",
1200 .ml_meth = (PyCFunction)pyrf_evsel__open,
1201 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1202 .ml_doc = PyDoc_STR("open the event selector file descriptor table.")
1203 },
1204 {
1205 .ml_name = "cpus",
1206 .ml_meth = (PyCFunction)pyrf_evsel__cpus,
1207 .ml_flags = METH_NOARGS,
1208 .ml_doc = PyDoc_STR("CPUs the event is to be used with.")
1209 },
1210 {
1211 .ml_name = "threads",
1212 .ml_meth = (PyCFunction)pyrf_evsel__threads,
1213 .ml_flags = METH_NOARGS,
1214 .ml_doc = PyDoc_STR("threads the event is to be used with.")
1215 },
1216 {
1217 .ml_name = "read",
1218 .ml_meth = (PyCFunction)pyrf_evsel__read,
1219 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1220 .ml_doc = PyDoc_STR("read counters")
1221 },
1222 { .ml_name = NULL, }
1223 };
1224
1225 #define evsel_member_def(member, ptype, help) \
1226 { #member, ptype, \
1227 offsetof(struct pyrf_evsel, evsel.member), \
1228 0, help }
1229
1230 #define evsel_attr_member_def(member, ptype, help) \
1231 { #member, ptype, \
1232 offsetof(struct pyrf_evsel, evsel.core.attr.member), \
1233 0, help }
1234
1235 static PyMemberDef pyrf_evsel__members[] = {
1236 evsel_member_def(tracking, T_BOOL, "tracking event."),
1237 evsel_attr_member_def(type, T_UINT, "attribute type."),
1238 evsel_attr_member_def(size, T_UINT, "attribute size."),
1239 evsel_attr_member_def(config, T_ULONGLONG, "attribute config."),
1240 evsel_attr_member_def(sample_period, T_ULONGLONG, "attribute sample_period."),
1241 evsel_attr_member_def(sample_type, T_ULONGLONG, "attribute sample_type."),
1242 evsel_attr_member_def(read_format, T_ULONGLONG, "attribute read_format."),
1243 evsel_attr_member_def(wakeup_events, T_UINT, "attribute wakeup_events."),
1244 { .name = NULL, },
1245 };
1246
1247 static const char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
1248
1249 static PyTypeObject pyrf_evsel__type = {
1250 PyVarObject_HEAD_INIT(NULL, 0)
1251 .tp_name = "perf.evsel",
1252 .tp_basicsize = sizeof(struct pyrf_evsel),
1253 .tp_dealloc = (destructor)pyrf_evsel__delete,
1254 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1255 .tp_doc = pyrf_evsel__doc,
1256 .tp_members = pyrf_evsel__members,
1257 .tp_methods = pyrf_evsel__methods,
1258 .tp_init = (initproc)pyrf_evsel__init,
1259 .tp_str = pyrf_evsel__str,
1260 .tp_repr = pyrf_evsel__str,
1261 };
1262
pyrf_evsel__setup_types(void)1263 static int pyrf_evsel__setup_types(void)
1264 {
1265 pyrf_evsel__type.tp_new = PyType_GenericNew;
1266 return PyType_Ready(&pyrf_evsel__type);
1267 }
1268
1269 struct pyrf_evlist {
1270 PyObject_HEAD
1271
1272 struct evlist evlist;
1273 };
1274
pyrf_evlist__init(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs __maybe_unused)1275 static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
1276 PyObject *args, PyObject *kwargs __maybe_unused)
1277 {
1278 PyObject *pcpus = NULL, *pthreads = NULL;
1279 struct perf_cpu_map *cpus;
1280 struct perf_thread_map *threads;
1281
1282 if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads))
1283 return -1;
1284
1285 threads = ((struct pyrf_thread_map *)pthreads)->threads;
1286 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
1287 evlist__init(&pevlist->evlist, cpus, threads);
1288 return 0;
1289 }
1290
pyrf_evlist__delete(struct pyrf_evlist * pevlist)1291 static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
1292 {
1293 evlist__exit(&pevlist->evlist);
1294 Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
1295 }
1296
pyrf_evlist__all_cpus(struct pyrf_evlist * pevlist)1297 static PyObject *pyrf_evlist__all_cpus(struct pyrf_evlist *pevlist)
1298 {
1299 struct pyrf_cpu_map *pcpu_map = PyObject_New(struct pyrf_cpu_map, &pyrf_cpu_map__type);
1300
1301 if (pcpu_map)
1302 pcpu_map->cpus = perf_cpu_map__get(pevlist->evlist.core.all_cpus);
1303
1304 return (PyObject *)pcpu_map;
1305 }
1306
pyrf_evlist__metrics(struct pyrf_evlist * pevlist)1307 static PyObject *pyrf_evlist__metrics(struct pyrf_evlist *pevlist)
1308 {
1309 PyObject *list = PyList_New(/*len=*/0);
1310 struct rb_node *node;
1311
1312 if (!list)
1313 return NULL;
1314
1315 for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
1316 node = rb_next(node)) {
1317 struct metric_event *me = container_of(node, struct metric_event, nd);
1318 struct list_head *pos;
1319
1320 list_for_each(pos, &me->head) {
1321 struct metric_expr *expr = container_of(pos, struct metric_expr, nd);
1322 PyObject *str = PyUnicode_FromString(expr->metric_name);
1323
1324 if (!str || PyList_Append(list, str) != 0) {
1325 Py_DECREF(list);
1326 return NULL;
1327 }
1328 Py_DECREF(str);
1329 }
1330 }
1331 return list;
1332 }
1333
prepare_metric(const struct metric_expr * mexp,const struct evsel * evsel,struct expr_parse_ctx * pctx,int cpu_idx,int thread_idx)1334 static int prepare_metric(const struct metric_expr *mexp,
1335 const struct evsel *evsel,
1336 struct expr_parse_ctx *pctx,
1337 int cpu_idx, int thread_idx)
1338 {
1339 struct evsel * const *metric_events = mexp->metric_events;
1340 struct metric_ref *metric_refs = mexp->metric_refs;
1341
1342 for (int i = 0; metric_events[i]; i++) {
1343 char *n = strdup(evsel__metric_id(metric_events[i]));
1344 double val, ena, run;
1345 int source_count = evsel__source_count(metric_events[i]);
1346 int ret;
1347 struct perf_counts_values *old_count, *new_count;
1348
1349 if (!n)
1350 return -ENOMEM;
1351
1352 if (source_count == 0)
1353 source_count = 1;
1354
1355 ret = evsel__ensure_counts(metric_events[i]);
1356 if (ret)
1357 return ret;
1358
1359 /* Set up pointers to the old and newly read counter values. */
1360 old_count = perf_counts(metric_events[i]->prev_raw_counts, cpu_idx, thread_idx);
1361 new_count = perf_counts(metric_events[i]->counts, cpu_idx, thread_idx);
1362 /* Update the value in metric_events[i]->counts. */
1363 evsel__read_counter(metric_events[i], cpu_idx, thread_idx);
1364
1365 val = new_count->val - old_count->val;
1366 ena = new_count->ena - old_count->ena;
1367 run = new_count->run - old_count->run;
1368
1369 if (ena != run && run != 0)
1370 val = val * ena / run;
1371 ret = expr__add_id_val_source_count(pctx, n, val, source_count);
1372 if (ret)
1373 return ret;
1374 }
1375
1376 for (int i = 0; metric_refs && metric_refs[i].metric_name; i++) {
1377 int ret = expr__add_ref(pctx, &metric_refs[i]);
1378
1379 if (ret)
1380 return ret;
1381 }
1382
1383 return 0;
1384 }
1385
pyrf_evlist__compute_metric(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs)1386 static PyObject *pyrf_evlist__compute_metric(struct pyrf_evlist *pevlist,
1387 PyObject *args, PyObject *kwargs)
1388 {
1389 int ret, cpu = 0, cpu_idx = 0, thread = 0, thread_idx = 0;
1390 const char *metric;
1391 struct rb_node *node;
1392 struct metric_expr *mexp = NULL;
1393 struct expr_parse_ctx *pctx;
1394 double result = 0;
1395
1396 if (!PyArg_ParseTuple(args, "sii", &metric, &cpu, &thread))
1397 return NULL;
1398
1399 for (node = rb_first_cached(&pevlist->evlist.metric_events.entries);
1400 mexp == NULL && node;
1401 node = rb_next(node)) {
1402 struct metric_event *me = container_of(node, struct metric_event, nd);
1403 struct list_head *pos;
1404
1405 list_for_each(pos, &me->head) {
1406 struct metric_expr *e = container_of(pos, struct metric_expr, nd);
1407
1408 if (strcmp(e->metric_name, metric))
1409 continue;
1410
1411 if (e->metric_events[0] == NULL)
1412 continue;
1413
1414 cpu_idx = perf_cpu_map__idx(e->metric_events[0]->core.cpus,
1415 (struct perf_cpu){.cpu = cpu});
1416 if (cpu_idx < 0)
1417 continue;
1418
1419 thread_idx = perf_thread_map__idx(e->metric_events[0]->core.threads,
1420 thread);
1421 if (thread_idx < 0)
1422 continue;
1423
1424 mexp = e;
1425 break;
1426 }
1427 }
1428 if (!mexp) {
1429 PyErr_Format(PyExc_TypeError, "Unknown metric '%s' for CPU '%d' and thread '%d'",
1430 metric, cpu, thread);
1431 return NULL;
1432 }
1433
1434 pctx = expr__ctx_new();
1435 if (!pctx)
1436 return PyErr_NoMemory();
1437
1438 ret = prepare_metric(mexp, mexp->metric_events[0], pctx, cpu_idx, thread_idx);
1439 if (ret) {
1440 expr__ctx_free(pctx);
1441 errno = -ret;
1442 PyErr_SetFromErrno(PyExc_OSError);
1443 return NULL;
1444 }
1445 if (expr__parse(&result, pctx, mexp->metric_expr))
1446 result = 0.0;
1447
1448 expr__ctx_free(pctx);
1449 return PyFloat_FromDouble(result);
1450 }
1451
pyrf_evlist__mmap(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs)1452 static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
1453 PyObject *args, PyObject *kwargs)
1454 {
1455 struct evlist *evlist = &pevlist->evlist;
1456 static char *kwlist[] = { "pages", "overwrite", NULL };
1457 int pages = 128, overwrite = false;
1458
1459 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist,
1460 &pages, &overwrite))
1461 return NULL;
1462
1463 if (evlist__mmap(evlist, pages) < 0) {
1464 PyErr_SetFromErrno(PyExc_OSError);
1465 return NULL;
1466 }
1467
1468 Py_INCREF(Py_None);
1469 return Py_None;
1470 }
1471
pyrf_evlist__poll(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs)1472 static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
1473 PyObject *args, PyObject *kwargs)
1474 {
1475 struct evlist *evlist = &pevlist->evlist;
1476 static char *kwlist[] = { "timeout", NULL };
1477 int timeout = -1, n;
1478
1479 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
1480 return NULL;
1481
1482 n = evlist__poll(evlist, timeout);
1483 if (n < 0) {
1484 PyErr_SetFromErrno(PyExc_OSError);
1485 return NULL;
1486 }
1487
1488 return Py_BuildValue("i", n);
1489 }
1490
pyrf_evlist__get_pollfd(struct pyrf_evlist * pevlist,PyObject * args __maybe_unused,PyObject * kwargs __maybe_unused)1491 static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
1492 PyObject *args __maybe_unused,
1493 PyObject *kwargs __maybe_unused)
1494 {
1495 struct evlist *evlist = &pevlist->evlist;
1496 PyObject *list = PyList_New(0);
1497 int i;
1498
1499 for (i = 0; i < evlist->core.pollfd.nr; ++i) {
1500 PyObject *file;
1501 file = PyFile_FromFd(evlist->core.pollfd.entries[i].fd, "perf", "r", -1,
1502 NULL, NULL, NULL, 0);
1503 if (file == NULL)
1504 goto free_list;
1505
1506 if (PyList_Append(list, file) != 0) {
1507 Py_DECREF(file);
1508 goto free_list;
1509 }
1510
1511 Py_DECREF(file);
1512 }
1513
1514 return list;
1515 free_list:
1516 return PyErr_NoMemory();
1517 }
1518
1519
pyrf_evlist__add(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs __maybe_unused)1520 static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
1521 PyObject *args,
1522 PyObject *kwargs __maybe_unused)
1523 {
1524 struct evlist *evlist = &pevlist->evlist;
1525 PyObject *pevsel;
1526 struct evsel *evsel;
1527
1528 if (!PyArg_ParseTuple(args, "O", &pevsel))
1529 return NULL;
1530
1531 Py_INCREF(pevsel);
1532 evsel = &((struct pyrf_evsel *)pevsel)->evsel;
1533 evsel->core.idx = evlist->core.nr_entries;
1534 evlist__add(evlist, evsel);
1535
1536 return Py_BuildValue("i", evlist->core.nr_entries);
1537 }
1538
get_md(struct evlist * evlist,int cpu)1539 static struct mmap *get_md(struct evlist *evlist, int cpu)
1540 {
1541 int i;
1542
1543 for (i = 0; i < evlist->core.nr_mmaps; i++) {
1544 struct mmap *md = &evlist->mmap[i];
1545
1546 if (md->core.cpu.cpu == cpu)
1547 return md;
1548 }
1549
1550 return NULL;
1551 }
1552
pyrf_evlist__read_on_cpu(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs)1553 static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
1554 PyObject *args, PyObject *kwargs)
1555 {
1556 struct evlist *evlist = &pevlist->evlist;
1557 union perf_event *event;
1558 int sample_id_all = 1, cpu;
1559 static char *kwlist[] = { "cpu", "sample_id_all", NULL };
1560 struct mmap *md;
1561 int err;
1562
1563 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
1564 &cpu, &sample_id_all))
1565 return NULL;
1566
1567 md = get_md(evlist, cpu);
1568 if (!md) {
1569 PyErr_Format(PyExc_TypeError, "Unknown CPU '%d'", cpu);
1570 return NULL;
1571 }
1572
1573 if (perf_mmap__read_init(&md->core) < 0)
1574 goto end;
1575
1576 event = perf_mmap__read_event(&md->core);
1577 if (event != NULL) {
1578 PyObject *pyevent = pyrf_event__new(event);
1579 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
1580 struct evsel *evsel;
1581
1582 if (pyevent == NULL)
1583 return PyErr_NoMemory();
1584
1585 evsel = evlist__event2evsel(evlist, event);
1586 if (!evsel) {
1587 Py_DECREF(pyevent);
1588 Py_INCREF(Py_None);
1589 return Py_None;
1590 }
1591
1592 pevent->evsel = evsel;
1593
1594 perf_mmap__consume(&md->core);
1595
1596 err = evsel__parse_sample(evsel, &pevent->event, &pevent->sample);
1597 if (err) {
1598 Py_DECREF(pyevent);
1599 return PyErr_Format(PyExc_OSError,
1600 "perf: can't parse sample, err=%d", err);
1601 }
1602
1603 return pyevent;
1604 }
1605 end:
1606 Py_INCREF(Py_None);
1607 return Py_None;
1608 }
1609
pyrf_evlist__open(struct pyrf_evlist * pevlist,PyObject * args,PyObject * kwargs)1610 static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist,
1611 PyObject *args, PyObject *kwargs)
1612 {
1613 struct evlist *evlist = &pevlist->evlist;
1614
1615 if (evlist__open(evlist) < 0) {
1616 PyErr_SetFromErrno(PyExc_OSError);
1617 return NULL;
1618 }
1619
1620 Py_INCREF(Py_None);
1621 return Py_None;
1622 }
1623
pyrf_evlist__close(struct pyrf_evlist * pevlist)1624 static PyObject *pyrf_evlist__close(struct pyrf_evlist *pevlist)
1625 {
1626 struct evlist *evlist = &pevlist->evlist;
1627
1628 evlist__close(evlist);
1629
1630 Py_INCREF(Py_None);
1631 return Py_None;
1632 }
1633
pyrf_evlist__config(struct pyrf_evlist * pevlist)1634 static PyObject *pyrf_evlist__config(struct pyrf_evlist *pevlist)
1635 {
1636 struct record_opts opts = {
1637 .sample_time = true,
1638 .mmap_pages = UINT_MAX,
1639 .user_freq = UINT_MAX,
1640 .user_interval = ULLONG_MAX,
1641 .freq = 4000,
1642 .target = {
1643 .uses_mmap = true,
1644 .default_per_cpu = true,
1645 },
1646 .nr_threads_synthesize = 1,
1647 .ctl_fd = -1,
1648 .ctl_fd_ack = -1,
1649 .no_buffering = true,
1650 .no_inherit = true,
1651 };
1652 struct evlist *evlist = &pevlist->evlist;
1653
1654 evlist__config(evlist, &opts, &callchain_param);
1655 Py_INCREF(Py_None);
1656 return Py_None;
1657 }
1658
pyrf_evlist__disable(struct pyrf_evlist * pevlist)1659 static PyObject *pyrf_evlist__disable(struct pyrf_evlist *pevlist)
1660 {
1661 evlist__disable(&pevlist->evlist);
1662 Py_INCREF(Py_None);
1663 return Py_None;
1664 }
1665
pyrf_evlist__enable(struct pyrf_evlist * pevlist)1666 static PyObject *pyrf_evlist__enable(struct pyrf_evlist *pevlist)
1667 {
1668 evlist__enable(&pevlist->evlist);
1669 Py_INCREF(Py_None);
1670 return Py_None;
1671 }
1672
1673 static PyMethodDef pyrf_evlist__methods[] = {
1674 {
1675 .ml_name = "all_cpus",
1676 .ml_meth = (PyCFunction)pyrf_evlist__all_cpus,
1677 .ml_flags = METH_NOARGS,
1678 .ml_doc = PyDoc_STR("CPU map union of all evsel CPU maps.")
1679 },
1680 {
1681 .ml_name = "metrics",
1682 .ml_meth = (PyCFunction)pyrf_evlist__metrics,
1683 .ml_flags = METH_NOARGS,
1684 .ml_doc = PyDoc_STR("List of metric names within the evlist.")
1685 },
1686 {
1687 .ml_name = "compute_metric",
1688 .ml_meth = (PyCFunction)pyrf_evlist__compute_metric,
1689 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1690 .ml_doc = PyDoc_STR("compute metric for given name, cpu and thread")
1691 },
1692 {
1693 .ml_name = "mmap",
1694 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
1695 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1696 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
1697 },
1698 {
1699 .ml_name = "open",
1700 .ml_meth = (PyCFunction)pyrf_evlist__open,
1701 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1702 .ml_doc = PyDoc_STR("open the file descriptors.")
1703 },
1704 {
1705 .ml_name = "close",
1706 .ml_meth = (PyCFunction)pyrf_evlist__close,
1707 .ml_flags = METH_NOARGS,
1708 .ml_doc = PyDoc_STR("close the file descriptors.")
1709 },
1710 {
1711 .ml_name = "poll",
1712 .ml_meth = (PyCFunction)pyrf_evlist__poll,
1713 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1714 .ml_doc = PyDoc_STR("poll the file descriptor table.")
1715 },
1716 {
1717 .ml_name = "get_pollfd",
1718 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
1719 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1720 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
1721 },
1722 {
1723 .ml_name = "add",
1724 .ml_meth = (PyCFunction)pyrf_evlist__add,
1725 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1726 .ml_doc = PyDoc_STR("adds an event selector to the list.")
1727 },
1728 {
1729 .ml_name = "read_on_cpu",
1730 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
1731 .ml_flags = METH_VARARGS | METH_KEYWORDS,
1732 .ml_doc = PyDoc_STR("reads an event.")
1733 },
1734 {
1735 .ml_name = "config",
1736 .ml_meth = (PyCFunction)pyrf_evlist__config,
1737 .ml_flags = METH_NOARGS,
1738 .ml_doc = PyDoc_STR("Apply default record options to the evlist.")
1739 },
1740 {
1741 .ml_name = "disable",
1742 .ml_meth = (PyCFunction)pyrf_evlist__disable,
1743 .ml_flags = METH_NOARGS,
1744 .ml_doc = PyDoc_STR("Disable the evsels in the evlist.")
1745 },
1746 {
1747 .ml_name = "enable",
1748 .ml_meth = (PyCFunction)pyrf_evlist__enable,
1749 .ml_flags = METH_NOARGS,
1750 .ml_doc = PyDoc_STR("Enable the evsels in the evlist.")
1751 },
1752 { .ml_name = NULL, }
1753 };
1754
pyrf_evlist__length(PyObject * obj)1755 static Py_ssize_t pyrf_evlist__length(PyObject *obj)
1756 {
1757 struct pyrf_evlist *pevlist = (void *)obj;
1758
1759 return pevlist->evlist.core.nr_entries;
1760 }
1761
pyrf_evlist__item(PyObject * obj,Py_ssize_t i)1762 static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
1763 {
1764 struct pyrf_evlist *pevlist = (void *)obj;
1765 struct evsel *pos;
1766
1767 if (i >= pevlist->evlist.core.nr_entries) {
1768 PyErr_SetString(PyExc_IndexError, "Index out of range");
1769 return NULL;
1770 }
1771
1772 evlist__for_each_entry(&pevlist->evlist, pos) {
1773 if (i-- == 0)
1774 break;
1775 }
1776
1777 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
1778 }
1779
pyrf_evlist__str(PyObject * self)1780 static PyObject *pyrf_evlist__str(PyObject *self)
1781 {
1782 struct pyrf_evlist *pevlist = (void *)self;
1783 struct evsel *pos;
1784 struct strbuf sb = STRBUF_INIT;
1785 bool first = true;
1786 PyObject *result;
1787
1788 strbuf_addstr(&sb, "evlist([");
1789 evlist__for_each_entry(&pevlist->evlist, pos) {
1790 if (!first)
1791 strbuf_addch(&sb, ',');
1792 if (!pos->pmu)
1793 strbuf_addstr(&sb, evsel__name(pos));
1794 else
1795 strbuf_addf(&sb, "%s/%s/", pos->pmu->name, evsel__name(pos));
1796 first = false;
1797 }
1798 strbuf_addstr(&sb, "])");
1799 result = PyUnicode_FromString(sb.buf);
1800 strbuf_release(&sb);
1801 return result;
1802 }
1803
1804 static PySequenceMethods pyrf_evlist__sequence_methods = {
1805 .sq_length = pyrf_evlist__length,
1806 .sq_item = pyrf_evlist__item,
1807 };
1808
1809 static const char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
1810
1811 static PyTypeObject pyrf_evlist__type = {
1812 PyVarObject_HEAD_INIT(NULL, 0)
1813 .tp_name = "perf.evlist",
1814 .tp_basicsize = sizeof(struct pyrf_evlist),
1815 .tp_dealloc = (destructor)pyrf_evlist__delete,
1816 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1817 .tp_as_sequence = &pyrf_evlist__sequence_methods,
1818 .tp_doc = pyrf_evlist__doc,
1819 .tp_methods = pyrf_evlist__methods,
1820 .tp_init = (initproc)pyrf_evlist__init,
1821 .tp_repr = pyrf_evlist__str,
1822 .tp_str = pyrf_evlist__str,
1823 };
1824
pyrf_evlist__setup_types(void)1825 static int pyrf_evlist__setup_types(void)
1826 {
1827 pyrf_evlist__type.tp_new = PyType_GenericNew;
1828 return PyType_Ready(&pyrf_evlist__type);
1829 }
1830
1831 #define PERF_CONST(name) { #name, PERF_##name }
1832
1833 struct perf_constant {
1834 const char *name;
1835 int value;
1836 };
1837
1838 static const struct perf_constant perf__constants[] = {
1839 PERF_CONST(TYPE_HARDWARE),
1840 PERF_CONST(TYPE_SOFTWARE),
1841 PERF_CONST(TYPE_TRACEPOINT),
1842 PERF_CONST(TYPE_HW_CACHE),
1843 PERF_CONST(TYPE_RAW),
1844 PERF_CONST(TYPE_BREAKPOINT),
1845
1846 PERF_CONST(COUNT_HW_CPU_CYCLES),
1847 PERF_CONST(COUNT_HW_INSTRUCTIONS),
1848 PERF_CONST(COUNT_HW_CACHE_REFERENCES),
1849 PERF_CONST(COUNT_HW_CACHE_MISSES),
1850 PERF_CONST(COUNT_HW_BRANCH_INSTRUCTIONS),
1851 PERF_CONST(COUNT_HW_BRANCH_MISSES),
1852 PERF_CONST(COUNT_HW_BUS_CYCLES),
1853 PERF_CONST(COUNT_HW_CACHE_L1D),
1854 PERF_CONST(COUNT_HW_CACHE_L1I),
1855 PERF_CONST(COUNT_HW_CACHE_LL),
1856 PERF_CONST(COUNT_HW_CACHE_DTLB),
1857 PERF_CONST(COUNT_HW_CACHE_ITLB),
1858 PERF_CONST(COUNT_HW_CACHE_BPU),
1859 PERF_CONST(COUNT_HW_CACHE_OP_READ),
1860 PERF_CONST(COUNT_HW_CACHE_OP_WRITE),
1861 PERF_CONST(COUNT_HW_CACHE_OP_PREFETCH),
1862 PERF_CONST(COUNT_HW_CACHE_RESULT_ACCESS),
1863 PERF_CONST(COUNT_HW_CACHE_RESULT_MISS),
1864
1865 PERF_CONST(COUNT_HW_STALLED_CYCLES_FRONTEND),
1866 PERF_CONST(COUNT_HW_STALLED_CYCLES_BACKEND),
1867
1868 PERF_CONST(COUNT_SW_CPU_CLOCK),
1869 PERF_CONST(COUNT_SW_TASK_CLOCK),
1870 PERF_CONST(COUNT_SW_PAGE_FAULTS),
1871 PERF_CONST(COUNT_SW_CONTEXT_SWITCHES),
1872 PERF_CONST(COUNT_SW_CPU_MIGRATIONS),
1873 PERF_CONST(COUNT_SW_PAGE_FAULTS_MIN),
1874 PERF_CONST(COUNT_SW_PAGE_FAULTS_MAJ),
1875 PERF_CONST(COUNT_SW_ALIGNMENT_FAULTS),
1876 PERF_CONST(COUNT_SW_EMULATION_FAULTS),
1877 PERF_CONST(COUNT_SW_DUMMY),
1878
1879 PERF_CONST(SAMPLE_IP),
1880 PERF_CONST(SAMPLE_TID),
1881 PERF_CONST(SAMPLE_TIME),
1882 PERF_CONST(SAMPLE_ADDR),
1883 PERF_CONST(SAMPLE_READ),
1884 PERF_CONST(SAMPLE_CALLCHAIN),
1885 PERF_CONST(SAMPLE_ID),
1886 PERF_CONST(SAMPLE_CPU),
1887 PERF_CONST(SAMPLE_PERIOD),
1888 PERF_CONST(SAMPLE_STREAM_ID),
1889 PERF_CONST(SAMPLE_RAW),
1890
1891 PERF_CONST(FORMAT_TOTAL_TIME_ENABLED),
1892 PERF_CONST(FORMAT_TOTAL_TIME_RUNNING),
1893 PERF_CONST(FORMAT_ID),
1894 PERF_CONST(FORMAT_GROUP),
1895
1896 PERF_CONST(RECORD_MMAP),
1897 PERF_CONST(RECORD_LOST),
1898 PERF_CONST(RECORD_COMM),
1899 PERF_CONST(RECORD_EXIT),
1900 PERF_CONST(RECORD_THROTTLE),
1901 PERF_CONST(RECORD_UNTHROTTLE),
1902 PERF_CONST(RECORD_FORK),
1903 PERF_CONST(RECORD_READ),
1904 PERF_CONST(RECORD_SAMPLE),
1905 PERF_CONST(RECORD_MMAP2),
1906 PERF_CONST(RECORD_AUX),
1907 PERF_CONST(RECORD_ITRACE_START),
1908 PERF_CONST(RECORD_LOST_SAMPLES),
1909 PERF_CONST(RECORD_SWITCH),
1910 PERF_CONST(RECORD_SWITCH_CPU_WIDE),
1911
1912 PERF_CONST(RECORD_MISC_SWITCH_OUT),
1913 { .name = NULL, },
1914 };
1915
pyrf__tracepoint(struct pyrf_evsel * pevsel,PyObject * args,PyObject * kwargs)1916 static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel,
1917 PyObject *args, PyObject *kwargs)
1918 {
1919 static char *kwlist[] = { "sys", "name", NULL };
1920 char *sys = NULL;
1921 char *name = NULL;
1922
1923 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ss", kwlist,
1924 &sys, &name))
1925 return NULL;
1926
1927 return PyLong_FromLong(tp_pmu__id(sys, name));
1928 }
1929
pyrf_evsel__from_evsel(struct evsel * evsel)1930 static PyObject *pyrf_evsel__from_evsel(struct evsel *evsel)
1931 {
1932 struct pyrf_evsel *pevsel = PyObject_New(struct pyrf_evsel, &pyrf_evsel__type);
1933
1934 if (!pevsel)
1935 return NULL;
1936
1937 memset(&pevsel->evsel, 0, sizeof(pevsel->evsel));
1938 evsel__init(&pevsel->evsel, &evsel->core.attr, evsel->core.idx);
1939
1940 evsel__clone(&pevsel->evsel, evsel);
1941 if (evsel__is_group_leader(evsel))
1942 evsel__set_leader(&pevsel->evsel, &pevsel->evsel);
1943 return (PyObject *)pevsel;
1944 }
1945
evlist__pos(struct evlist * evlist,struct evsel * evsel)1946 static int evlist__pos(struct evlist *evlist, struct evsel *evsel)
1947 {
1948 struct evsel *pos;
1949 int idx = 0;
1950
1951 evlist__for_each_entry(evlist, pos) {
1952 if (evsel == pos)
1953 return idx;
1954 idx++;
1955 }
1956 return -1;
1957 }
1958
evlist__at(struct evlist * evlist,int idx)1959 static struct evsel *evlist__at(struct evlist *evlist, int idx)
1960 {
1961 struct evsel *pos;
1962 int idx2 = 0;
1963
1964 evlist__for_each_entry(evlist, pos) {
1965 if (idx == idx2)
1966 return pos;
1967 idx2++;
1968 }
1969 return NULL;
1970 }
1971
pyrf_evlist__from_evlist(struct evlist * evlist)1972 static PyObject *pyrf_evlist__from_evlist(struct evlist *evlist)
1973 {
1974 struct pyrf_evlist *pevlist = PyObject_New(struct pyrf_evlist, &pyrf_evlist__type);
1975 struct evsel *pos;
1976 struct rb_node *node;
1977
1978 if (!pevlist)
1979 return NULL;
1980
1981 memset(&pevlist->evlist, 0, sizeof(pevlist->evlist));
1982 evlist__init(&pevlist->evlist, evlist->core.all_cpus, evlist->core.threads);
1983 evlist__for_each_entry(evlist, pos) {
1984 struct pyrf_evsel *pevsel = (void *)pyrf_evsel__from_evsel(pos);
1985
1986 evlist__add(&pevlist->evlist, &pevsel->evsel);
1987 }
1988 evlist__for_each_entry(&pevlist->evlist, pos) {
1989 struct evsel *leader = evsel__leader(pos);
1990
1991 if (pos != leader) {
1992 int idx = evlist__pos(evlist, leader);
1993
1994 if (idx >= 0)
1995 evsel__set_leader(pos, evlist__at(&pevlist->evlist, idx));
1996 else if (leader == NULL)
1997 evsel__set_leader(pos, pos);
1998 }
1999 }
2000 metricgroup__copy_metric_events(&pevlist->evlist, /*cgrp=*/NULL,
2001 &pevlist->evlist.metric_events,
2002 &evlist->metric_events);
2003 for (node = rb_first_cached(&pevlist->evlist.metric_events.entries); node;
2004 node = rb_next(node)) {
2005 struct metric_event *me = container_of(node, struct metric_event, nd);
2006 struct list_head *mpos;
2007 int idx = evlist__pos(evlist, me->evsel);
2008
2009 if (idx >= 0)
2010 me->evsel = evlist__at(&pevlist->evlist, idx);
2011 list_for_each(mpos, &me->head) {
2012 struct metric_expr *e = container_of(mpos, struct metric_expr, nd);
2013
2014 for (int j = 0; e->metric_events[j]; j++) {
2015 idx = evlist__pos(evlist, e->metric_events[j]);
2016 if (idx >= 0)
2017 e->metric_events[j] = evlist__at(&pevlist->evlist, idx);
2018 }
2019 }
2020 }
2021 return (PyObject *)pevlist;
2022 }
2023
pyrf__parse_events(PyObject * self,PyObject * args)2024 static PyObject *pyrf__parse_events(PyObject *self, PyObject *args)
2025 {
2026 const char *input;
2027 struct evlist evlist = {};
2028 struct parse_events_error err;
2029 PyObject *result;
2030 PyObject *pcpus = NULL, *pthreads = NULL;
2031 struct perf_cpu_map *cpus;
2032 struct perf_thread_map *threads;
2033
2034 if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
2035 return NULL;
2036
2037 threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
2038 cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
2039
2040 parse_events_error__init(&err);
2041 evlist__init(&evlist, cpus, threads);
2042 if (parse_events(&evlist, input, &err)) {
2043 parse_events_error__print(&err, input);
2044 PyErr_SetFromErrno(PyExc_OSError);
2045 return NULL;
2046 }
2047 result = pyrf_evlist__from_evlist(&evlist);
2048 evlist__exit(&evlist);
2049 return result;
2050 }
2051
pyrf__parse_metrics(PyObject * self,PyObject * args)2052 static PyObject *pyrf__parse_metrics(PyObject *self, PyObject *args)
2053 {
2054 const char *input;
2055 struct evlist evlist = {};
2056 PyObject *result;
2057 PyObject *pcpus = NULL, *pthreads = NULL;
2058 struct perf_cpu_map *cpus;
2059 struct perf_thread_map *threads;
2060 int ret;
2061
2062 if (!PyArg_ParseTuple(args, "s|OO", &input, &pcpus, &pthreads))
2063 return NULL;
2064
2065 threads = pthreads ? ((struct pyrf_thread_map *)pthreads)->threads : NULL;
2066 cpus = pcpus ? ((struct pyrf_cpu_map *)pcpus)->cpus : NULL;
2067
2068 evlist__init(&evlist, cpus, threads);
2069 ret = metricgroup__parse_groups(&evlist, /*pmu=*/"all", input,
2070 /*metric_no_group=*/ false,
2071 /*metric_no_merge=*/ false,
2072 /*metric_no_threshold=*/ true,
2073 /*user_requested_cpu_list=*/ NULL,
2074 /*system_wide=*/true,
2075 /*hardware_aware_grouping=*/ false);
2076 if (ret) {
2077 errno = -ret;
2078 PyErr_SetFromErrno(PyExc_OSError);
2079 return NULL;
2080 }
2081 result = pyrf_evlist__from_evlist(&evlist);
2082 evlist__exit(&evlist);
2083 return result;
2084 }
2085
pyrf__metrics_groups(const struct pmu_metric * pm)2086 static PyObject *pyrf__metrics_groups(const struct pmu_metric *pm)
2087 {
2088 PyObject *groups = PyList_New(/*len=*/0);
2089 const char *mg = pm->metric_group;
2090
2091 if (!groups)
2092 return NULL;
2093
2094 while (mg) {
2095 PyObject *val = NULL;
2096 const char *sep = strchr(mg, ';');
2097 size_t len = sep ? (size_t)(sep - mg) : strlen(mg);
2098
2099 if (len > 0) {
2100 val = PyUnicode_FromStringAndSize(mg, len);
2101 if (val)
2102 PyList_Append(groups, val);
2103
2104 Py_XDECREF(val);
2105 }
2106 mg = sep ? sep + 1 : NULL;
2107 }
2108 return groups;
2109 }
2110
pyrf__metrics_cb(const struct pmu_metric * pm,const struct pmu_metrics_table * table __maybe_unused,void * vdata)2111 static int pyrf__metrics_cb(const struct pmu_metric *pm,
2112 const struct pmu_metrics_table *table __maybe_unused,
2113 void *vdata)
2114 {
2115 PyObject *py_list = vdata;
2116 PyObject *dict = PyDict_New();
2117 PyObject *key = dict ? PyUnicode_FromString("MetricGroup") : NULL;
2118 PyObject *value = key ? pyrf__metrics_groups(pm) : NULL;
2119
2120 if (!value || PyDict_SetItem(dict, key, value) != 0) {
2121 Py_XDECREF(key);
2122 Py_XDECREF(value);
2123 Py_XDECREF(dict);
2124 return -ENOMEM;
2125 }
2126
2127 if (!add_to_dict(dict, "MetricName", pm->metric_name) ||
2128 !add_to_dict(dict, "PMU", pm->pmu) ||
2129 !add_to_dict(dict, "MetricExpr", pm->metric_expr) ||
2130 !add_to_dict(dict, "MetricThreshold", pm->metric_threshold) ||
2131 !add_to_dict(dict, "ScaleUnit", pm->unit) ||
2132 !add_to_dict(dict, "Compat", pm->compat) ||
2133 !add_to_dict(dict, "BriefDescription", pm->desc) ||
2134 !add_to_dict(dict, "PublicDescription", pm->long_desc) ||
2135 PyList_Append(py_list, dict) != 0) {
2136 Py_DECREF(dict);
2137 return -ENOMEM;
2138 }
2139 Py_DECREF(dict);
2140 return 0;
2141 }
2142
pyrf__metrics(PyObject * self,PyObject * args)2143 static PyObject *pyrf__metrics(PyObject *self, PyObject *args)
2144 {
2145 const struct pmu_metrics_table *table = pmu_metrics_table__find();
2146 PyObject *list = PyList_New(/*len=*/0);
2147 int ret;
2148
2149 if (!list)
2150 return NULL;
2151
2152 ret = pmu_metrics_table__for_each_metric(table, pyrf__metrics_cb, list);
2153 if (!ret)
2154 ret = pmu_for_each_sys_metric(pyrf__metrics_cb, list);
2155
2156 if (ret) {
2157 Py_DECREF(list);
2158 errno = -ret;
2159 PyErr_SetFromErrno(PyExc_OSError);
2160 return NULL;
2161 }
2162 return list;
2163 }
2164
2165 static PyMethodDef perf__methods[] = {
2166 {
2167 .ml_name = "metrics",
2168 .ml_meth = (PyCFunction) pyrf__metrics,
2169 .ml_flags = METH_NOARGS,
2170 .ml_doc = PyDoc_STR(
2171 "Returns a list of metrics represented as string values in dictionaries.")
2172 },
2173 {
2174 .ml_name = "tracepoint",
2175 .ml_meth = (PyCFunction) pyrf__tracepoint,
2176 .ml_flags = METH_VARARGS | METH_KEYWORDS,
2177 .ml_doc = PyDoc_STR("Get tracepoint config.")
2178 },
2179 {
2180 .ml_name = "parse_events",
2181 .ml_meth = (PyCFunction) pyrf__parse_events,
2182 .ml_flags = METH_VARARGS,
2183 .ml_doc = PyDoc_STR("Parse a string of events and return an evlist.")
2184 },
2185 {
2186 .ml_name = "parse_metrics",
2187 .ml_meth = (PyCFunction) pyrf__parse_metrics,
2188 .ml_flags = METH_VARARGS,
2189 .ml_doc = PyDoc_STR(
2190 "Parse a string of metrics or metric groups and return an evlist.")
2191 },
2192 {
2193 .ml_name = "pmus",
2194 .ml_meth = (PyCFunction) pyrf__pmus,
2195 .ml_flags = METH_NOARGS,
2196 .ml_doc = PyDoc_STR("Returns a sequence of pmus.")
2197 },
2198 { .ml_name = NULL, }
2199 };
2200
PyInit_perf(void)2201 PyMODINIT_FUNC PyInit_perf(void)
2202 {
2203 PyObject *obj;
2204 int i;
2205 PyObject *dict;
2206 static struct PyModuleDef moduledef = {
2207 PyModuleDef_HEAD_INIT,
2208 "perf", /* m_name */
2209 "", /* m_doc */
2210 -1, /* m_size */
2211 perf__methods, /* m_methods */
2212 NULL, /* m_reload */
2213 NULL, /* m_traverse */
2214 NULL, /* m_clear */
2215 NULL, /* m_free */
2216 };
2217 PyObject *module = PyModule_Create(&moduledef);
2218
2219 if (module == NULL ||
2220 pyrf_event__setup_types() < 0 ||
2221 pyrf_evlist__setup_types() < 0 ||
2222 pyrf_evsel__setup_types() < 0 ||
2223 pyrf_thread_map__setup_types() < 0 ||
2224 pyrf_cpu_map__setup_types() < 0 ||
2225 pyrf_pmu_iterator__setup_types() < 0 ||
2226 pyrf_pmu__setup_types() < 0 ||
2227 pyrf_counts_values__setup_types() < 0)
2228 return module;
2229
2230 /* The page_size is placed in util object. */
2231 page_size = sysconf(_SC_PAGE_SIZE);
2232
2233 Py_INCREF(&pyrf_evlist__type);
2234 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
2235
2236 Py_INCREF(&pyrf_evsel__type);
2237 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
2238
2239 Py_INCREF(&pyrf_mmap_event__type);
2240 PyModule_AddObject(module, "mmap_event", (PyObject *)&pyrf_mmap_event__type);
2241
2242 Py_INCREF(&pyrf_lost_event__type);
2243 PyModule_AddObject(module, "lost_event", (PyObject *)&pyrf_lost_event__type);
2244
2245 Py_INCREF(&pyrf_comm_event__type);
2246 PyModule_AddObject(module, "comm_event", (PyObject *)&pyrf_comm_event__type);
2247
2248 Py_INCREF(&pyrf_task_event__type);
2249 PyModule_AddObject(module, "task_event", (PyObject *)&pyrf_task_event__type);
2250
2251 Py_INCREF(&pyrf_throttle_event__type);
2252 PyModule_AddObject(module, "throttle_event", (PyObject *)&pyrf_throttle_event__type);
2253
2254 Py_INCREF(&pyrf_task_event__type);
2255 PyModule_AddObject(module, "task_event", (PyObject *)&pyrf_task_event__type);
2256
2257 Py_INCREF(&pyrf_read_event__type);
2258 PyModule_AddObject(module, "read_event", (PyObject *)&pyrf_read_event__type);
2259
2260 Py_INCREF(&pyrf_sample_event__type);
2261 PyModule_AddObject(module, "sample_event", (PyObject *)&pyrf_sample_event__type);
2262
2263 Py_INCREF(&pyrf_context_switch_event__type);
2264 PyModule_AddObject(module, "switch_event", (PyObject *)&pyrf_context_switch_event__type);
2265
2266 Py_INCREF(&pyrf_thread_map__type);
2267 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
2268
2269 Py_INCREF(&pyrf_cpu_map__type);
2270 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
2271
2272 Py_INCREF(&pyrf_counts_values__type);
2273 PyModule_AddObject(module, "counts_values", (PyObject *)&pyrf_counts_values__type);
2274
2275 dict = PyModule_GetDict(module);
2276 if (dict == NULL)
2277 goto error;
2278
2279 for (i = 0; perf__constants[i].name != NULL; i++) {
2280 obj = PyLong_FromLong(perf__constants[i].value);
2281 if (obj == NULL)
2282 goto error;
2283 PyDict_SetItemString(dict, perf__constants[i].name, obj);
2284 Py_DECREF(obj);
2285 }
2286
2287 error:
2288 if (PyErr_Occurred())
2289 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
2290 return module;
2291 }
2292