Package logilab-common-0 ::
Package 39 ::
Package 0 ::
Module 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
15
16
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
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
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
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
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
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
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
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
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