Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Side by Side Diff: psyco_win32/psyco/profiler.py

Issue 6777021: Adding Win32 installation of Psyco. This will be used to speed up GYP, adding (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « psyco_win32/psyco/logger.py ('k') | psyco_win32/psyco/support.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 ###########################################################################
2 #
3 # Psyco profiler (Python part).
4 # Copyright (C) 2001-2002 Armin Rigo et.al.
5
6 """Psyco profiler (Python part).
7
8 The implementation of the non-time-critical parts of the profiler.
9 See profile() and full() in core.py for the easy interface.
10 """
11 ###########################################################################
12
13 import _psyco
14 from support import *
15 import math, time, types, atexit
16 now = time.time
17 try:
18 import thread
19 except ImportError:
20 import dummy_thread as thread
21
22
23 # current profiler instance
24 current = None
25
26 # enabled profilers, in order of priority
27 profilers = []
28
29 # logger module (when enabled by core.log())
30 logger = None
31
32 # a lock for a thread-safe go()
33 go_lock = thread.allocate_lock()
34
35 def go(stop=0):
36 # run the highest-priority profiler in 'profilers'
37 global current
38 go_lock.acquire()
39 try:
40 prev = current
41 if stop:
42 del profilers[:]
43 if prev:
44 if profilers and profilers[0] is prev:
45 return # best profiler already running
46 prev.stop()
47 current = None
48 for p in profilers[:]:
49 if p.start():
50 current = p
51 if logger: # and p is not prev:
52 logger.write("%s: starting" % p.__class__.__name__, 5)
53 return
54 finally:
55 go_lock.release()
56 # no profiler is running now
57 if stop:
58 if logger:
59 logger.writefinalstats()
60 else:
61 tag2bind()
62
63 atexit.register(go, 1)
64
65
66 def buildfncache(globals, cache):
67 if hasattr(types.IntType, '__dict__'):
68 clstypes = (types.ClassType, types.TypeType)
69 else:
70 clstypes = types.ClassType
71 for x in globals.values():
72 if isinstance(x, types.MethodType):
73 x = x.im_func
74 if isinstance(x, types.FunctionType):
75 cache[x.func_code] = x, ''
76 elif isinstance(x, clstypes):
77 for y in x.__dict__.values():
78 if isinstance(y, types.MethodType):
79 y = y.im_func
80 if isinstance(y, types.FunctionType):
81 cache[y.func_code] = y, x.__name__
82
83 # code-to-function mapping (cache)
84 function_cache = {}
85
86 def trytobind(co, globals, log=1):
87 try:
88 f, clsname = function_cache[co]
89 except KeyError:
90 buildfncache(globals, function_cache)
91 try:
92 f, clsname = function_cache[co]
93 except KeyError:
94 if logger:
95 logger.write('warning: cannot find function %s in %s' %
96 (co.co_name, globals.get('__name__', '?')), 3)
97 return # give up
98 if logger and log:
99 modulename = globals.get('__name__', '?')
100 if clsname:
101 modulename += '.' + clsname
102 logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
103 f.func_code = _psyco.proxycode(f)
104
105
106 # the list of code objects that have been tagged
107 tagged_codes = []
108
109 def tag(co, globals):
110 if logger:
111 try:
112 f, clsname = function_cache[co]
113 except KeyError:
114 buildfncache(globals, function_cache)
115 try:
116 f, clsname = function_cache[co]
117 except KeyError:
118 clsname = '' # give up
119 modulename = globals.get('__name__', '?')
120 if clsname:
121 modulename += '.' + clsname
122 logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
123 tagged_codes.append((co, globals))
124 _psyco.turbo_frame(co)
125 _psyco.turbo_code(co)
126
127 def tag2bind():
128 if tagged_codes:
129 if logger:
130 logger.write('profiling stopped, binding %d functions' %
131 len(tagged_codes), 2)
132 for co, globals in tagged_codes:
133 trytobind(co, globals, 0)
134 function_cache.clear()
135 del tagged_codes[:]
136
137
138 class Profiler:
139 MemoryTimerResolution = 0.103
140
141 def run(self, memory, time, memorymax, timemax):
142 self.memory = memory
143 self.memorymax = memorymax
144 self.time = time
145 if timemax is None:
146 self.endtime = None
147 else:
148 self.endtime = now() + timemax
149 self.alarms = []
150 profilers.append(self)
151 go()
152
153 def start(self):
154 curmem = _psyco.memory()
155 memlimits = []
156 if self.memorymax is not None:
157 if curmem >= self.memorymax:
158 if logger:
159 logger.writememory()
160 return self.limitreached('memorymax')
161 memlimits.append(self.memorymax)
162 if self.memory is not None:
163 if self.memory <= 0:
164 if logger:
165 logger.writememory()
166 return self.limitreached('memory')
167 memlimits.append(curmem + self.memory)
168 self.memory_at_start = curmem
169
170 curtime = now()
171 timelimits = []
172 if self.endtime is not None:
173 if curtime >= self.endtime:
174 return self.limitreached('timemax')
175 timelimits.append(self.endtime - curtime)
176 if self.time is not None:
177 if self.time <= 0.0:
178 return self.limitreached('time')
179 timelimits.append(self.time)
180 self.time_at_start = curtime
181
182 try:
183 self.do_start()
184 except error, e:
185 if logger:
186 logger.write('%s: disabled by psyco.error:' % (
187 self.__class__.__name__), 4)
188 logger.write(' %s' % str(e), 3)
189 return 0
190
191 if memlimits:
192 self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
193 self.check_memory, (min(memlimits),))
194 self.alarms.append(_psyco.alarm(*self.memlimits_args))
195 if timelimits:
196 self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
197 self.time_out))
198 return 1
199
200 def stop(self):
201 for alarm in self.alarms:
202 alarm.stop(0)
203 for alarm in self.alarms:
204 alarm.stop(1) # wait for parallel threads to stop
205 del self.alarms[:]
206 if self.time is not None:
207 self.time -= now() - self.time_at_start
208 if self.memory is not None:
209 self.memory -= _psyco.memory() - self.memory_at_start
210
211 try:
212 self.do_stop()
213 except error:
214 return 0
215 return 1
216
217 def check_memory(self, limit):
218 if _psyco.memory() < limit:
219 return self.memlimits_args
220 go()
221
222 def time_out(self):
223 self.time = 0.0
224 go()
225
226 def limitreached(self, limitname):
227 try:
228 profilers.remove(self)
229 except ValueError:
230 pass
231 if logger:
232 logger.write('%s: disabled (%s limit reached)' % (
233 self.__class__.__name__, limitname), 4)
234 return 0
235
236
237 class FullCompiler(Profiler):
238
239 def do_start(self):
240 _psyco.profiling('f')
241
242 def do_stop(self):
243 _psyco.profiling('.')
244
245
246 class RunOnly(Profiler):
247
248 def do_start(self):
249 _psyco.profiling('n')
250
251 def do_stop(self):
252 _psyco.profiling('.')
253
254
255 class ChargeProfiler(Profiler):
256
257 def __init__(self, watermark, parentframe):
258 self.watermark = watermark
259 self.parent2 = parentframe * 2.0
260 self.lock = thread.allocate_lock()
261
262 def init_charges(self):
263 _psyco.statwrite(watermark = self.watermark,
264 parent2 = self.parent2)
265
266 def do_stop(self):
267 _psyco.profiling('.')
268 _psyco.statwrite(callback = None)
269
270
271 class ActiveProfiler(ChargeProfiler):
272
273 def active_start(self):
274 _psyco.profiling('p')
275
276 def do_start(self):
277 self.init_charges()
278 self.active_start()
279 _psyco.statwrite(callback = self.charge_callback)
280
281 def charge_callback(self, frame, charge):
282 tag(frame.f_code, frame.f_globals)
283
284
285 class PassiveProfiler(ChargeProfiler):
286
287 initial_charge_unit = _psyco.statread('unit')
288 reset_stats_after = 120 # half-lives (maximum 200!)
289 reset_limit = initial_charge_unit * (2.0 ** reset_stats_after)
290
291 def __init__(self, watermark, halflife, pollfreq, parentframe):
292 ChargeProfiler.__init__(self, watermark, parentframe)
293 self.pollfreq = pollfreq
294 # self.progress is slightly more than 1.0, and computed so that
295 # do_profile() will double the change_unit every 'halflife' seconds.
296 self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
297
298 def reset(self):
299 _psyco.statwrite(unit = self.initial_charge_unit, callback = None)
300 _psyco.statreset()
301 if logger:
302 logger.write("%s: resetting stats" % self.__class__.__name__, 1)
303
304 def passive_start(self):
305 self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
306 self.do_profile)
307 self.alarms.append(_psyco.alarm(*self.passivealarm_args))
308
309 def do_start(self):
310 tag2bind()
311 self.init_charges()
312 self.passive_start()
313
314 def do_profile(self):
315 _psyco.statcollect()
316 if logger:
317 logger.dumpcharges()
318 nunit = _psyco.statread('unit') * self.progress
319 if nunit > self.reset_limit:
320 self.reset()
321 else:
322 _psyco.statwrite(unit = nunit, callback = self.charge_callback)
323 return self.passivealarm_args
324
325 def charge_callback(self, frame, charge):
326 trytobind(frame.f_code, frame.f_globals)
327
328
329 class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
330
331 def do_start(self):
332 self.init_charges()
333 self.active_start()
334 self.passive_start()
335
336 def charge_callback(self, frame, charge):
337 tag(frame.f_code, frame.f_globals)
338
339
340
341 #
342 # we register our own version of sys.settrace(), sys.setprofile()
343 # and thread.start_new_thread().
344 #
345
346 def psyco_settrace(*args, **kw):
347 "This is the Psyco-aware version of sys.settrace()."
348 result = original_settrace(*args, **kw)
349 go()
350 return result
351
352 def psyco_setprofile(*args, **kw):
353 "This is the Psyco-aware version of sys.setprofile()."
354 result = original_setprofile(*args, **kw)
355 go()
356 return result
357
358 def psyco_thread_stub(callable, args, kw):
359 _psyco.statcollect()
360 if kw is None:
361 return callable(*args)
362 else:
363 return callable(*args, **kw)
364
365 def psyco_start_new_thread(callable, args, kw=None):
366 "This is the Psyco-aware version of thread.start_new_thread()."
367 return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
368
369 original_settrace = sys.settrace
370 original_setprofile = sys.setprofile
371 original_start_new_thread = thread.start_new_thread
372 sys.settrace = psyco_settrace
373 sys.setprofile = psyco_setprofile
374 thread.start_new_thread = psyco_start_new_thread
375 # hack to patch threading._start_new_thread if the module is
376 # already loaded
377 if ('threading' in sys.modules and
378 hasattr(sys.modules['threading'], '_start_new_thread')):
379 sys.modules['threading']._start_new_thread = psyco_start_new_thread
OLDNEW
« no previous file with comments | « psyco_win32/psyco/logger.py ('k') | psyco_win32/psyco/support.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698