On 03/25/2010 08:49 PM, William Stein wrote:
Hi,

I was trying to understand why certain modular symbols code was too
slow, and ran across a method that looked like this (in
modular/modsym/element.py):

     def modular_symbol_rep(self):
         try:
             return self.__modular_symbols
         except AttributeError:
             A = self.parent()
             v = self.manin_symbol_rep()
             if v == 0:
                 return v
             w = [c * x.modular_symbol_rep() for c, x in v]
             return sum(w)
         return self.__modular_symbols

Of course, on multiple calls, the above is slow, because the
__modular_symbols cache never gets set.
So I though, ah ha!, this is a great example where I should use
@cached_method, now that we have it.
So I tried that, but doing

  timeit('...')

showed that it still took about 20microsend/call to call the above function.
Replacing @cached_method with the try/except as above, but actually
settin gself.__modular_symbols correctly resulted in the speedup I
wanted (e.g., each call takes a few hundred nanoseconds).

MORAL: If you care about speed, don't use the cached_method decorator
yet.   It entails massive overheard.

It's seems easy and eloquent to just write "@cached_method" to speed
up and cache your methods.  But watch out -- there is a potentially
serious price to pay for doing so, which may or may not matter
depending on your application.   I'm writing this, because I really
wish somebody had warned me about this before.


Interesting. In looking at the source for cached_function, we have three direct python function calls and at least one more indirect python function call in the critical path. Two python calls are completely unnecessary (the has_key call and the get_cache call).

        cache = self.get_cache()  # <-- PYTHON CALL!
k = self.get_key(*args, **kwds) # <-- PYTHON CALL! (involves another python call inside this too) if cache.has_key(k): # PYTHON CALL! should be "k in cache", which is over twice as fast
            return cache[k]
        w = self.f(*args, **kwds)
        cache[k] = w
        return w


My guess is that it would be very easy to speed up the @cached_method and @cached_function decorators.

Thanks,

Jason

--
To post to this group, send an email to sage-devel@googlegroups.com
To unsubscribe from this group, send an email to 
sage-devel+unsubscr...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

To unsubscribe from this group, send email to sage-devel+unsubscribegooglegroups.com or 
reply to this email with the words "REMOVE ME" as the subject.

Reply via email to