History

perf tools: Add Python 3 support

Added Python 3 support while keeping Python 2.7 compatibility. Committer notes: This doesn't make it to auto detect python 3, one has to explicitely ask it to build with python 3 devel files, here are the instructions provided by Jaroslav: --- $ cp -a tools/perf tools/python3-perf $ make V=1 prefix=/usr -C tools/perf PYTHON=/usr/bin/python2 all $ make V=1 prefix=/usr -C tools/python3-perf PYTHON=/usr/bin/python3 all $ make V=1 prefix=/usr -C tools/python3-perf PYTHON=/usr/bin/python3 DESTDIR=%{buildroot} install-python_ext $ make V=1 prefix=/usr -C tools/perf PYTHON=/usr/bin/python2 DESTDIR=%{buildroot} install-python_ext --- We need to make this automatic, just like the existing tests for checking if the python2 devel files are in place, allowing the build with python3 if available, fallbacking to python2 and then just disabling it if none are available. So, using the PYTHON variable to build it using O= we get: Before this patch: $ rpm -q python3 python3-devel python3-3.6.4-7.fc27.x86_64 python3-devel-3.6.4-7.fc27.x86_64 $ rm -rf /tmp/build/perf/ ; mkdir -p /tmp/build/perf ; make O=/tmp/build/perf PYTHON=/usr/bin/python3 -C tools/perf install-bin make: Entering directory '/home/acme/git/linux/tools/perf' <SNIP> Makefile.config:670: Python 3 is not yet supported; please set Makefile.config:671: PYTHON and/or PYTHON_CONFIG appropriately. Makefile.config:672: If you also have Python 2 installed, then Makefile.config:673: try something like: Makefile.config:674: Makefile.config:675: make PYTHON=python2 Makefile.config:676: Makefile.config:677: Otherwise, disable Python support entirely: Makefile.config:678: Makefile.config:679: make NO_LIBPYTHON=1 Makefile.config:680: Makefile.config:681: *** . Stop. make[1]: *** [Makefile.perf:212: sub-make] Error 2 make: *** [Makefile:110: install-bin] Error 2 make: Leaving directory '/home/acme/git/linux/tools/perf' $ After: $ make O=/tmp/build/perf PYTHON=python3 -C tools/perf install-bin $ ldd ~/bin/perf | grep python libpython3.6m.so.1.0 => /lib64/libpython3.6m.so.1.0 (0x00007f58a31e8000) $ rpm -qf /lib64/libpython3.6m.so.1.0 python3-libs-3.6.4-7.fc27.x86_64 $ Now verify that when using the binding the right ELF file is loaded, using perf trace: $ perf trace -e open* perf test python 0.051 ( 0.016 ms): perf/3927 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC ) = 3 <SNIP> 18: 'import perf' in python : 8.849 ( 0.013 ms): sh/3929 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC ) = 3 <SNIP> 25.572 ( 0.008 ms): python3/3931 openat(dfd: CWD, filename: /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so, flags: CLOEXEC) = 3 <SNIP> Ok <SNIP> $ And using tools/perf/python/twatch.py, to show PERF_RECORD_ metaevents: $ python3 tools/perf/python/twatch.py cpu: 3, pid: 16060, tid: 16060 { type: fork, pid: 5207, ppid: 16060, tid: 5207, ptid: 16060, time: 10798513015459} cpu: 3, pid: 16060, tid: 16060 { type: fork, pid: 5208, ppid: 16060, tid: 5208, ptid: 16060, time: 10798513562503} cpu: 0, pid: 5208, tid: 5208 { type: comm, pid: 5208, tid: 5208, comm: grep } cpu: 2, pid: 5207, tid: 5207 { type: comm, pid: 5207, tid: 5207, comm: ps } cpu: 2, pid: 5207, tid: 5207 { type: exit, pid: 5207, ppid: 5207, tid: 5207, ptid: 5207, time: 10798551337484} cpu: 3, pid: 5208, tid: 5208 { type: exit, pid: 5208, ppid: 5208, tid: 5208, ptid: 5208, time: 10798551292153} cpu: 3, pid: 601, tid: 601 { type: fork, pid: 5209, ppid: 601, tid: 5209, ptid: 601, time: 10801779977324} ^CTraceback (most recent call last): File "tools/perf/python/twatch.py", line 68, in <module> main() File "tools/perf/python/twatch.py", line 40, in main evlist.poll(timeout = -1) KeyboardInterrupt $ # ps ax|grep twatch 5197 pts/8 S+ 0:00 python3 tools/perf/python/twatch.py # ls -la /proc/5197/smaps -r--r--r--. 1 acme acme 0 Feb 19 13:14 /proc/5197/smaps # grep python /proc/5197/smaps 558111307000-558111309000 r-xp 00000000 fd:00 3151710 /usr/bin/python3.6 558111508000-558111509000 r--p 00001000 fd:00 3151710 /usr/bin/python3.6 558111509000-55811150a000 rw-p 00002000 fd:00 3151710 /usr/bin/python3.6 7ffad6fc1000-7ffad7008000 r-xp 00000000 00:2d 220196 /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so 7ffad7008000-7ffad7207000 ---p 00047000 00:2d 220196 /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so 7ffad7207000-7ffad7208000 r--p 00046000 00:2d 220196 /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so 7ffad7208000-7ffad7215000 rw-p 00047000 00:2d 220196 /tmp/build/perf/python/perf.cpython-36m-x86_64-linux-gnu.so 7ffadea77000-7ffaded3d000 r-xp 00000000 fd:00 3151795 /usr/lib64/libpython3.6m.so.1.0 7ffaded3d000-7ffadef3c000 ---p 002c6000 fd:00 3151795 /usr/lib64/libpython3.6m.so.1.0 7ffadef3c000-7ffadef42000 r--p 002c5000 fd:00 3151795 /usr/lib64/libpython3.6m.so.1.0 7ffadef42000-7ffadefa5000 rw-p 002cb000 fd:00 3151795 /usr/lib64/libpython3.6m.so.1.0 # And with this patch, but building normally, without specifying the PYTHON=python3 part, which will make it use python2 if its devel files are available, like in this test: $ make O=/tmp/build/perf -C tools/perf install-bin $ ldd ~/bin/perf | grep python libpython2.7.so.1.0 => /lib64/libpython2.7.so.1.0 (0x00007f6a44410000) $ ldd /tmp/build/perf/python_ext_build/lib/perf.so | grep python libpython2.7.so.1.0 => /lib64/libpython2.7.so.1.0 (0x00007fed28a2c000) $ [acme@jouet perf]$ tools/perf/python/twatch.py cpu: 0, pid: 2817, tid: 2817 { type: fork, pid: 2817, ppid: 2817, tid: 8910, ptid: 2817, time: 11126454335306} cpu: 0, pid: 2817, tid: 2817 { type: comm, pid: 2817, tid: 8910, comm: worker } $ ps ax | grep twatch.py 8909 pts/8 S+ 0:00 /usr/bin/python tools/perf/python/twatch.py $ grep python /proc/8909/smaps 5579de658000-5579de659000 r-xp 00000000 fd:00 3156044 /usr/bin/python2.7 5579de858000-5579de859000 r--p 00000000 fd:00 3156044 /usr/bin/python2.7 5579de859000-5579de85a000 rw-p 00001000 fd:00 3156044 /usr/bin/python2.7 7f0de01f7000-7f0de023e000 r-xp 00000000 00:2d 230695 /tmp/build/perf/python/perf.so 7f0de023e000-7f0de043d000 ---p 00047000 00:2d 230695 /tmp/build/perf/python/perf.so 7f0de043d000-7f0de043e000 r--p 00046000 00:2d 230695 /tmp/build/perf/python/perf.so 7f0de043e000-7f0de044b000 rw-p 00047000 00:2d 230695 /tmp/build/perf/python/perf.so 7f0de6f0f000-7f0de6f13000 r-xp 00000000 fd:00 134975 /usr/lib64/python2.7/lib-dynload/_localemodule.so 7f0de6f13000-7f0de7113000 ---p 00004000 fd:00 134975 /usr/lib64/python2.7/lib-dynload/_localemodule.so 7f0de7113000-7f0de7114000 r--p 00004000 fd:00 134975 /usr/lib64/python2.7/lib-dynload/_localemodule.so 7f0de7114000-7f0de7115000 rw-p 00005000 fd:00 134975 /usr/lib64/python2.7/lib-dynload/_localemodule.so 7f0de7e73000-7f0de8052000 r-xp 00000000 fd:00 3173292 /usr/lib64/libpython2.7.so.1.0 7f0de8052000-7f0de8251000 ---p 001df000 fd:00 3173292 /usr/lib64/libpython2.7.so.1.0 7f0de8251000-7f0de8255000 r--p 001de000 fd:00 3173292 /usr/lib64/libpython2.7.so.1.0 7f0de8255000-7f0de8291000 rw-p 001e2000 fd:00 3173292 /usr/lib64/libpython2.7.so.1.0 $

Jaroslav Škarvada committed 8 years ago

Commit 66dfdff1 parent d2ed5d26 files · +221 −88Browse files

Showing the changes to tools/perf/util/python.c (1 of 6 files). Show all

Unified · Split

tools/perf/util/python.c+77−18
@@ -12,6 +12,30 @@ · 11 unmodified lines
1212 #include "print_binary.h"
1313 #include "thread_map.h"
1414
15+#if PY_MAJOR_VERSION < 3
16+#define _PyUnicode_FromString(arg) \
17+ PyString_FromString(arg)
18+#define _PyUnicode_AsString(arg) \
19+ PyString_AsString(arg)
20+#define _PyUnicode_FromFormat(...) \
21+ PyString_FromFormat(__VA_ARGS__)
22+#define _PyLong_FromLong(arg) \
23+ PyInt_FromLong(arg)
24+
25+#else
26+
27+#define _PyUnicode_FromString(arg) \
28+ PyUnicode_FromString(arg)
29+#define _PyUnicode_FromFormat(...) \
30+ PyUnicode_FromFormat(__VA_ARGS__)
31+#define _PyLong_FromLong(arg) \
32+ PyLong_FromLong(arg)
33+#endif
34+
35+#ifndef Py_TYPE
36+#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
37+#endif
38+
1539 /*
1640 * Provide these two so that we don't have to link against callchain.c and
1741 * start dragging hist.c, etc.
@@ -49,7 +73,11 @@ int eprintf(int level, int var, const char *fmt, ...) · 31 unmodified lines
4973 # define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
5074 #endif
5175
76+#if PY_MAJOR_VERSION < 3
5277 PyMODINIT_FUNC initperf(void);
78+#else
79+PyMODINIT_FUNC PyInit_perf(void);
80+#endif
5381
5482 #define member_def(type, member, ptype, help) \
5583 { #member, ptype, \
@@ -107,7 +135,7 @@ static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent) · 51 unmodified lines
107135 pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) {
108136 ret = PyErr_NoMemory();
109137 } else {
110− ret = PyString_FromString(s);
138+ ret = _PyUnicode_FromString(s);
111139 free(s);
112140 }
113141 return ret;
@@ -138,7 +166,7 @@ static PyMemberDef pyrf_task_event__members[] = { · 24 unmodified lines
138166
139167 static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent)
140168 {
141− return PyString_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
169+ return _PyUnicode_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, "
142170 "ptid: %u, time: %" PRIu64 "}",
143171 pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit",
144172 pevent->event.fork.pid,
@@ -171,7 +199,7 @@ static PyMemberDef pyrf_comm_event__members[] = { · 26 unmodified lines
171199
172200 static PyObject *pyrf_comm_event__repr(struct pyrf_event *pevent)
173201 {
174− return PyString_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
202+ return _PyUnicode_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }",
175203 pevent->event.comm.pid,
176204 pevent->event.comm.tid,
177205 pevent->event.comm.comm);
@@ -202,7 +230,7 @@ static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent) · 24 unmodified lines
202230 {
203231 struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1);
204232
205− return PyString_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64
233+ return _PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64
206234 ", stream_id: %" PRIu64 " }",
207235 pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un",
208236 te->time, te->id, te->stream_id);
@@ -237,7 +265,7 @@ static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) · 28 unmodified lines
237265 pevent->event.lost.id, pevent->event.lost.lost) < 0) {
238266 ret = PyErr_NoMemory();
239267 } else {
240− ret = PyString_FromString(s);
268+ ret = _PyUnicode_FromString(s);
241269 free(s);
242270 }
243271 return ret;
@@ -264,7 +292,7 @@ static PyMemberDef pyrf_read_event__members[] = { · 20 unmodified lines
264292
265293 static PyObject *pyrf_read_event__repr(struct pyrf_event *pevent)
266294 {
267− return PyString_FromFormat("{ type: read, pid: %u, tid: %u }",
295+ return _PyUnicode_FromFormat("{ type: read, pid: %u, tid: %u }",
268296 pevent->event.read.pid,
269297 pevent->event.read.tid);
270298 /*
@@ -299,7 +327,7 @@ static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) · 28 unmodified lines
299327 if (asprintf(&s, "{ type: sample }") < 0) {
300328 ret = PyErr_NoMemory();
301329 } else {
302− ret = PyString_FromString(s);
330+ ret = _PyUnicode_FromString(s);
303331 free(s);
304332 }
305333 return ret;
@@ -330,7 +358,7 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) · 24 unmodified lines
330358 }
331359 if (field->flags & FIELD_IS_STRING &&
332360 is_printable_array(data + offset, len)) {
333− ret = PyString_FromString((char *)data + offset);
361+ ret = _PyUnicode_FromString((char *)data + offset);
334362 } else {
335363 ret = PyByteArray_FromStringAndSize((const char *) data + offset, len);
336364 field->flags &= ~FIELD_IS_STRING;
@@ -352,7 +380,7 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) · 15 unmodified lines
352380 static PyObject*
353381 get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name)
354382 {
355− const char *str = PyString_AsString(PyObject_Str(attr_name));
383+ const char *str = _PyUnicode_AsString(PyObject_Str(attr_name));
356384 struct perf_evsel *evsel = pevent->evsel;
357385 struct format_field *field;
358386
@@ -416,7 +444,7 @@ static PyObject *pyrf_context_switch_event__repr(struct pyrf_event *pevent) · 57 unmodified lines
416444 !!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT)) < 0) {
417445 ret = PyErr_NoMemory();
418446 } else {
419− ret = PyString_FromString(s);
447+ ret = _PyUnicode_FromString(s);
420448 free(s);
421449 }
422450 return ret;
@@ -528,7 +556,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, · 105 unmodified lines
528556 static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
529557 {
530558 cpu_map__put(pcpus->cpus);
531− pcpus->ob_type->tp_free((PyObject*)pcpus);
559+ Py_TYPE(pcpus)->tp_free((PyObject*)pcpus);
532560 }
533561
534562 static Py_ssize_t pyrf_cpu_map__length(PyObject *obj)
@@ -597,7 +625,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, · 62 unmodified lines
597625 static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
598626 {
599627 thread_map__put(pthreads->threads);
600− pthreads->ob_type->tp_free((PyObject*)pthreads);
628+ Py_TYPE(pthreads)->tp_free((PyObject*)pthreads);
601629 }
602630
603631 static Py_ssize_t pyrf_thread_map__length(PyObject *obj)
@@ -759,7 +787,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, · 155 unmodified lines
759787 static void pyrf_evsel__delete(struct pyrf_evsel *pevsel)
760788 {
761789 perf_evsel__exit(&pevsel->evsel);
762− pevsel->ob_type->tp_free((PyObject*)pevsel);
790+ Py_TYPE(pevsel)->tp_free((PyObject*)pevsel);
763791 }
764792
765793 static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel,
@@ -850,7 +878,7 @@ static int pyrf_evlist__init(struct pyrf_evlist *pevlist, · 84 unmodified lines
850878 static void pyrf_evlist__delete(struct pyrf_evlist *pevlist)
851879 {
852880 perf_evlist__exit(&pevlist->evlist);
853− pevlist->ob_type->tp_free((PyObject*)pevlist);
881+ Py_TYPE(pevlist)->tp_free((PyObject*)pevlist);
854882 }
855883
856884 static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist,
@@ -902,12 +930,16 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, · 45 unmodified lines
902930
903931 for (i = 0; i < evlist->pollfd.nr; ++i) {
904932 PyObject *file;
933+#if PY_MAJOR_VERSION < 3
905934 FILE *fp = fdopen(evlist->pollfd.entries[i].fd, "r");
906935
907936 if (fp == NULL)
908937 goto free_list;
909938
910939 file = PyFile_FromFile(fp, "perf", "r", NULL);
940+#else
941+ file = PyFile_FromFd(evlist->pollfd.entries[i].fd, "perf", "r", -1, NULL, NULL, NULL, 1);
942+#endif
911943 if (file == NULL)
912944 goto free_list;
913945
@@ -1194,9 +1226,9 @@ static PyObject *pyrf__tracepoint(struct pyrf_evsel *pevsel, · 280 unmodified lines
11941226
11951227 tp_format = trace_event__tp_format(sys, name);
11961228 if (IS_ERR(tp_format))
1197− return PyInt_FromLong(-1);
1229+ return _PyLong_FromLong(-1);
11981230
1199− return PyInt_FromLong(tp_format->id);
1231+ return _PyLong_FromLong(tp_format->id);
12001232 }
12011233
12021234 static PyMethodDef perf__methods[] = {
@@ -1209,11 +1241,31 @@ static PyMethodDef perf__methods[] = { · 6 unmodified lines
12091241 { .ml_name = NULL, }
12101242 };
12111243
1244+#if PY_MAJOR_VERSION < 3
12121245 PyMODINIT_FUNC initperf(void)
1246+#else
1247+PyMODINIT_FUNC PyInit_perf(void)
1248+#endif
12131249 {
12141250 PyObject *obj;
12151251 int i;
1216− PyObject *dict, *module = Py_InitModule("perf", perf__methods);
1252+ PyObject *dict;
1253+#if PY_MAJOR_VERSION < 3
1254+ PyObject *module = Py_InitModule("perf", perf__methods);
1255+#else
1256+ static struct PyModuleDef moduledef = {
1257+ PyModuleDef_HEAD_INIT,
1258+ "perf", /* m_name */
1259+ "", /* m_doc */
1260+ -1, /* m_size */
1261+ perf__methods, /* m_methods */
1262+ NULL, /* m_reload */
1263+ NULL, /* m_traverse */
1264+ NULL, /* m_clear */
1265+ NULL, /* m_free */
1266+ };
1267+ PyObject *module = PyModule_Create(&moduledef);
1268+#endif
12171269
12181270 if (module == NULL ||
12191271 pyrf_event__setup_types() < 0 ||
@@ -1221,7 +1273,11 @@ PyMODINIT_FUNC initperf(void) · 1 unmodified line
12211273 pyrf_evsel__setup_types() < 0 ||
12221274 pyrf_thread_map__setup_types() < 0 ||
12231275 pyrf_cpu_map__setup_types() < 0)
1276+#if PY_MAJOR_VERSION < 3
12241277 return;
1278+#else
1279+ return module;
1280+#endif
12251281
12261282 /* The page_size is placed in util object. */
12271283 page_size = sysconf(_SC_PAGE_SIZE);
@@ -1270,7 +1326,7 @@ PyMODINIT_FUNC initperf(void) · 42 unmodified lines
12701326 goto error;
12711327
12721328 for (i = 0; perf__constants[i].name != NULL; i++) {
1273− obj = PyInt_FromLong(perf__constants[i].value);
1329+ obj = _PyLong_FromLong(perf__constants[i].value);
12741330 if (obj == NULL)
12751331 goto error;
12761332 PyDict_SetItemString(dict, perf__constants[i].name, obj);
@@ -1280,6 +1336,9 @@ PyMODINIT_FUNC initperf(void) · 3 unmodified lines
12801336 error:
12811337 if (PyErr_Occurred())
12821338 PyErr_SetString(PyExc_ImportError, "perf: Init failed!");
1339+#if PY_MAJOR_VERSION >= 3
1340+ return module;
1341+#endif
12831342 }
12841343
12851344 /*