#12808: Optimize ClassCallMetaClass using Cython
--------------------------------------------------+-------------------------
Reporter: hivert | Owner: jason
Type: enhancement | Status: needs_review
Priority: major | Milestone: sage-5.0
Component: misc | Resolution:
Keywords: classcall UniqueRepresentation | Work issues:
Report Upstream: N/A | Reviewers:
Authors: Florent Hivert, Simon King | Merged in:
Dependencies: | Stopgaps:
--------------------------------------------------+-------------------------
Changes (by {'newvalue': u'Florent Hivert, Simon King', 'oldvalue': u'Florent
Hivert'}):
* author: Florent Hivert => Florent Hivert, Simon King
Old description:
> When a class {{{C}}} is an instance of {{{ClasscallMetaclass}}}, then for
> any constructor call, the system currently looks for {{{__classcall__}}}
> and {{{__classcall_private__}}} in {{{C}}}. This adds quite an overhead
> and this could be cached, assuming no one modifies {{{C}}} (which seems
> reasonable). Improving this speeds up, in particular, all call to the
> constructor of a subclass of {{{UniqueRepresentation}}}, eg. many
> parents, all categories...
>
> __Apply__
>
> [attachment:trac_12808-classcall_speedup-fh.patch]
New description:
When a class {{{C}}} is an instance of {{{ClasscallMetaclass}}}, then for
any constructor call, the system currently looks for {{{__classcall__}}}
and {{{__classcall_private__}}} in {{{C}}}. This adds quite an overhead
and this could be cached, assuming no one modifies {{{C}}} (which seems
reasonable). Improving this speeds up, in particular, all call to the
constructor of a subclass of {{{UniqueRepresentation}}}, eg. many parents,
all categories...
__Apply__
* [attachment:trac_12808-classcall_speedup-fh.patch]
* [attachment:trac_12808_nested_class_cython.patch]
and we have to decide whether the third patch helps to make the code
clearer:
* [attachment:trac_12808-classcall_cdef.patch]
--
Comment:
I have attached my two patches. Your patch and my patch actually turn out
to be independent.
Purpose of my first patch: Make `NestedClassMetaclass` an extension type
of type, and avoid some calling overhead during its creation.
Purpose of my second patch: Make `ClasscallMetclass` an extension type as
well, directly derived from `NestedClassMetaclass`.
'''__Timings__'''
With '''sage-5.1.notebook unpatched''', I get for Florent's examples
{{{
sage: class Rien(object):
....: pass
....:
sage: from sage.misc.classcall_metaclass import ClasscallMetaclass
sage: class NOCALL(object):
....: __metaclass__ = ClasscallMetaclass
....: pass
....:
sage: %timeit [Rien() for i in range(10000)]
125 loops, best of 3: 1.74 ms per loop
sage: %timeit [NOCALL() for i in range(10000)]
25 loops, best of 3: 16.7 ms per loop
sage: class CALL(object):
....: __metaclass__ = ClasscallMetaclass
....: @staticmethod
....: def __classcall_private__(cls, arg):
....: arg = arg + arg
....: return arg
....:
sage: %timeit [CALL(i) for i in range(10000)]
25 loops, best of 3: 9.05 ms per loop
}}}
Here is something with `__classcall__` instead of `__classcall_private__`,
and in a way that has less overhead than `arg+arg`:
{{{
sage: class NewCall(object):
....: __metaclass__ = ClasscallMetaclass
....: @staticmethod
....: def __classcall__(cls, C):
....: return C
....:
sage: C = ZZ.__class__
sage: timeit("a = NewCall(C)", number=10000)
10000 loops, best of 3: 878 ns per loop
}}}
And finally a "nested class" example:
{{{
sage: from sage.misc.nested_class import NestedClassMetaclass
sage: def test_nest():
....: class A:
....: __metaclass__ = NestedClassMetaclass
....: class B:
....: pass
....:
sage: %timeit test_nest()
625 loops, best of 3: 33.1 µs per loop
}}}
Now, the same examples with my first patch:
{{{
sage: %timeit [Rien() for i in range(10000)]
125 loops, best of 3: 1.76 ms per loop
sage: %timeit [NOCALL() for i in range(10000)]
25 loops, best of 3: 18.3 ms per loop
sage: %timeit [CALL(i) for i in range(10000)]
25 loops, best of 3: 10.7 ms per loop
sage: %timeit test_nest()
625 loops, best of 3: 23.6 µs per loop
}}}
Now, with your patch only:
{{{
sage: %timeit [Rien() for i in range(10000)]
125 loops, best of 3: 1.77 ms per loop
sage: %timeit [NOCALL() for i in range(10000)]
125 loops, best of 3: 2.05 ms per loop
sage: %timeit [CALL(i) for i in range(10000)]
125 loops, best of 3: 4.34 ms per loop
sage: timeit("a = NewCall(C)", number=10000)
10000 loops, best of 3: 889 ns per loop
sage: %timeit test_nest()
625 loops, best of 3: 32.8 µs per loop
}}}
Thus, our patches treat orthogonal aspects. Now, the first two patches
together:
{{{
sage: %timeit [Rien() for i in range(10000)]
125 loops, best of 3: 1.78 ms per loop
sage: %timeit [NOCALL() for i in range(10000)]
125 loops, best of 3: 2 ms per loop
sage: %timeit [CALL(i) for i in range(10000)]
125 loops, best of 3: 4.34 ms per loop
sage: timeit("a = NewCall(C)", number=10000)
10000 loops, best of 3: 895 ns per loop
sage: %timeit test_nest()
625 loops, best of 3: 23.6 µs per loop
}}}
And with all three patches:
{{{
sage: %timeit [Rien() for i in range(10000)]
125 loops, best of 3: 1.75 ms per loop
sage: %timeit [NOCALL() for i in range(10000)]
125 loops, best of 3: 2.08 ms per loop
sage: %timeit [CALL(i) for i in range(10000)]
125 loops, best of 3: 4.44 ms per loop
sage: timeit("a = NewCall(C)", number=10000)
10000 loops, best of 3: 897 ns per loop
sage: %timeit test_nest()
625 loops, best of 3: 23.6 µs per loop
}}}
__CONCLUSION__
My first patch does improve the time spent for the creation of a nested
class. Your patch improves a lot of things for classcall metaclass. My
second patch makes (I think) the inheritance a bit clearer, but it does
not provide a speed-up. The reason is explained in my previous post.
Apply trac_12808-classcall_speedup-fh.patch
trac_12808_nested_class_cython.patch trac_12808-classcall_cdef.patch
--
Ticket URL: <http://trac.sagemath.org/sage_trac/ticket/12808#comment:41>
Sage <http://www.sagemath.org>
Sage: Creating a Viable Open Source Alternative to Magma, Maple, Mathematica,
and MATLAB
--
You received this message because you are subscribed to the Google Groups
"sage-trac" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sage-trac?hl=en.