1 ########################################################################### |
|
2 # |
|
3 # Psyco main functions. |
|
4 # Copyright (C) 2001-2002 Armin Rigo et.al. |
|
5 |
|
6 """Psyco main functions. |
|
7 |
|
8 Here are the routines that you can use from your applications. |
|
9 These are mostly interfaces to the C core, but they depend on |
|
10 the Python version. |
|
11 |
|
12 You can use these functions from the 'psyco' module instead of |
|
13 'psyco.core', e.g. |
|
14 |
|
15 import psyco |
|
16 psyco.log('/tmp/psyco.log') |
|
17 psyco.profile() |
|
18 """ |
|
19 ########################################################################### |
|
20 |
|
21 import _psyco |
|
22 import types, new |
|
23 from support import * |
|
24 |
|
25 |
|
26 # Default charge profiler values |
|
27 default_watermark = 0.09 # between 0.0 (0%) and 1.0 (100%) |
|
28 default_halflife = 0.5 # seconds |
|
29 default_pollfreq_profile = 20 # Hz |
|
30 default_pollfreq_background = 100 # Hz -- a maximum for sleep's resolution |
|
31 default_parentframe = 0.25 # should not be more than 0.5 (50%) |
|
32 |
|
33 |
|
34 def full(memory=None, time=None, memorymax=None, timemax=None): |
|
35 """Compile as much as possible. |
|
36 |
|
37 Typical use is for small scripts performing intensive computations |
|
38 or string handling.""" |
|
39 import profiler |
|
40 p = profiler.FullCompiler() |
|
41 p.run(memory, time, memorymax, timemax) |
|
42 |
|
43 |
|
44 def profile(watermark = default_watermark, |
|
45 halflife = default_halflife, |
|
46 pollfreq = default_pollfreq_profile, |
|
47 parentframe = default_parentframe, |
|
48 memory=None, time=None, memorymax=None, timemax=None): |
|
49 """Turn on profiling. |
|
50 |
|
51 The 'watermark' parameter controls how easily running functions will |
|
52 be compiled. The smaller the value, the more functions are compiled.""" |
|
53 import profiler |
|
54 p = profiler.ActivePassiveProfiler(watermark, halflife, |
|
55 pollfreq, parentframe) |
|
56 p.run(memory, time, memorymax, timemax) |
|
57 |
|
58 |
|
59 def background(watermark = default_watermark, |
|
60 halflife = default_halflife, |
|
61 pollfreq = default_pollfreq_background, |
|
62 parentframe = default_parentframe, |
|
63 memory=None, time=None, memorymax=None, timemax=None): |
|
64 """Turn on passive profiling. |
|
65 |
|
66 This is a very lightweight mode in which only intensively computing |
|
67 functions can be detected. The smaller the 'watermark', the more functions |
|
68 are compiled.""" |
|
69 import profiler |
|
70 p = profiler.PassiveProfiler(watermark, halflife, pollfreq, parentframe) |
|
71 p.run(memory, time, memorymax, timemax) |
|
72 |
|
73 |
|
74 def runonly(memory=None, time=None, memorymax=None, timemax=None): |
|
75 """Nonprofiler. |
|
76 |
|
77 XXX check if this is useful and document.""" |
|
78 import profiler |
|
79 p = profiler.RunOnly() |
|
80 p.run(memory, time, memorymax, timemax) |
|
81 |
|
82 |
|
83 def stop(): |
|
84 """Turn off all automatic compilation. bind() calls remain in effect.""" |
|
85 import profiler |
|
86 profiler.go([]) |
|
87 |
|
88 |
|
89 def log(logfile='', mode='w', top=10): |
|
90 """Enable logging to the given file. |
|
91 |
|
92 If the file name is unspecified, a default name is built by appending |
|
93 a 'log-psyco' extension to the main script name. |
|
94 |
|
95 Mode is 'a' to append to a possibly existing file or 'w' to overwrite |
|
96 an existing file. Note that the log file may grow quickly in 'a' mode.""" |
|
97 import profiler, logger |
|
98 if not logfile: |
|
99 import os |
|
100 logfile, dummy = os.path.splitext(sys.argv[0]) |
|
101 if os.path.basename(logfile): |
|
102 logfile += '.' |
|
103 logfile += 'log-psyco' |
|
104 if hasattr(_psyco, 'VERBOSE_LEVEL'): |
|
105 print >> sys.stderr, 'psyco: logging to', logfile |
|
106 # logger.current should be a real file object; subtle problems |
|
107 # will show up if its write() and flush() methods are written |
|
108 # in Python, as Psyco will invoke them while compiling. |
|
109 logger.current = open(logfile, mode) |
|
110 logger.print_charges = top |
|
111 profiler.logger = logger |
|
112 logger.writedate('Logging started') |
|
113 cannotcompile(logger.psycowrite) |
|
114 _psyco.statwrite(logger=logger.psycowrite) |
|
115 |
|
116 |
|
117 def bind(x, rec=None): |
|
118 """Enable compilation of the given function, method, or class object. |
|
119 |
|
120 If C is a class (or anything with a '__dict__' attribute), bind(C) will |
|
121 rebind all functions and methods found in C.__dict__ (which means, for |
|
122 classes, all methods defined in the class but not in its parents). |
|
123 |
|
124 The optional second argument specifies the number of recursive |
|
125 compilation levels: all functions called by func are compiled |
|
126 up to the given depth of indirection.""" |
|
127 if isinstance(x, types.MethodType): |
|
128 x = x.im_func |
|
129 if isinstance(x, types.FunctionType): |
|
130 if rec is None: |
|
131 x.func_code = _psyco.proxycode(x) |
|
132 else: |
|
133 x.func_code = _psyco.proxycode(x, rec) |
|
134 return |
|
135 if hasattr(x, '__dict__'): |
|
136 funcs = [o for o in x.__dict__.values() |
|
137 if isinstance(o, types.MethodType) |
|
138 or isinstance(o, types.FunctionType)] |
|
139 if not funcs: |
|
140 raise error, ("nothing bindable found in %s object" % |
|
141 type(x).__name__) |
|
142 for o in funcs: |
|
143 bind(o, rec) |
|
144 return |
|
145 raise TypeError, "cannot bind %s objects" % type(x).__name__ |
|
146 |
|
147 |
|
148 def unbind(x): |
|
149 """Reverse of bind().""" |
|
150 if isinstance(x, types.MethodType): |
|
151 x = x.im_func |
|
152 if isinstance(x, types.FunctionType): |
|
153 try: |
|
154 f = _psyco.unproxycode(x.func_code) |
|
155 except error: |
|
156 pass |
|
157 else: |
|
158 x.func_code = f.func_code |
|
159 return |
|
160 if hasattr(x, '__dict__'): |
|
161 for o in x.__dict__.values(): |
|
162 if (isinstance(o, types.MethodType) |
|
163 or isinstance(o, types.FunctionType)): |
|
164 unbind(o) |
|
165 return |
|
166 raise TypeError, "cannot unbind %s objects" % type(x).__name__ |
|
167 |
|
168 |
|
169 def proxy(x, rec=None): |
|
170 """Return a Psyco-enabled copy of the function. |
|
171 |
|
172 The original function is still available for non-compiled calls. |
|
173 The optional second argument specifies the number of recursive |
|
174 compilation levels: all functions called by func are compiled |
|
175 up to the given depth of indirection.""" |
|
176 if isinstance(x, types.FunctionType): |
|
177 if rec is None: |
|
178 code = _psyco.proxycode(x) |
|
179 else: |
|
180 code = _psyco.proxycode(x, rec) |
|
181 return new.function(code, x.func_globals, x.func_name) |
|
182 if isinstance(x, types.MethodType): |
|
183 p = proxy(x.im_func, rec) |
|
184 return new.instancemethod(p, x.im_self, x.im_class) |
|
185 raise TypeError, "cannot proxy %s objects" % type(x).__name__ |
|
186 |
|
187 |
|
188 def unproxy(proxy): |
|
189 """Return a new copy of the original function of method behind a proxy. |
|
190 The result behaves like the original function in that calling it |
|
191 does not trigger compilation nor execution of any compiled code.""" |
|
192 if isinstance(proxy, types.FunctionType): |
|
193 return _psyco.unproxycode(proxy.func_code) |
|
194 if isinstance(proxy, types.MethodType): |
|
195 f = unproxy(proxy.im_func) |
|
196 return new.instancemethod(f, proxy.im_self, proxy.im_class) |
|
197 raise TypeError, "%s objects cannot be proxies" % type(proxy).__name__ |
|
198 |
|
199 |
|
200 def cannotcompile(x): |
|
201 """Instruct Psyco never to compile the given function, method |
|
202 or code object.""" |
|
203 if isinstance(x, types.MethodType): |
|
204 x = x.im_func |
|
205 if isinstance(x, types.FunctionType): |
|
206 x = x.func_code |
|
207 if isinstance(x, types.CodeType): |
|
208 _psyco.cannotcompile(x) |
|
209 else: |
|
210 raise TypeError, "unexpected %s object" % type(x).__name__ |
|
211 |
|
212 |
|
213 def dumpcodebuf(): |
|
214 """Write in file psyco.dump a copy of the emitted machine code, |
|
215 provided Psyco was compiled with a non-zero CODE_DUMP. |
|
216 See py-utils/httpxam.py to examine psyco.dump.""" |
|
217 if hasattr(_psyco, 'dumpcodebuf'): |
|
218 _psyco.dumpcodebuf() |
|
219 |
|
220 |
|
221 ########################################################################### |
|
222 # Psyco variables |
|
223 # error * the error raised by Psyco |
|
224 # warning * the warning raised by Psyco |
|
225 # __in_psyco__ * a new built-in variable which is always zero, but which |
|
226 # Psyco special-cases by returning 1 instead. So |
|
227 # __in_psyco__ can be used in a function to know if |
|
228 # that function is being executed by Psyco or not. |
|