Package logilab-common-0 :: Package 36 :: Package 1 :: Module bind
[frames] | no frames]

Source Code for Module logilab-common-0.36.1.bind

  1  """Optimize globals in certain functions by binding their names to values 
  2  provided in a dictionnary. 
  3   
  4  :copyright: 2002-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 
  5  :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr 
  6  :license: General Public License version 2 - http://www.gnu.org/licenses 
  7  """ 
  8  __docformat__ = "restructuredtext en" 
  9   
 10  from warnings import warn 
 11  warn('logilab.common.bind module is deprecated and will disappear in a near release', 
 12       DeprecationWarning, stacklevel=2) 
 13   
 14  # TODO: unit tests 
 15  # * this module provide a function bind(func,vars) which replaces every 
 16  #   global variable 'm' by the value vars['m'] if such value exists in dict 
 17   
 18  from dis import HAVE_ARGUMENT 
 19  from new import code as make_code, function as make_function 
 20  import inspect 
 21   
 22  LOAD_GLOBAL = 116 
 23  LOAD_CONST = 100 
 24  EXTENDED_ARG = 143 
 25  STORE_GLOBAL = 97 
 26   
27 -def bind_code(co, globals):
28 """ 29 Take a code object and a dictionnary and returns a new code object where 30 the opcodes LOAD_GLOBAL are replaced by LOAD_CONST whenever the global's 31 name appear in the dictionnary 32 """ 33 consts = list(co.co_consts) 34 assigned = {} 35 36 code = co.co_code 37 new_code = "" 38 n = len(code) 39 i = 0 40 while i < n: 41 c = code[i] 42 op = ord(c) 43 i += 1 44 if op >= HAVE_ARGUMENT: 45 oparg = ord(code[i]) + ord(code[i+1]) * 256 46 i += 2 47 else: 48 oparg = None 49 if op == LOAD_GLOBAL: 50 name = co.co_names[oparg] 51 if name in globals: 52 k = assigned.get(name, None) 53 if k == None: 54 k = len(consts) 55 assigned[name] = len(consts) 56 consts.append(globals[name]) 57 op = LOAD_CONST 58 oparg = k 59 new_code += chr(op) 60 if oparg is not None: 61 new_code += chr(oparg & 255) 62 new_code += chr( (oparg>>8) & 255 ) 63 64 return make_code(co.co_argcount, 65 co.co_nlocals, 66 co.co_stacksize, 67 co.co_flags, 68 new_code, 69 tuple(consts), 70 co.co_names, 71 co.co_varnames, 72 co.co_filename, 73 co.co_name, 74 co.co_firstlineno, 75 co.co_lnotab )
76 77
78 -def bind(f, globals):
79 """Returns a new function whose code object has been 80 bound by bind_code()""" 81 newcode = bind_code(f.func_code, globals) 82 defaults = f.func_defaults or () 83 return make_function(newcode, f.func_globals, f.func_name, defaults)
84 85 if type(__builtins__) == dict: 86 builtins = __builtins__ 87 else: 88 builtins = __builtins__.__dict__ 89 90 bind_code_opt = bind(bind_code, builtins ) 91 bind_code_opt = bind(bind_code_opt, globals() ) 92 93
94 -def optimize_module(m, global_consts):
95 if not inspect.ismodule(m): 96 raise TypeError 97 d = {} 98 for i in global_consts: 99 v = m.__dict__.get(i) 100 d[i] = v 101 builtins = m.__builtins__ 102 for name, f in m.__dict__.items(): 103 if inspect.isfunction(f): 104 f = bind(f, builtins) 105 if d: 106 f = bind(f, d) 107 m.__dict__[name] = f
108 109 110 111
112 -def analyze_code(co, globals, consts_dict, consts_list):
113 """Take a code object and a dictionnary and returns a 114 new code object where the opcodes LOAD_GLOBAL are replaced 115 by LOAD_CONST whenever the global's name appear in the 116 dictionnary""" 117 modified_globals = [] 118 for c in co.co_consts: 119 if c not in consts_list: 120 consts_list.append(c) 121 modified = [] 122 code = co.co_code 123 new_code = "" 124 n = len(code) 125 i = 0 126 extended_arg = 0 127 while i < n: 128 c = code[i] 129 op = ord(c) 130 i += 1 131 if op >= HAVE_ARGUMENT: 132 oparg = ord(code[i]) + ord(code[i+1])*256 + extended_arg 133 extended_arg = 0 134 i += 2 135 else: 136 oparg = None 137 if op == EXTENDED_ARG: 138 extended_arg = oparg*65536L 139 140 if op == LOAD_GLOBAL: 141 name = co.co_names[oparg] 142 if name in globals: 143 k = consts_dict.get(name, None) 144 if k == None: 145 k = len(consts_list) 146 consts_dict[name] = k 147 consts_list.append(globals[name]) 148 if op == STORE_GLOBAL: 149 name = co.co_names[oparg] 150 if name in globals: 151 modified_globals.append(name) 152 return modified_globals
153
154 -def rewrite_code(co, consts_dict, consts_tuple):
155 """Take a code object and a dictionnary and returns a 156 new code object where the opcodes LOAD_GLOBAL are replaced 157 by LOAD_CONST whenever the global's name appear in the 158 dictionnary""" 159 code = co.co_code 160 new_code = "" 161 n = len(code) 162 i = 0 163 consts_list = list(consts_tuple) 164 while i < n: 165 c = code[i] 166 op = ord(c) 167 i += 1 168 extended_arg = 0 169 if op >= HAVE_ARGUMENT: 170 oparg = ord(code[i]) + ord(code[i+1])*256+extended_arg 171 extended_arg = 0 172 i += 2 173 else: 174 oparg = None 175 if op == EXTENDED_ARG: 176 extended_arg = oparg*65536L 177 elif op == LOAD_GLOBAL: 178 name = co.co_names[oparg] 179 k = consts_dict.get(name) 180 if k is not None: 181 op = LOAD_CONST 182 oparg = k 183 elif op == LOAD_CONST: 184 val = co.co_consts[oparg] 185 oparg = consts_list.index(val) 186 new_code += chr(op) 187 if oparg is not None: 188 new_code += chr(oparg & 255) 189 new_code += chr( (oparg>>8) & 255 ) 190 191 return make_code(co.co_argcount, 192 co.co_nlocals, 193 co.co_stacksize, 194 co.co_flags, 195 new_code, 196 consts_tuple, 197 co.co_names, 198 co.co_varnames, 199 co.co_filename, 200 co.co_name, 201 co.co_firstlineno, 202 co.co_lnotab )
203
204 -def optimize_module_2(m, globals_consts, bind_builtins=1):
205 if not inspect.ismodule(m): 206 raise TypeError 207 consts_dict = {} 208 consts_list = [] 209 if type(globals_consts) == list or type(globals_consts) == tuple: 210 globals = {} 211 for i in globals_consts: 212 v = m.__dict__.get(i) 213 globals[i] = v 214 else: 215 globals = globals_consts 216 if bind_builtins: 217 for builtin_name, builtin_value in m.__builtins__.items(): 218 # this way it is possible to redefine a builtin in globals_consts 219 globals.setdefault(builtin_name, builtin_value) 220 functions = {} 221 for name, f in m.__dict__.items(): 222 if inspect.isfunction(f): 223 functions[name] = f 224 analyze_code(f.func_code, globals, consts_dict, consts_list) 225 consts_list = tuple(consts_list) 226 for name, f in functions.items(): 227 newcode = rewrite_code(f.func_code, consts_dict, consts_list) 228 defaults = f.func_defaults or () 229 m.__dict__[name] = make_function(newcode, f.func_globals, f.func_name, 230 defaults)
231 232
233 -def run_bench(n):
234 from time import time 235 t = time() 236 g = globals() 237 for i in range(n): 238 test = bind(bind_code, g) 239 t1 = time()-t 240 bind2 = bind(bind, {'bind_code':bind_code_opt}) 241 t = time() 242 for i in range(n): 243 test=bind2(bind_code, g) 244 t2 = time()-t 245 print "1 regular version", t1 246 print "2 optimized version", t2 247 print "ratio (1-2)/1 : %f %%" % (100.*(t1-t2)/t1)
248 249
250 -def test_pystone():
251 from test import pystone 252 for _ in range(5): 253 pystone.main() 254 optimize_module(pystone, ('TRUE','FALSE','Proc0','Proc1','Proc2','Proc3', 255 'Proc4','Proc5','Proc6','Proc7','Proc8','Func1', 256 ' Func2','Func3')) 257 optimize_module(pystone, builtins.keys()) 258 for _ in range(5): 259 pystone.main()
260 261 262 if __name__ == "__main__": 263 run_bench(1000) 264