This speeds up e.g. parsing of rst pages by factor 2.

Put this at the beginning of e.g. moin.py:

   1 import unfold, __builtin__
   2 _opti_mods = set()
   3 def __import__(name, globals={}, locals={}, fromlist=[]):
   4     mod = __builtin__.__import_old__(name, globals, locals, fromlist)
   5     if name not in _opti_mods:
   6         _opti_mods.add(name)
   7         unfold.bind_all(mod, stoplist=('_url_re', '_acl_cache', '_wiki_plugins',
   8                                        '_opti_mods'))
   9     return mod
  10 
  11 __builtin__.__import_old__ = __builtin__.__import__
  12 __builtin__.__import__ = __import__
  13 
  14 import sys
  15 for mod in sys.modules.copy():
  16     try:
  17         __import__(mod)
  18     except ImportError:
  19         pass

Put this into a folder in the python-path and call it unfold.py:

   1 # stolen from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940
   2 from types import *
   3 import __builtin__
   4 
   5 from opcode import opmap, HAVE_ARGUMENT, EXTENDED_ARG
   6 globals().update(opmap)
   7 
   8 def _make_constants(f, builtin_only=False, stoplist=(), verbose=False):
   9     try:
  10         co = f.func_code
  11     except AttributeError:
  12         return f        # Jython doesn't have a func_code attribute.
  13     newcode = map(ord, co.co_code)
  14     newconsts = list(co.co_consts)
  15     names = co.co_names
  16     codelen = len(newcode)
  17 
  18     env = vars(__builtin__).copy()
  19     if builtin_only:
  20         stoplist = dict.fromkeys(stoplist)
  21         stoplist.update(f.func_globals)
  22     else:
  23         env.update(f.func_globals)
  24 
  25     # First pass converts global lookups into constants
  26     i = 0
  27     while i < codelen:
  28         opcode = newcode[i]
  29         if opcode in (EXTENDED_ARG, STORE_GLOBAL):
  30             return f    # for simplicity, only optimize common cases
  31         if opcode == LOAD_GLOBAL:
  32             oparg = newcode[i+1] + (newcode[i+2] << 8)
  33             name = co.co_names[oparg]
  34             if name in env and name not in stoplist:
  35                 value = env[name]
  36                 for pos, v in enumerate(newconsts):
  37                     if v is value:
  38                         break
  39                 else:
  40                     pos = len(newconsts)
  41                     newconsts.append(value)
  42                 newcode[i] = LOAD_CONST
  43                 newcode[i+1] = pos & 0xFF
  44                 newcode[i+2] = pos >> 8
  45                 if verbose:
  46                     print name, '-->', value
  47         i += 1
  48         if opcode >= HAVE_ARGUMENT:
  49             i += 2
  50 
  51     # Second pass folds tuples of constants and constant attribute lookups
  52     i = 0
  53     while i < codelen:
  54 
  55         newtuple = []
  56         while newcode[i] == LOAD_CONST:
  57             oparg = newcode[i+1] + (newcode[i+2] << 8)
  58             newtuple.append(newconsts[oparg])
  59             i += 3
  60 
  61         opcode = newcode[i]
  62         if not newtuple:
  63             i += 1
  64             if opcode >= HAVE_ARGUMENT:
  65                 i += 2
  66             continue
  67 
  68         if opcode == LOAD_ATTR:
  69             obj = newtuple[-1]
  70             oparg = newcode[i+1] + (newcode[i+2] << 8)
  71             name = names[oparg]
  72             try:
  73                 value = getattr(obj, name)
  74             except AttributeError:
  75                 continue
  76             deletions = 1
  77 
  78         elif opcode == BUILD_TUPLE:
  79             oparg = newcode[i+1] + (newcode[i+2] << 8)
  80             if oparg != len(newtuple):
  81                 continue
  82             deletions = len(newtuple)
  83             value = tuple(newtuple)
  84 
  85         else:
  86             continue
  87 
  88         reljump = deletions * 3
  89         newcode[i-reljump] = JUMP_FORWARD
  90         newcode[i-reljump+1] = (reljump-3) & 0xFF
  91         newcode[i-reljump+2] = (reljump-3) >> 8
  92 
  93         n = len(newconsts)
  94         newconsts.append(value)
  95         newcode[i] = LOAD_CONST
  96         newcode[i+1] = n & 0xFF
  97         newcode[i+2] = n >> 8
  98         i += 3
  99         if verbose:
 100             print "new folded constant:", repr(value)
 101 
 102     codestr = ''.join(map(chr, newcode))
 103     codeobj = type(co)(co.co_argcount, co.co_nlocals, co.co_stacksize,
 104                     co.co_flags, codestr, tuple(newconsts), co.co_names,
 105                     co.co_varnames, co.co_filename, co.co_name,
 106                     co.co_firstlineno, co.co_lnotab, co.co_freevars,
 107                     co.co_cellvars)
 108     return type(f)(codeobj, f.func_globals, f.func_name, f.func_defaults,
 109                     f.func_closure)
 110 
 111 _make_constants = _make_constants(_make_constants) # optimize thyself!
 112 
 113 def bind_all(mc, builtin_only=False, stoplist=(),  verbose=False):
 114     """Recursively apply constant binding to functions in a module or class.
 115 
 116     Use as the last line of the module (after everything is defined, but
 117     before test code).  In modules that need modifiable globals, set
 118     builtin_only to True.
 119     """
 120     try:
 121         d = vars(mc)
 122     except TypeError:
 123         return
 124     for k, v in d.items():
 125         if type(v) is FunctionType:
 126             newv = _make_constants(v, builtin_only, stoplist, verbose)
 127             setattr(mc, k, newv)
 128         elif type(v) in (type, ClassType):
 129             bind_all(v, builtin_only, stoplist, verbose)
 130 
 131 bind_all = _make_constants(bind_all)

MoinMoin: AlexanderSchremmer/ConstantFolding (last edited 2007-10-29 19:07:33 by localhost)