aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/python.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2011-01-29 12:44:29 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-01-30 08:37:38 -0500
commit877108e42b1b9ba64857c4030cf356ecc120fd18 (patch)
treeca41fa741081faa0f936b7296d721c84d1b89176 /tools/perf/util/python.c
parent8115d60c323dd9931b95221c0a392aeddc1d6ef3 (diff)
perf tools: Initial python binding
First clarifying that this kind of binding is not a replacement or an equivalent to the 'perf script' way of using python with perf. The 'perf script' way is to process events and look at a given script for some python function that matches the events to pass each event for processing. This is a python module, i.e. everything is driven from the python script, that merely uses "import perf" or "from perf import". perf script is focused on tracepoints, this binding is focused on profiling as an initial target. More work is needed to make available tracepoint specific variables as event variables accessible via this binding. There is one example of such usage model, in tools/perf/python/twatch.py, a tool to watch "cycles" events together with task (fork, exit) and comm perf events. For now, due to me not being able to grok how python distutils cope with building C extensions outside the sources dir the install target just builds it, I'm using it as: [root@emilia linux]# export PYTHONPATH=~acme/git/build/perf/lib.linux-x86_64-2.6/ [root@emilia linux]# tools/perf/python/twatch.py cpu: 4, pid: 30126, tid: 30126 { type: mmap, pid: 30126, tid: 30126, start: 0x4, length: 0x82e9ca03, offset: 0, filename: } cpu: 6, pid: 47, tid: 47 { type: mmap, pid: 47, tid: 47, start: 0x6, length: 0xbef87c36, offset: 0, filename: } cpu: 1, pid: 0, tid: 0 { type: mmap, pid: 0, tid: 0, start: 0x1, length: 0x775d1904, offset: 0, filename: } cpu: 7, pid: 0, tid: 0 { type: mmap, pid: 0, tid: 0, start: 0x7, length: 0xc750aeb6, offset: 0, filename: } cpu: 5, pid: 2255, tid: 2255 { type: mmap, pid: 2255, tid: 2255, start: 0x5, length: 0x76669635, offset: 0, filename: } cpu: 0, pid: 0, tid: 0 { type: mmap, pid: 0, tid: 0, start: 0, length: 0x6422ef6b, offset: 0, filename: } cpu: 2, pid: 2255, tid: 2255 { type: mmap, pid: 2255, tid: 2255, start: 0x2, length: 0xe078757a, offset: 0, filename: } cpu: 1, pid: 5769, tid: 5769 { type: fork, pid: 30127, ppid: 5769, tid: 30127, ptid: 5769, time: 103893991270534} cpu: 6, pid: 30127, tid: 30127 { type: comm, pid: 30127, tid: 30127, comm: ls } cpu: 6, pid: 30127, tid: 30127 { type: exit, pid: 30127, ppid: 30127, tid: 30127, ptid: 30127, time: 103893993273024} The first 8 mmap events in this 8 way machine are a mistery that is still being investigated. More of the tools/perf/util/ APIs will be exposed via this python binding as the need arises. For now the focus is on creating events and processing them, symbol resolution is an obvious next step, with tracepoint variables as a close second step. Cc: Clark Williams <williams@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/python.c')
-rw-r--r--tools/perf/util/python.c888
1 files changed, 888 insertions, 0 deletions
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
new file mode 100644
index 000000000000..88d47895a79c
--- /dev/null
+++ b/tools/perf/util/python.c
@@ -0,0 +1,888 @@
1#include <Python.h>
2#include <structmember.h>
3#include <inttypes.h>
4#include <poll.h>
5#include "evlist.h"
6#include "evsel.h"
7#include "event.h"
8#include "cpumap.h"
9#include "thread_map.h"
10
11struct throttle_event {
12 struct perf_event_header header;
13 u64 time;
14 u64 id;
15 u64 stream_id;
16};
17
18#define member_def(type, member, ptype, help) \
19 { #member, ptype, \
20 offsetof(struct pyrf_event, event) + offsetof(struct type, member), \
21 0, help }
22
23#define sample_member_def(name, member, ptype, help) \
24 { #name, ptype, \
25 offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \
26 0, help }
27
28struct pyrf_event {
29 PyObject_HEAD
30 struct perf_sample sample;
31 union perf_event event;
32};
33
34#define T_ULONG_LONG T_ULONG
35
36#define sample_members \
37 sample_member_def(sample_ip, ip, T_ULONG_LONG, "event type"), \
38 sample_member_def(sample_pid, pid, T_INT, "event pid"), \
39 sample_member_def(sample_tid, tid, T_INT, "event tid"), \
40 sample_member_def(sample_time, time, T_ULONG_LONG, "event timestamp"), \
41 sample_member_def(sample_addr, addr, T_ULONG_LONG, "event addr"), \
42 sample_member_def(sample_id, id, T_ULONG_LONG, "event id"), \
43 sample_member_def(sample_stream_id, stream_id, T_ULONG_LONG, "event stream id"), \
44 sample_member_def(sample_period, period, T_ULONG_LONG, "event period"), \
45 sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"),
46
47static char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object.");
48
49static PyMemberDef pyrf_mmap_event__members[] = {
50 sample_members
51 member_def(perf_event_header, type, T_UINT, "event type"),
52 member_def(mmap_event, pid, T_UINT, "event pid"),
53 member_def(mmap_event, tid, T_UINT, "event tid"),
54 member_def(mmap_event, start, T_ULONG_LONG, "start of the map"),
55 member_def(mmap_event, len, T_ULONG_LONG, "map length"),
56 member_def(mmap_event, pgoff, T_ULONG_LONG, "page offset"),
57 member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"),
58 { NULL, },
59};
60
61static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent)
62{
63 PyObject *ret;
64 char *s;
65
66 if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", "
67 "length: %#" PRIx64 ", offset: %#" PRIx64 ", "
68 "filename: %s }",
69 pevent->event.mmap.pid, pevent->event.mmap.tid,
70 pevent->event.mmap.start, pevent->event.mmap.len,
71 pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) {
72 ret = PyErr_NoMemory();
73 } else {
74 ret = PyString_FromString(s);
75 free(s);
76 }
77 return ret;
78}
79
80static PyTypeObject pyrf_mmap_event__type = {
81 PyVarObject_HEAD_INIT(NULL, 0)
82 .tp_name = "perf.mmap_event",
83 .tp_basicsize = sizeof(struct pyrf_event),
84 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
85 .tp_doc = pyrf_mmap_event__doc,
86 .tp_members = pyrf_mmap_event__members,
87 .tp_repr = (reprfunc)pyrf_mmap_event__repr,
88};
89
90static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object.");
91
92static PyMemberDef pyrf_task_event__members[] = {
93 sample_members
94 member_def(perf_event_header, type, T_UINT, "event type"),
95 member_def(fork_event, pid, T_UINT, "event pid"),
96 member_def(fork_event, ppid, T_UINT, "event ppid"),
97 member_def(fork_event, tid, T_UINT, "event tid"),
98 member_def(fork_event, ptid, T_UINT, "event ptid"),
99 member_def(fork_event, time, T_ULONG_LONG, "timestamp"),
100 { NULL, },
101};
102
103static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent)
104{
105 return PyString_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
106 "ptid: %u, time: %" PRIu64 "}",
107 pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit",
108 pevent->event.fork.pid,
109 pevent->event.fork.ppid,
110 pevent->event.fork.tid,
111 pevent->event.fork.ptid,
112 pevent->event.fork.time);
113}
114
115static PyTypeObject pyrf_task_event__type = {
116 PyVarObject_HEAD_INIT(NULL, 0)
117 .tp_name = "perf.task_event",
118 .tp_basicsize = sizeof(struct pyrf_event),
119 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
120 .tp_doc = pyrf_task_event__doc,
121 .tp_members = pyrf_task_event__members,
122 .tp_repr = (reprfunc)pyrf_task_event__repr,
123};
124
125static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object.");
126
127static PyMemberDef pyrf_comm_event__members[] = {
128 sample_members
129 member_def(perf_event_header, type, T_UINT, "event type"),
130 member_def(comm_event, pid, T_UINT, "event pid"),
131 member_def(comm_event, tid, T_UINT, "event tid"),
132 member_def(comm_event, comm, T_STRING_INPLACE, "process name"),
133 { NULL, },
134};
135
136static PyObject *pyrf_comm_event__repr(struct pyrf_event *pevent)
137{
138 return PyString_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
139 pevent->event.comm.pid,
140 pevent->event.comm.tid,
141 pevent->event.comm.comm);
142}
143
144static PyTypeObject pyrf_comm_event__type = {
145 PyVarObject_HEAD_INIT(NULL, 0)
146 .tp_name = "perf.comm_event",
147 .tp_basicsize = sizeof(struct pyrf_event),
148 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
149 .tp_doc = pyrf_comm_event__doc,
150 .tp_members = pyrf_comm_event__members,
151 .tp_repr = (reprfunc)pyrf_comm_event__repr,
152};
153
154static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object.");
155
156static PyMemberDef pyrf_throttle_event__members[] = {
157 sample_members
158 member_def(perf_event_header, type, T_UINT, "event type"),
159 member_def(throttle_event, time, T_ULONG_LONG, "timestamp"),
160 member_def(throttle_event, id, T_ULONG_LONG, "event id"),
161 member_def(throttle_event, stream_id, T_ULONG_LONG, "event stream id"),
162 { NULL, },
163};
164
165static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent)
166{
167 struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1);
168
169 return PyString_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64
170 ", stream_id: %" PRIu64 " }",
171 pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un",
172 te->time, te->id, te->stream_id);
173}
174
175static PyTypeObject pyrf_throttle_event__type = {
176 PyVarObject_HEAD_INIT(NULL, 0)
177 .tp_name = "perf.throttle_event",
178 .tp_basicsize = sizeof(struct pyrf_event),
179 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
180 .tp_doc = pyrf_throttle_event__doc,
181 .tp_members = pyrf_throttle_event__members,
182 .tp_repr = (reprfunc)pyrf_throttle_event__repr,
183};
184
185static int pyrf_event__setup_types(void)
186{
187 int err;
188 pyrf_mmap_event__type.tp_new =
189 pyrf_task_event__type.tp_new =
190 pyrf_comm_event__type.tp_new =
191 pyrf_throttle_event__type.tp_new = PyType_GenericNew;
192 err = PyType_Ready(&pyrf_mmap_event__type);
193 if (err < 0)
194 goto out;
195 err = PyType_Ready(&pyrf_task_event__type);
196 if (err < 0)
197 goto out;
198 err = PyType_Ready(&pyrf_comm_event__type);
199 if (err < 0)
200 goto out;
201 err = PyType_Ready(&pyrf_throttle_event__type);
202 if (err < 0)
203 goto out;
204out:
205 return err;
206}
207
208static PyTypeObject *pyrf_event__type[] = {
209 [PERF_RECORD_MMAP] = &pyrf_mmap_event__type,
210 [PERF_RECORD_LOST] = &pyrf_mmap_event__type,
211 [PERF_RECORD_COMM] = &pyrf_comm_event__type,
212 [PERF_RECORD_EXIT] = &pyrf_task_event__type,
213 [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type,
214 [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type,
215 [PERF_RECORD_FORK] = &pyrf_task_event__type,
216 [PERF_RECORD_READ] = &pyrf_mmap_event__type,
217 [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type,
218};
219
220static PyObject *pyrf_event__new(union perf_event *event)
221{
222 struct pyrf_event *pevent;
223 PyTypeObject *ptype;
224
225 if (event->header.type < PERF_RECORD_MMAP ||
226 event->header.type > PERF_RECORD_SAMPLE)
227 return NULL;
228
229 ptype = pyrf_event__type[event->header.type];
230 pevent = PyObject_New(struct pyrf_event, ptype);
231 if (pevent != NULL)
232 memcpy(&pevent->event, event, event->header.size);
233 return (PyObject *)pevent;
234}
235
236struct pyrf_cpu_map {
237 PyObject_HEAD
238
239 struct cpu_map *cpus;
240};
241
242static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
243 PyObject *args, PyObject *kwargs)
244{
245 static char *kwlist[] = { "cpustr", NULL, NULL, };
246 char *cpustr = NULL;
247
248 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s",
249 kwlist, &cpustr))
250 return -1;
251
252 pcpus->cpus = cpu_map__new(cpustr);
253 if (pcpus->cpus == NULL)
254 return -1;
255 return 0;
256}
257
258static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
259{
260 cpu_map__delete(pcpus->cpus);
261 pcpus->ob_type->tp_free((PyObject*)pcpus);
262}
263
264static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
265{
266 struct pyrf_cpu_map *pcpus = (void *)obj;
267
268 return pcpus->cpus->nr;
269}
270
271static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i)
272{
273 struct pyrf_cpu_map *pcpus = (void *)obj;
274
275 if (i >= pcpus->cpus->nr)
276 return NULL;
277
278 return Py_BuildValue("i", pcpus->cpus->map[i]);
279}
280
281static PySequenceMethods pyrf_cpu_map__sequence_methods = {
282 .sq_length = pyrf_cpu_map__length,
283 .sq_item = pyrf_cpu_map__item,
284};
285
286static char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object.");
287
288static PyTypeObject pyrf_cpu_map__type = {
289 PyVarObject_HEAD_INIT(NULL, 0)
290 .tp_name = "perf.cpu_map",
291 .tp_basicsize = sizeof(struct pyrf_cpu_map),
292 .tp_dealloc = (destructor)pyrf_cpu_map__delete,
293 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
294 .tp_doc = pyrf_cpu_map__doc,
295 .tp_as_sequence = &pyrf_cpu_map__sequence_methods,
296 .tp_init = (initproc)pyrf_cpu_map__init,
297};
298
299static int pyrf_cpu_map__setup_types(void)
300{
301 pyrf_cpu_map__type.tp_new = PyType_GenericNew;
302 return PyType_Ready(&pyrf_cpu_map__type);
303}
304
305struct pyrf_thread_map {
306 PyObject_HEAD
307
308 struct thread_map *threads;
309};
310
311static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
312 PyObject *args, PyObject *kwargs)
313{
314 static char *kwlist[] = { "pid", "tid", NULL, NULL, };
315 int pid = -1, tid = -1;
316
317 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
318 kwlist, &pid, &tid))
319 return -1;
320
321 pthreads->threads = thread_map__new(pid, tid);
322 if (pthreads->threads == NULL)
323 return -1;
324 return 0;
325}
326
327static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
328{
329 thread_map__delete(pthreads->threads);
330 pthreads->ob_type->tp_free((PyObject*)pthreads);
331}
332
333static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
334{
335 struct pyrf_thread_map *pthreads = (void *)obj;
336
337 return pthreads->threads->nr;
338}
339
340static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i)
341{
342 struct pyrf_thread_map *pthreads = (void *)obj;
343
344 if (i >= pthreads->threads->nr)
345 return NULL;
346
347 return Py_BuildValue("i", pthreads->threads->map[i]);
348}
349
350static PySequenceMethods pyrf_thread_map__sequence_methods = {
351 .sq_length = pyrf_thread_map__length,
352 .sq_item = pyrf_thread_map__item,
353};
354
355static char pyrf_thread_map__doc[] = PyDoc_STR("thread map object.");
356
357static PyTypeObject pyrf_thread_map__type = {
358 PyVarObject_HEAD_INIT(NULL, 0)
359 .tp_name = "perf.thread_map",
360 .tp_basicsize = sizeof(struct pyrf_thread_map),
361 .tp_dealloc = (destructor)pyrf_thread_map__delete,
362 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
363 .tp_doc = pyrf_thread_map__doc,
364 .tp_as_sequence = &pyrf_thread_map__sequence_methods,
365 .tp_init = (initproc)pyrf_thread_map__init,
366};
367
368static int pyrf_thread_map__setup_types(void)
369{
370 pyrf_thread_map__type.tp_new = PyType_GenericNew;
371 return PyType_Ready(&pyrf_thread_map__type);
372}
373
374struct pyrf_evsel {
375 PyObject_HEAD
376
377 struct perf_evsel evsel;
378};
379
380static int pyrf_evsel__init(struct pyrf_evsel *pevsel,
381 PyObject *args, PyObject *kwargs)
382{
383 struct perf_event_attr attr = {
384 .type = PERF_TYPE_HARDWARE,
385 .config = PERF_COUNT_HW_CPU_CYCLES,
386 .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID,
387 };
388 static char *kwlist[] = {
389 "type",
390 "config",
391 "sample_freq",
392 "sample_period",
393 "sample_type",
394 "read_format",
395 "disabled",
396 "inherit",
397 "pinned",
398 "exclusive",
399 "exclude_user",
400 "exclude_kernel",
401 "exclude_hv",
402 "exclude_idle",
403 "mmap",
404 "comm",
405 "freq",
406 "inherit_stat",
407 "enable_on_exec",
408 "task",
409 "watermark",
410 "precise_ip",
411 "mmap_data",
412 "sample_id_all",
413 "wakeup_events",
414 "bp_type",
415 "bp_addr",
416 "bp_len", NULL, NULL, };
417 u64 sample_period = 0;
418 u32 disabled = 0,
419 inherit = 0,
420 pinned = 0,
421 exclusive = 0,
422 exclude_user = 0,
423 exclude_kernel = 0,
424 exclude_hv = 0,
425 exclude_idle = 0,
426 mmap = 0,
427 comm = 0,
428 freq = 1,
429 inherit_stat = 0,
430 enable_on_exec = 0,
431 task = 0,
432 watermark = 0,
433 precise_ip = 0,
434 mmap_data = 0,
435 sample_id_all = 1;
436 int idx = 0;
437
438 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
439 "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist,
440 &attr.type, &attr.config, &attr.sample_freq,
441 &sample_period, &attr.sample_type,
442 &attr.read_format, &disabled, &inherit,
443 &pinned, &exclusive, &exclude_user,
444 &exclude_kernel, &exclude_hv, &exclude_idle,
445 &mmap, &comm, &freq, &inherit_stat,
446 &enable_on_exec, &task, &watermark,
447 &precise_ip, &mmap_data, &sample_id_all,
448 &attr.wakeup_events, &attr.bp_type,
449 &attr.bp_addr, &attr.bp_len, &idx))
450 return -1;
451
452 /* union... */
453 if (sample_period != 0) {
454 if (attr.sample_freq != 0)
455 return -1; /* FIXME: throw right exception */
456 attr.sample_period = sample_period;
457 }
458
459 /* Bitfields */
460 attr.disabled = disabled;
461 attr.inherit = inherit;
462 attr.pinned = pinned;
463 attr.exclusive = exclusive;
464 attr.exclude_user = exclude_user;
465 attr.exclude_kernel = exclude_kernel;
466 attr.exclude_hv = exclude_hv;
467 attr.exclude_idle = exclude_idle;
468 attr.mmap = mmap;
469 attr.comm = comm;
470 attr.freq = freq;
471 attr.inherit_stat = inherit_stat;
472 attr.enable_on_exec = enable_on_exec;
473 attr.task = task;
474 attr.watermark = watermark;
475 attr.precise_ip = precise_ip;
476 attr.mmap_data = mmap_data;
477 attr.sample_id_all = sample_id_all;
478
479 perf_evsel__init(&pevsel->evsel, &attr, idx);
480 return 0;
481}
482
483static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
484{
485 perf_evsel__exit(&pevsel->evsel);
486 pevsel->ob_type->tp_free((PyObject*)pevsel);
487}
488
489static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
490 PyObject *args, PyObject *kwargs)
491{
492 struct perf_evsel *evsel = &pevsel->evsel;
493 struct cpu_map *cpus = NULL;
494 struct thread_map *threads = NULL;
495 PyObject *pcpus = NULL, *pthreads = NULL;
496 int group = 0, overwrite = 0;
497 static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL};
498
499 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist,
500 &pcpus, &pthreads, &group, &overwrite))
501 return NULL;
502
503 if (pthreads != NULL)
504 threads = ((struct pyrf_thread_map *)pthreads)->threads;
505
506 if (pcpus != NULL)
507 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
508
509 if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) {
510 PyErr_SetFromErrno(PyExc_OSError);
511 return NULL;
512 }
513
514 Py_INCREF(Py_None);
515 return Py_None;
516}
517
518static PyMethodDef pyrf_evsel__methods[] = {
519 {
520 .ml_name = "open",
521 .ml_meth = (PyCFunction)pyrf_evsel__open,
522 .ml_flags = METH_VARARGS | METH_KEYWORDS,
523 .ml_doc = PyDoc_STR("open the event selector file descriptor table.")
524 },
525 { NULL, }
526};
527
528static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object.");
529
530static PyTypeObject pyrf_evsel__type = {
531 PyVarObject_HEAD_INIT(NULL, 0)
532 .tp_name = "perf.evsel",
533 .tp_basicsize = sizeof(struct pyrf_evsel),
534 .tp_dealloc = (destructor)pyrf_evsel__delete,
535 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
536 .tp_doc = pyrf_evsel__doc,
537 .tp_methods = pyrf_evsel__methods,
538 .tp_init = (initproc)pyrf_evsel__init,
539};
540
541static int pyrf_evsel__setup_types(void)
542{
543 pyrf_evsel__type.tp_new = PyType_GenericNew;
544 return PyType_Ready(&pyrf_evsel__type);
545}
546
547struct pyrf_evlist {
548 PyObject_HEAD
549
550 struct perf_evlist evlist;
551};
552
553static int pyrf_evlist__init(struct pyrf_evlist *pevlist,
554 PyObject *args, PyObject *kwargs)
555{
556 perf_evlist__init(&pevlist->evlist);
557 return 0;
558}
559
560static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
561{
562 perf_evlist__exit(&pevlist->evlist);
563 pevlist->ob_type->tp_free((PyObject*)pevlist);
564}
565
566static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
567 PyObject *args, PyObject *kwargs)
568{
569 struct perf_evlist *evlist = &pevlist->evlist;
570 PyObject *pcpus = NULL, *pthreads = NULL;
571 struct cpu_map *cpus = NULL;
572 struct thread_map *threads = NULL;
573 static char *kwlist[] = {"cpus", "threads", "pages", "overwrite",
574 NULL, NULL};
575 int pages = 128, overwrite = false;
576
577 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ii", kwlist,
578 &pcpus, &pthreads, &pages, &overwrite))
579 return NULL;
580
581 threads = ((struct pyrf_thread_map *)pthreads)->threads;
582 cpus = ((struct pyrf_cpu_map *)pcpus)->cpus;
583
584 if (perf_evlist__mmap(evlist, cpus, threads, pages, overwrite) < 0) {
585 PyErr_SetFromErrno(PyExc_OSError);
586 return NULL;
587 }
588
589 Py_INCREF(Py_None);
590 return Py_None;
591}
592
593static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist,
594 PyObject *args, PyObject *kwargs)
595{
596 struct perf_evlist *evlist = &pevlist->evlist;
597 static char *kwlist[] = {"timeout", NULL, NULL};
598 int timeout = -1, n;
599
600 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout))
601 return NULL;
602
603 n = poll(evlist->pollfd, evlist->nr_fds, timeout);
604 if (n < 0) {
605 PyErr_SetFromErrno(PyExc_OSError);
606 return NULL;
607 }
608
609 return Py_BuildValue("i", n);
610}
611
612static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist,
613 PyObject *args, PyObject *kwargs)
614{
615 struct perf_evlist *evlist = &pevlist->evlist;
616 PyObject *list = PyList_New(0);
617 int i;
618
619 for (i = 0; i < evlist->nr_fds; ++i) {
620 PyObject *file;
621 FILE *fp = fdopen(evlist->pollfd[i].fd, "r");
622
623 if (fp == NULL)
624 goto free_list;
625
626 file = PyFile_FromFile(fp, "perf", "r", NULL);
627 if (file == NULL)
628 goto free_list;
629
630 if (PyList_Append(list, file) != 0) {
631 Py_DECREF(file);
632 goto free_list;
633 }
634
635 Py_DECREF(file);
636 }
637
638 return list;
639free_list:
640 return PyErr_NoMemory();
641}
642
643
644static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist,
645 PyObject *args, PyObject *kwargs)
646{
647 struct perf_evlist *evlist = &pevlist->evlist;
648 PyObject *pevsel;
649 struct perf_evsel *evsel;
650
651 if (!PyArg_ParseTuple(args, "O", &pevsel))
652 return NULL;
653
654 Py_INCREF(pevsel);
655 evsel = &((struct pyrf_evsel *)pevsel)->evsel;
656 evsel->idx = evlist->nr_entries;
657 perf_evlist__add(evlist, evsel);
658
659 return Py_BuildValue("i", evlist->nr_entries);
660}
661
662static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
663 PyObject *args, PyObject *kwargs)
664{
665 struct perf_evlist *evlist = &pevlist->evlist;
666 union perf_event *event;
667 int sample_id_all = 1, cpu;
668 static char *kwlist[] = {"sample_id_all", NULL, NULL};
669
670 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist,
671 &cpu, &sample_id_all))
672 return NULL;
673
674 event = perf_evlist__read_on_cpu(evlist, cpu);
675 if (event != NULL) {
676 struct perf_evsel *first;
677 PyObject *pyevent = pyrf_event__new(event);
678 struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
679
680 if (pyevent == NULL)
681 return PyErr_NoMemory();
682
683 first = list_entry(evlist->entries.next, struct perf_evsel, node);
684 perf_event__parse_sample(event, first->attr.sample_type, sample_id_all,
685 &pevent->sample);
686 return pyevent;
687 }
688
689 Py_INCREF(Py_None);
690 return Py_None;
691}
692
693static PyMethodDef pyrf_evlist__methods[] = {
694 {
695 .ml_name = "mmap",
696 .ml_meth = (PyCFunction)pyrf_evlist__mmap,
697 .ml_flags = METH_VARARGS | METH_KEYWORDS,
698 .ml_doc = PyDoc_STR("mmap the file descriptor table.")
699 },
700 {
701 .ml_name = "poll",
702 .ml_meth = (PyCFunction)pyrf_evlist__poll,
703 .ml_flags = METH_VARARGS | METH_KEYWORDS,
704 .ml_doc = PyDoc_STR("poll the file descriptor table.")
705 },
706 {
707 .ml_name = "get_pollfd",
708 .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd,
709 .ml_flags = METH_VARARGS | METH_KEYWORDS,
710 .ml_doc = PyDoc_STR("get the poll file descriptor table.")
711 },
712 {
713 .ml_name = "add",
714 .ml_meth = (PyCFunction)pyrf_evlist__add,
715 .ml_flags = METH_VARARGS | METH_KEYWORDS,
716 .ml_doc = PyDoc_STR("adds an event selector to the list.")
717 },
718 {
719 .ml_name = "read_on_cpu",
720 .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu,
721 .ml_flags = METH_VARARGS | METH_KEYWORDS,
722 .ml_doc = PyDoc_STR("reads an event.")
723 },
724 { NULL, }
725};
726
727static Py_ssize_t pyrf_evlist__length(PyObject *obj)
728{
729 struct pyrf_evlist *pevlist = (void *)obj;
730
731 return pevlist->evlist.nr_entries;
732}
733
734static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i)
735{
736 struct pyrf_evlist *pevlist = (void *)obj;
737 struct perf_evsel *pos;
738
739 if (i >= pevlist->evlist.nr_entries)
740 return NULL;
741
742 list_for_each_entry(pos, &pevlist->evlist.entries, node)
743 if (i-- == 0)
744 break;
745
746 return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel));
747}
748
749static PySequenceMethods pyrf_evlist__sequence_methods = {
750 .sq_length = pyrf_evlist__length,
751 .sq_item = pyrf_evlist__item,
752};
753
754static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object.");
755
756static PyTypeObject pyrf_evlist__type = {
757 PyVarObject_HEAD_INIT(NULL, 0)
758 .tp_name = "perf.evlist",
759 .tp_basicsize = sizeof(struct pyrf_evlist),
760 .tp_dealloc = (destructor)pyrf_evlist__delete,
761 .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
762 .tp_as_sequence = &pyrf_evlist__sequence_methods,
763 .tp_doc = pyrf_evlist__doc,
764 .tp_methods = pyrf_evlist__methods,
765 .tp_init = (initproc)pyrf_evlist__init,
766};
767
768static int pyrf_evlist__setup_types(void)
769{
770 pyrf_evlist__type.tp_new = PyType_GenericNew;
771 return PyType_Ready(&pyrf_evlist__type);
772}
773
774static struct {
775 const char *name;
776 int value;
777} perf__constants[] = {
778 { "TYPE_HARDWARE", PERF_TYPE_HARDWARE },
779 { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE },
780 { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT },
781 { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE },
782 { "TYPE_RAW", PERF_TYPE_RAW },
783 { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT },
784
785 { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES },
786 { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS },
787 { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES },
788 { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES },
789 { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
790 { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES },
791 { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES },
792 { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D },
793 { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I },
794 { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL },
795 { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB },
796 { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB },
797 { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU },
798 { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ },
799 { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE },
800 { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH },
801 { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS },
802 { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS },
803
804 { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK },
805 { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK },
806 { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS },
807 { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES },
808 { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS },
809 { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN },
810 { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ },
811 { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS },
812 { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS },
813
814 { "SAMPLE_IP", PERF_SAMPLE_IP },
815 { "SAMPLE_TID", PERF_SAMPLE_TID },
816 { "SAMPLE_TIME", PERF_SAMPLE_TIME },
817 { "SAMPLE_ADDR", PERF_SAMPLE_ADDR },
818 { "SAMPLE_READ", PERF_SAMPLE_READ },
819 { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN },
820 { "SAMPLE_ID", PERF_SAMPLE_ID },
821 { "SAMPLE_CPU", PERF_SAMPLE_CPU },
822 { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD },
823 { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID },
824 { "SAMPLE_RAW", PERF_SAMPLE_RAW },
825
826 { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED },
827 { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING },
828 { "FORMAT_ID", PERF_FORMAT_ID },
829 { "FORMAT_GROUP", PERF_FORMAT_GROUP },
830
831 { "RECORD_MMAP", PERF_RECORD_MMAP },
832 { "RECORD_LOST", PERF_RECORD_LOST },
833 { "RECORD_COMM", PERF_RECORD_COMM },
834 { "RECORD_EXIT", PERF_RECORD_EXIT },
835 { "RECORD_THROTTLE", PERF_RECORD_THROTTLE },
836 { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE },
837 { "RECORD_FORK", PERF_RECORD_FORK },
838 { "RECORD_READ", PERF_RECORD_READ },
839 { "RECORD_SAMPLE", PERF_RECORD_SAMPLE },
840 { NULL, },
841};
842
843static PyMethodDef perf__methods[] = {
844 { NULL, NULL }
845};
846
847PyMODINIT_FUNC initperf(void)
848{
849 PyObject *obj;
850 int i;
851 PyObject *dict, *module = Py_InitModule("perf", perf__methods);
852
853 if (module == NULL ||
854 pyrf_event__setup_types() < 0 ||
855 pyrf_evlist__setup_types() < 0 ||
856 pyrf_evsel__setup_types() < 0 ||
857 pyrf_thread_map__setup_types() < 0 ||
858 pyrf_cpu_map__setup_types() < 0)
859 return;
860
861 Py_INCREF(&pyrf_evlist__type);
862 PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type);
863
864 Py_INCREF(&pyrf_evsel__type);
865 PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type);
866
867 Py_INCREF(&pyrf_thread_map__type);
868 PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type);
869
870 Py_INCREF(&pyrf_cpu_map__type);
871 PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type);
872
873 dict = PyModule_GetDict(module);
874 if (dict == NULL)
875 goto error;
876
877 for (i = 0; perf__constants[i].name != NULL; i++) {
878 obj = PyInt_FromLong(perf__constants[i].value);
879 if (obj == NULL)
880 goto error;
881 PyDict_SetItemString(dict, perf__constants[i].name, obj);
882 Py_DECREF(obj);
883 }
884
885error:
886 if (PyErr_Occurred())
887 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
888}