On Tue, Mar 29, 2011 at 12:07:15PM -0700, Simon King wrote:
> Hi!
>
> Tickets #9944 and #9138 provide some nice features, but slow things
> down. It seems to me that the reason of the performance loss is that
> the patches from these tickets make the method resolution order of
> polynomial rings much longer - in some cases the length doubles (15
> versus 39 steps until <type 'object'> is reached).
>
> As much as I understand: If the mro is longer than Python needs more
> time to look up a method that is defined for a very basic class (such
> as sage.structure.category_object.CategoryObject or
> sage.structure.parent.Parent).
I may be wrong but I have the impression that there is a cache here:
Let's create a long mro
class End(object):
def toto(self):
return 1
def long_mro(n):
if n == 0:
return End
else:
class New(long_mro(n-1)):
pass
return New
obj_long = long_mro(500)()
obj_end = End()
Then after that:
sage: len(type(obj_long).mro())
502
sage: len(type(obj_end).mro())
2
sage: timeit('obj_long.toto()',number=10^6)
1000000 loops, best of 3: 187 ns per loop
sage: timeit('obj_end.toto()',number=10^6)
1000000 loops, best of 3: 188 ns per loop
So it seems that there is no difference... Well actually I just figured out
that this has something to do with Cython: if I change
class End(object):
to
class End(SageObject):
Then:
sage: timeit('obj_long.toto()',number=10^6)
1000000 loops, best of 3: 9.22 �s per loop
sage: timeit('obj_end.toto()',number=10^6)
1000000 loops, best of 3: 203 ns per loop
Now we see the difference. Maybe it's a bug... I'll as on Cython-dev.
Cheers,
Florent
--
To post to this group, send an email to sage-...@googlegroups.com
To unsubscribe from this group, send an email to sage-devel+...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org
Note: for good or bad, the Cython classes come before categories in
the mro:
sage: sage: C = CombinatorialFreeModule(ZZ, ZZ)
sage: C.__class__.mro()
[<class 'sage.combinat.free_module.CombinatorialFreeModule_with_category'>,
<class 'sage.combinat.free_module.CombinatorialFreeModule'>,
<class 'sage.structure.unique_representation.UniqueRepresentation'>,
<type 'sage.modules.module.Module'>,
<type 'sage.structure.parent.Parent'>,
<type 'sage.structure.category_object.CategoryObject'>,
<type 'sage.structure.sage_object.SageObject'>,
<class 'sage.categories.modules_with_basis.ModulesWithBasis.parent_class'>, ... <type 'object'>]
So the number of classes to walk through to find base_ring only
increases by 1 (due to the _with_category).
Cheers,
Nicolas
--
Nicolas M. Thi�ry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/
Not at this point apparently: category_object.pyx, line 479:
def base_ring(self): # This should be in a category or elsewhere, but not here
return self._base
def base(self):
return self._base
Maybe making them such would solve Simon's problem? And actually
accelerate things, since Cython could optimize (inline?) their call in
the coercion/arithmetic code.
> You want to be a little careful overriding such methods with
> Python functions living in the dictionary, because then the
> functions called by Cython code that knows the type of your
> object, and the code called by Python code will be different.
Another trick to try would be add in Modules.ParentMethods:
def __init_extra__(self):
self.basis_ring = self.base_ring
therefore adding a short path for base_ring in all parents in Modules.
This should be rather safe (I don't expect the base_ring method to
change over time).
> I think, the question is (at least on the short run), how one can work
> around.
>
> Taking your example:
> class End(SageObject):
> def toto(self):
> return 1
> sage: c_long = long_mro(500)
> sage: obj_long = c_long()
> sage: obj_end = End()
> sage: timeit("obj_end.toto()")
> 625 loops, best of 3: 963 ns per loop
> sage: timeit("obj_long.toto()")
> 625 loops, best of 3: 22.8 �s per loop
>
> So, as you confirmed, a long mro matters, at least if Cython is
> involved.
I don't have to investigate further but, according to Stefan Behnel on
cython-users it seems to be solved in cython 0.14 !
Cheers,
Florent
I expected a potential improvement not when calling base_ring from the
interpreter, but from compiled Cython code, typically in
coercion/arithmetic.