On Oct 29, 2008, at 11:08 PM, Case Vanhorsen wrote: > I help maintain the gmpy library and I've been experimenting with a > Cython-based wrapper for GMP. I've done simple performance tests with > an early version of the library and it is slower than the C-based gmpy > library. I compared object creation and addition times for Python > longs, gmpy, and gmpy3 (the experimental library). These are my > results, in seconds (code is below): > > create times > long: 2.25385284424 > gmpy: 1.70728683472 > gmpy3: 2.3947558403 > > addition times > long: 3.03700900078 > gmpy: 2.6448340416 > gmpy3: 4.70184206963
Interesting. > Do you have any suggestions for improving the performance? It looks like gmpy.c doesn't do any type checking for add, which could be a cause for concern (but also make things faster). Is this with cython-devel or the release version? The isinstance function will be much faster in the next release of Cython, as is the argument parsing, so that should help too. Probably the most significant thing you could do is construct the mpz class directly rather than call mpz () (e.g. see the PY_NEW macro at http://www.sagemath.org/hg/sage-main/ file/3859ace86968/c_lib/include/stdsage.h for one way to do that). Also, type your "base" parameter to be an int in the __init__ method. > > Thanks, > > Case > > -------------------------------------------- > > The test script: > > import time > import gmpy > import gmpy3 > > def create_test(ctor, times): > start = time.time() > for i in range(times): > a=ctor(i) > return (time.time() - start) > > def addition_test(ctor, times): > b = ctor('12345678901234567890') > start = time.time() > for i in range(times): > a=ctor(i) + b > return (time.time() - start) > > print "create times" > print "long: ", create_test(long, 10000000) > print "gmpy: ", create_test(gmpy.mpz, 10000000) > print "gmpy3: ", create_test(gmpy3.mpz, 10000000) > print > print "addition times" > print "long: ", addition_test(long, 10000000) > print "gmpy: ", addition_test(gmpy.mpz, 10000000) > print "gmpy3: ", addition_test(gmpy3.mpz, 10000000) > > ----------------------------------------------------------------- > > Excerpts from gmpy3.pyx > > cdef class mpz: > """ > Wrapper for GMP multiple-precision integers. > """ > > cdef mpz_t z > > def __init__(self, val=None, base=10): > """ > Initialize a variable of type mpz. > """ > cdef _longobject *l > > if val is None: > mpz_init(self.z) > elif PyInt_CheckExact(val): > mpz_init_set_si(self.z, val) > elif PyString_CheckExact(val): > if mpz_init_set_str(self.z, val, base): > raise ValueError('Invalid literal for mpz() with base > ' + str(base)) > elif PyLong_CheckExact(val): > mpz_init(self.z) > l = <_longobject *> val > if l.ob_size < 0: > negval = True > length = - l.ob_size > else: > negval = False > length = l.ob_size > mpz_import(self.z, length, -1, sizeof(l.ob_digit[0]), 0, > sizeof(l.ob_digit[0])*8 - SHIFT, l.ob_digit) > if negval: > mpz_neg(self.z, self.z) > elif PyFloat_CheckExact(val): > mpz_init_set_d(self.z, val) > elif isinstance(val, mpz): > mpz_init_set(self.z, (<mpz>val).z) > else: > raise TypeError('mpz() argument must be string, int, long, > or float') > > def __dealloc__(self): > mpz_clear(self.z) > > def __add__(self, other): > cdef int temp > result = mpz() > cdef mpz Z > > if isinstance(self, mpz): > if isinstance(other, mpz): > mpz_add((<mpz>result).z, (<mpz>self).z, > (<mpz>other).z) > elif PyInt_CheckExact(other): > if other >= 0: > mpz_add_ui((<mpz>result).z, (<mpz>self).z, other) > else: > mpz_sub_ui((<mpz>result).z, (<mpz>self).z, abs > (other)) > else: > mpz_add((<mpz>result).z, (<mpz>self).z, (<mpz>mpz > (other)).z) > return result > else: > return mpz.__add__(other, self) > _______________________________________________ > Cython-dev mailing list > [email protected] > http://codespeak.net/mailman/listinfo/cython-dev _______________________________________________ Cython-dev mailing list [email protected] http://codespeak.net/mailman/listinfo/cython-dev
