[Cython] Code generated for the expression int(x)+1
Hi all, I am having a simple performance problem that can be resolved by splitting up an expression in two lines. I don't know if it is a bug or I am missing something. The piece of code below is translated to slow code 1) cdef int i i=int(x)+1 whereas the code below is translated to fast code 2) cdef int i i=int(x) i=i+1 Snippet of generated code by cython 1) /* "test.pyx":4 * cdef double x=3.2 * cdef int i * i=int(x)+1 # << * return i * */ __pyx_t_1 = PyFloat_FromDouble(__pyx_v_x); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_t_2 = PyTuple_New(1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_1 = PyObject_Call(((PyObject *)((PyObject*)(&PyInt_Type))), ((PyObject *)__pyx_t_2), NULL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; __pyx_t_2 = PyNumber_Add(__pyx_t_1, __pyx_int_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_3 = __Pyx_PyInt_AsInt(__pyx_t_2); if (unlikely((__pyx_t_3 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 4; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_v_i = __pyx_t_3; 2) /* "test.pyx":11 * cdef double x=3.2 * cdef int i * i=int(x) # << * i=i+1 * return i */ __pyx_v_i = ((int)__pyx_v_x); /* "test.pyx":12 * cdef int i * i=int(x) * i=i+1 # << * return i * */ __pyx_v_i = (__pyx_v_i + 1); I am using Cython-0.15.1 Best regards, Ask ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Code generated for the expression int(x)+1
Ask F. Jakobsen, 01.05.2012 09:53: > I am having a simple performance problem that can be resolved by splitting up > an expression in two lines. I don't know if it is a bug or I am missing > something. > > The piece of code below is translated to slow code > > 1) > cdef int i > i=int(x)+1 What you are saying here is: Convert x (known to be a C double) to an arbitrary size Python integer value, add 1, convert it to a C int and assign it to i. > whereas the code below is translated to fast code > > 2) > cdef int i > i=int(x) > i=i+1 This means: Convert x (known to be a C double) to an arbitrary size Python integer value, convert that to a C int and assign it to i, then add 1 and assign the result to i. In the first case, Cython cannot safely assume that the result of the int() conversion will fit into a C int and will therefore evaluate the expression in Python space. Note that the "+1" only hits a specific case where it looks safe, if you had written "int(x) // 200", this decision would make a lot more sense, because the intermediate result of int(x) could really be larger than a C int, even though the result of the division will have to fit into one (or will be made to fit, because you say so). In the second case, you explicitly tell Cython that the result of the int() conversion will fit into a C int and that *you* accept the responsibility for any overflows, so Cython can safely optimise the Python coercion away and reduce the int() call to a bare C cast from double to int. You can get the same result by writing down the cast yourself. Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Wacky idea: proper macros
On 04/30/2012 11:36 PM, William Stein wrote: On Mon, Apr 30, 2012 at 2:32 PM, Dag Sverre Seljebotn wrote: Wes McKinney wrote: On Mon, Apr 30, 2012 at 4:55 PM, Nathaniel Smith wrote: On Mon, Apr 30, 2012 at 9:49 PM, Dag Sverre Seljebotn wrote: JIT is really the way to go. It is one thing that a JIT could optimize the case where you pass a callback to a function and inline it run-time. But even if it doesn't get that fancy, it'd be great to just be able to write something like "cython.eval(s)" and have that be compiled (I guess you could do that now, but the sheer overhead of the C compiler and all the .so files involved means nobody would sanely use that as the main way of stringing together something like pandas). The overhead of running a fully optimizing compiler over pandas on every import is pretty high, though. You can come up with various caching mechanisms, but they all mean introducing some kind of compile time/run time distinction. So I'm skeptical we'll just be able to get rid of that concept, even in a brave new LLVM/PyPy/Julia world. -- Nathaniel ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel I'd be perfectly OK with just having to compile pandas's "data engine" and generate loads of C/C++ code. JIT-compiling little array expressions would be cool too. I've got enough of an itch that I might have to start scratching pretty soon. I think a good start is: Myself I'd look into just using Jinja2 to generate all the Cython code, rather than those horrible Python interpolated strings...that should give you something that's at least rather pleasant for you to work with once you are used to it (even if it is a bit horrible to newcomers to the code base). You can even check in the generated sources. And we've discussed letting cython be smart with templating languages and error report on a line in the original template, such features will certainly accepted once somebody codes it up. (I can give you me breakdown of how I eliminate other templating languages than Jinja2 for this purpose tomorrow if you are interested). Can you point us to a good example of you using jinja2 for this purpose? Sure, I just needed some sleep... I only use it for C code, haven't used it for Cython so far (I tend to write things in C and wrap it in Cython). 1) https://github.com/dagss/elemental4py/blob/master/src/elemental_wrapper.cpp.in (work-in-progress) Here I use Jinja2 to write a C wrapper around Elemental (Elemental is a library for dense linear algebra over MPI). The C++ library is a heavy user of templates, I replace the templates with run-time dispatches using if-tests, so that rather than "DistMatrix" you have an elem_matrix struct with ELEM_DOUBLE, ELEM_MC, ELEM_MR. 2) https://github.com/wavemoth/wavemoth/blob/master/src/legendre_transform.c.in This is a numerical kernel where I do loop unrolling etc. using metaprogramming (with Tempita, not Jinja2). https://github.com/wavemoth/wavemoth/blob/cuda/wavemoth/cuda/legendre_transform.cu.in 3) https://github.com/wavemoth/wavemoth/blob/cuda/wavemoth/cuda/legendre_transform.cu.in Numerical kernel in templated CUDA using Tempita. On templating languages I tried) I've scanned through a few and actually tried Tempita, Mako, Jinja2. The features I need: - Pythonic syntax and ability to embed arbitrary Python code - A "call-block", such as this {% call catch('A->grid->ctx') %} BODY {% endcall %} i.e. in Jinja 2, one of the arguments to the function "catch" here is "caller", which when called invokes the body (and can be called multiple times with different arguments) I started out with Tempita because it's so simple to ship, but the lack of a call-block construct + the inability to break lines where I wanted drove me crazy. Then I tried Mako, because it has the largest set of features, but the syntax was simply too gruesome. I first tried to ignore this, but simply couldn't, it made my code totally unreadable. Finally, Jinja2 has most of what I need. Slight disadvantage is it tries to be "pure" and not allow too much arbitrary Python, Ideally what I'd like is something like Tempita but developed further to allow line-breaks and call-blocks, but lacking that I use Jinja2. I don't remember why I didn't like Cheetah (perhaps it doesn't do call-blocks?) Dag ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Wacky idea: proper macros
On 05/01/2012 10:29 AM, Dag Sverre Seljebotn wrote: On 04/30/2012 11:36 PM, William Stein wrote: On Mon, Apr 30, 2012 at 2:32 PM, Dag Sverre Seljebotn wrote: Wes McKinney wrote: On Mon, Apr 30, 2012 at 4:55 PM, Nathaniel Smith wrote: On Mon, Apr 30, 2012 at 9:49 PM, Dag Sverre Seljebotn wrote: JIT is really the way to go. It is one thing that a JIT could optimize the case where you pass a callback to a function and inline it run-time. But even if it doesn't get that fancy, it'd be great to just be able to write something like "cython.eval(s)" and have that be compiled (I guess you could do that now, but the sheer overhead of the C compiler and all the .so files involved means nobody would sanely use that as the main way of stringing together something like pandas). The overhead of running a fully optimizing compiler over pandas on every import is pretty high, though. You can come up with various caching mechanisms, but they all mean introducing some kind of compile time/run time distinction. So I'm skeptical we'll just be able to get rid of that concept, even in a brave new LLVM/PyPy/Julia world. -- Nathaniel ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel I'd be perfectly OK with just having to compile pandas's "data engine" and generate loads of C/C++ code. JIT-compiling little array expressions would be cool too. I've got enough of an itch that I might have to start scratching pretty soon. I think a good start is: Myself I'd look into just using Jinja2 to generate all the Cython code, rather than those horrible Python interpolated strings...that should give you something that's at least rather pleasant for you to work with once you are used to it (even if it is a bit horrible to newcomers to the code base). You can even check in the generated sources. And we've discussed letting cython be smart with templating languages and error report on a line in the original template, such features will certainly accepted once somebody codes it up. (I can give you me breakdown of how I eliminate other templating languages than Jinja2 for this purpose tomorrow if you are interested). Can you point us to a good example of you using jinja2 for this purpose? Sure, I just needed some sleep... I only use it for C code, haven't used it for Cython so far (I tend to write things in C and wrap it in Cython). 1) https://github.com/dagss/elemental4py/blob/master/src/elemental_wrapper.cpp.in (work-in-progress) Here I use Jinja2 to write a C wrapper around Elemental (Elemental is a library for dense linear algebra over MPI). The C++ library is a heavy user of templates, I replace the templates with run-time dispatches using if-tests, so that rather than "DistMatrix" you have an elem_matrix struct with ELEM_DOUBLE, ELEM_MC, ELEM_MR. 2) https://github.com/wavemoth/wavemoth/blob/master/src/legendre_transform.c.in This is a numerical kernel where I do loop unrolling etc. using metaprogramming (with Tempita, not Jinja2). https://github.com/wavemoth/wavemoth/blob/cuda/wavemoth/cuda/legendre_transform.cu.in 3) https://github.com/wavemoth/wavemoth/blob/cuda/wavemoth/cuda/legendre_transform.cu.in Numerical kernel in templated CUDA using Tempita. On templating languages I tried) I've scanned through a few and actually tried Tempita, Mako, Jinja2. The features I need: - Pythonic syntax and ability to embed arbitrary Python code - A "call-block", such as this {% call catch('A->grid->ctx') %} BODY {% endcall %} i.e. in Jinja 2, one of the arguments to the function "catch" here is "caller", which when called invokes the body (and can be called multiple times with different arguments) I started out with Tempita because it's so simple to ship, but the lack of a call-block construct + the inability to break lines where I wanted drove me crazy. Then I tried Mako, because it has the largest set of features, but the syntax was simply too gruesome. I first tried to ignore this, but simply couldn't, it made my code totally unreadable. Finally, Jinja2 has most of what I need. Slight disadvantage is it tries to be "pure" and not allow too much arbitrary Python, [sorry:] Slight disadvantage is it tries to be "pure" and not allow too much arbitrary Python, but one can work around that by using an auxiliary Python module and pass that Python module to the template when instantiating it -- so one kind of can use arbitrary Python in the templating process, one just need to edit separate files. (Which is perhaps better -- I'm unable to make up my mind on such trivial issues.) Dag Ideally what I'd like is something like Tempita but developed further to allow line-breaks and call-blocks, but lacking that I use Jinja2. I don't remember why I didn't like Cheetah (perhaps it doesn't do call-blocks?) Dag ___ cython-devel mailing list cytho
Re: [Cython] [cython-users] Conditional import in pure Python mode
>>> On 29 April 2012 01:33, Ian Bell wrote: idiom like if cython.compiled: cython.import('from libc.math cimport sin') else: from math import sin Actually, in this particular case, I would even accept a solution that special cases the "math" module internally by automatically cimporting libc.math as an override (or rather an adapted version as plain "math.pxd"). This CEP describes a general approach: http://wiki.cython.org/enhancements/overlaypythonmodules It's partly outdated, so things may have become easier these days. Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] [cython-users] Conditional import in pure Python mode
Ian Bell, 01.05.2012 15:50: > On Tue, May 1, 2012 at 9:21 PM, Stefan Behnel wrote: > On 29 April 2012 01:33, Ian Bell wrote: >> idiom like >> >> if cython.compiled: >> cython.import('from libc.math cimport sin') >> else: >> from math import sin >> >> Actually, in this particular case, I would even accept a solution that >> special cases the "math" module internally by automatically cimporting >> libc.math as an override (or rather an adapted version as plain >> "math.pxd"). >> >> This CEP describes a general approach: >> >> http://wiki.cython.org/enhancements/overlaypythonmodules >> >> It's partly outdated, so things may have become easier these days. > > That is exactly what I was looking for. If we could implement that, it > would solve all my problems. It would meet all my needs - on this front at > least. There are two things to do here: 1) Write up a math.pxd that contains declarations equivalent to Python's math module. Note that this may not be entirely trivial because the math module does some error handling and type special casing under the hood. Some of this may still be required for the C level equivalents, although the type special casing would better be done by overriding function signatures using this feature: http://docs.cython.org/src/userguide/external_C_code.html#resolving-naming-conflicts-c-name-specifications Basically, you would declare two (or more) function signatures under the same name, but with different C names. 2) Use math.pxd as an override for the math module. I'm not sure yet how that would best be made to work, but it shouldn't be all that complex. It already works (mostly?) for numpy.pxd, for example, although that's done explicitly in user code. I think we should start with 2) to see how to get this to work in general, before we put too much work into 1). Could you sign up for the cython-devel mailing list please, so that we can coordinate the work there? Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
Stefan Behnel, 01.05.2012 21:14: > 2) Use math.pxd as an override for the math module. I'm not sure yet how > that would best be made to work, but it shouldn't be all that complex. It > already works (mostly?) for numpy.pxd, for example, although that's done > explicitly in user code. BTW, I think it would be helpful to make the numpy.pxd cimport automatic as well whenever someone does "import numpy" and friends, right? Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
On 1 May 2012 20:22, Stefan Behnel wrote: > Stefan Behnel, 01.05.2012 21:14: >> 2) Use math.pxd as an override for the math module. I'm not sure yet how >> that would best be made to work, but it shouldn't be all that complex. It >> already works (mostly?) for numpy.pxd, for example, although that's done >> explicitly in user code. > > BTW, I think it would be helpful to make the numpy.pxd cimport automatic as > well whenever someone does "import numpy" and friends, right? > > Stefan > ___ > cython-devel mailing list > cython-devel@python.org > http://mail.python.org/mailman/listinfo/cython-devel I'm not sure, it means the user has to have numpy development headers. ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
On 5/1/12 2:39 PM, mark florisson wrote: On 1 May 2012 20:22, Stefan Behnel wrote: Stefan Behnel, 01.05.2012 21:14: 2) Use math.pxd as an override for the math module. I'm not sure yet how that would best be made to work, but it shouldn't be all that complex. It already works (mostly?) for numpy.pxd, for example, although that's done explicitly in user code. BTW, I think it would be helpful to make the numpy.pxd cimport automatic as well whenever someone does "import numpy" and friends, right? Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel I'm not sure, it means the user has to have numpy development headers. But if the user is going to compile a NumPy application, it sounds like strange to me that she should not be required to install the NumPy development headers, right? -- Francesc Alted ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
mark florisson, 01.05.2012 21:39: > On 1 May 2012 20:22, Stefan Behnel wrote: >> Stefan Behnel, 01.05.2012 21:14: >>> 2) Use math.pxd as an override for the math module. I'm not sure yet how >>> that would best be made to work, but it shouldn't be all that complex. It >>> already works (mostly?) for numpy.pxd, for example, although that's done >>> explicitly in user code. >> >> BTW, I think it would be helpful to make the numpy.pxd cimport automatic as >> well whenever someone does "import numpy" and friends, right? > > I'm not sure, it means the user has to have numpy development headers. Hmm, right. What about making it an explicit compile time option then? Something like # cython: override_modules = math,numpy Or should we go for an opt-out? # cython: python_modules = math,numpy Sounds like it would hit the more common case by default. Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
Francesc Alted, 01.05.2012 21:49: > On 5/1/12 2:39 PM, mark florisson wrote: >> On 1 May 2012 20:22, Stefan Behnel wrote: >>> Stefan Behnel, 01.05.2012 21:14: 2) Use math.pxd as an override for the math module. I'm not sure yet how that would best be made to work, but it shouldn't be all that complex. It already works (mostly?) for numpy.pxd, for example, although that's done explicitly in user code. >>> BTW, I think it would be helpful to make the numpy.pxd cimport automatic as >>> well whenever someone does "import numpy" and friends, right? >>> >> I'm not sure, it means the user has to have numpy development headers. > > But if the user is going to compile a NumPy application, it sounds like > strange to me that she should not be required to install the NumPy > development headers, right? Let's say it's not impossible that someone uses NumPy and Cython without any accelerated C level connection between the two, but it's rather unlikely, given that Cython already has all dependencies that this connection would require as well, except for the NumPy header files. So I would suggest to make the automatic override the default for any module for which a .pxd file with the same fully qualified name is found in the search path, and to require users to explicitly disable this feature for a given module using a module level (or external) compiler directive if they feel like getting slower code (or working around a bug or whatever). Anyway, given that this feature isn't even implemented yet, it may appear a bit premature to discuss these details. Stefan ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel
Re: [Cython] Conditional import in pure Python mode
On Tue, May 1, 2012 at 1:02 PM, Stefan Behnel wrote: > Francesc Alted, 01.05.2012 21:49: >> On 5/1/12 2:39 PM, mark florisson wrote: >>> On 1 May 2012 20:22, Stefan Behnel wrote: Stefan Behnel, 01.05.2012 21:14: > 2) Use math.pxd as an override for the math module. I'm not sure yet how > that would best be made to work, but it shouldn't be all that complex. It > already works (mostly?) for numpy.pxd, for example, although that's done > explicitly in user code. math.pxd would be a bit trickier, as we're trying to shadow python functions with independent c implementations (rather than declaring structure to the single numpy array object and exposing c-level only methods. We'd need to support stuff like double x = ... double y = sin(x) # fast cdef object f = sin # grab the builtin one? but this is by no means insurmountable and could be really useful. BTW, I think it would be helpful to make the numpy.pxd cimport automatic as well whenever someone does "import numpy" and friends, right? >>> I'm not sure, it means the user has to have numpy development headers. >> >> But if the user is going to compile a NumPy application, it sounds like >> strange to me that she should not be required to install the NumPy >> development headers, right? > > Let's say it's not impossible that someone uses NumPy and Cython without > any accelerated C level connection between the two, but it's rather > unlikely, given that Cython already has all dependencies that this > connection would require as well, except for the NumPy header files. > > So I would suggest to make the automatic override the default for any > module for which a .pxd file with the same fully qualified name is found in > the search path, and to require users to explicitly disable this feature > for a given module using a module level (or external) compiler directive if > they feel like getting slower code (or working around a bug or whatever). There is another consideration: this can introduce unnecessary and potentially costly dependencies. For example, in Sage one has sage/rings/integer.pxd. Not everything that imports from this file needs c-level access to the Integer type, and requiring everything that imports from sage.rings.integer to be re-compiled when this file changes would increase the (admittedly already lengthy) re-compile, as well as sucking in a (chain of) un-needed declarations. As Cython becomes more and more common, a similar effect could happen between projects as well. This may be the exception rather than the rule, so perhaps it's not *that* bad to let opt-in be the default, i.e. # cython: cimport_on_import = __all__ - Robert ___ cython-devel mailing list cython-devel@python.org http://mail.python.org/mailman/listinfo/cython-devel