[Pyrex] slow constructor call

Joachim Saul saul at gfz-potsdam.de
Mon Dec 15 16:59:49 CET 2003


Hi there,

I am currently migrating a set of Python extension types for
seismological analysis to Pyrex, which I had written by hand using
the Python/C API. I really like the clean Pyrex code resulting
from the migration, which is much easier to maintain.

One of the classes (actually the first which I have migrated, in
order to compare performance) is a "Time" class to allow simple
time arithmetics. Unfortunately, calling the constructor of the
Pyrex version (which calls the same C functions as the
corresponding C version) is slower by about a factor of 4.
Interestingly, operations which don't require calling the
constructor, such as in-place subtractions, are practically
exactly as fast in the Pyrex as in the C version.

Comparing the codes brought out that the principal difference
appears to be that in Pyrex-generated code "PyObject_CallObject"
is called to create a new instance, whereas in my older codes use
"PyObject_NEW", which appears to be faster. I am not so familiar
with the internals, but PyObject_CallObject appears to produce the
overhead.

Is there a faster way to construct a class instance? In this
particular case the difference is really not a big deal in
practice, but *if* there is currently a faster way, I'd certainly
like to take advantage of it.

Cheers,
Joachim

BTW: The definition of my "Time" class is as follows (trimmed to the
most essential for clarity; all that has a "SeisTime" prefix is C):

cdef class Time:

    cdef SeisTime *t

    def __init__(self, obj=None):
        if obj:
            self.t = SeisTime_newFromString(obj)
        else:
            self.t = SeisTime_new(0, 0.)

    def __dealloc__(self):
        SeisTime_del(self.t)

    def __copy__(self):
        cdef Time new
        new = Time() # SLOW
	# copy data parts only:
        SeisTime_copy(new.t, self.t)
        return new

    def __sub__(Time left, right): # slow
        cdef Time tmp
        cdef double dt

        tmp = Time() # this is what makes it so slow
        if isnumber(right): # isnumber is a C function
            SeisTime_copy(tmp.t, left.t)
            dt = right # needed for conversion
            SeisTime_add_float(tmp.t, -dt)
            return tmp

        return NotImplemented

    def __isub__(self, double other): # very fast
        SeisTime_add_float(self.t, -other)
        return self






More information about the Pyrex mailing list