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