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

Unified 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, 9 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « psyco_win32/psyco/logger.py ('k') | psyco_win32/psyco/support.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: psyco_win32/psyco/profiler.py
===================================================================
--- psyco_win32/psyco/profiler.py (revision 0)
+++ psyco_win32/psyco/profiler.py (revision 0)
@@ -0,0 +1,379 @@
+###########################################################################
+#
+# Psyco profiler (Python part).
+# Copyright (C) 2001-2002 Armin Rigo et.al.
+
+"""Psyco profiler (Python part).
+
+The implementation of the non-time-critical parts of the profiler.
+See profile() and full() in core.py for the easy interface.
+"""
+###########################################################################
+
+import _psyco
+from support import *
+import math, time, types, atexit
+now = time.time
+try:
+ import thread
+except ImportError:
+ import dummy_thread as thread
+
+
+# current profiler instance
+current = None
+
+# enabled profilers, in order of priority
+profilers = []
+
+# logger module (when enabled by core.log())
+logger = None
+
+# a lock for a thread-safe go()
+go_lock = thread.allocate_lock()
+
+def go(stop=0):
+ # run the highest-priority profiler in 'profilers'
+ global current
+ go_lock.acquire()
+ try:
+ prev = current
+ if stop:
+ del profilers[:]
+ if prev:
+ if profilers and profilers[0] is prev:
+ return # best profiler already running
+ prev.stop()
+ current = None
+ for p in profilers[:]:
+ if p.start():
+ current = p
+ if logger: # and p is not prev:
+ logger.write("%s: starting" % p.__class__.__name__, 5)
+ return
+ finally:
+ go_lock.release()
+ # no profiler is running now
+ if stop:
+ if logger:
+ logger.writefinalstats()
+ else:
+ tag2bind()
+
+atexit.register(go, 1)
+
+
+def buildfncache(globals, cache):
+ if hasattr(types.IntType, '__dict__'):
+ clstypes = (types.ClassType, types.TypeType)
+ else:
+ clstypes = types.ClassType
+ for x in globals.values():
+ if isinstance(x, types.MethodType):
+ x = x.im_func
+ if isinstance(x, types.FunctionType):
+ cache[x.func_code] = x, ''
+ elif isinstance(x, clstypes):
+ for y in x.__dict__.values():
+ if isinstance(y, types.MethodType):
+ y = y.im_func
+ if isinstance(y, types.FunctionType):
+ cache[y.func_code] = y, x.__name__
+
+# code-to-function mapping (cache)
+function_cache = {}
+
+def trytobind(co, globals, log=1):
+ try:
+ f, clsname = function_cache[co]
+ except KeyError:
+ buildfncache(globals, function_cache)
+ try:
+ f, clsname = function_cache[co]
+ except KeyError:
+ if logger:
+ logger.write('warning: cannot find function %s in %s' %
+ (co.co_name, globals.get('__name__', '?')), 3)
+ return # give up
+ if logger and log:
+ modulename = globals.get('__name__', '?')
+ if clsname:
+ modulename += '.' + clsname
+ logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
+ f.func_code = _psyco.proxycode(f)
+
+
+# the list of code objects that have been tagged
+tagged_codes = []
+
+def tag(co, globals):
+ if logger:
+ try:
+ f, clsname = function_cache[co]
+ except KeyError:
+ buildfncache(globals, function_cache)
+ try:
+ f, clsname = function_cache[co]
+ except KeyError:
+ clsname = '' # give up
+ modulename = globals.get('__name__', '?')
+ if clsname:
+ modulename += '.' + clsname
+ logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
+ tagged_codes.append((co, globals))
+ _psyco.turbo_frame(co)
+ _psyco.turbo_code(co)
+
+def tag2bind():
+ if tagged_codes:
+ if logger:
+ logger.write('profiling stopped, binding %d functions' %
+ len(tagged_codes), 2)
+ for co, globals in tagged_codes:
+ trytobind(co, globals, 0)
+ function_cache.clear()
+ del tagged_codes[:]
+
+
+class Profiler:
+ MemoryTimerResolution = 0.103
+
+ def run(self, memory, time, memorymax, timemax):
+ self.memory = memory
+ self.memorymax = memorymax
+ self.time = time
+ if timemax is None:
+ self.endtime = None
+ else:
+ self.endtime = now() + timemax
+ self.alarms = []
+ profilers.append(self)
+ go()
+
+ def start(self):
+ curmem = _psyco.memory()
+ memlimits = []
+ if self.memorymax is not None:
+ if curmem >= self.memorymax:
+ if logger:
+ logger.writememory()
+ return self.limitreached('memorymax')
+ memlimits.append(self.memorymax)
+ if self.memory is not None:
+ if self.memory <= 0:
+ if logger:
+ logger.writememory()
+ return self.limitreached('memory')
+ memlimits.append(curmem + self.memory)
+ self.memory_at_start = curmem
+
+ curtime = now()
+ timelimits = []
+ if self.endtime is not None:
+ if curtime >= self.endtime:
+ return self.limitreached('timemax')
+ timelimits.append(self.endtime - curtime)
+ if self.time is not None:
+ if self.time <= 0.0:
+ return self.limitreached('time')
+ timelimits.append(self.time)
+ self.time_at_start = curtime
+
+ try:
+ self.do_start()
+ except error, e:
+ if logger:
+ logger.write('%s: disabled by psyco.error:' % (
+ self.__class__.__name__), 4)
+ logger.write(' %s' % str(e), 3)
+ return 0
+
+ if memlimits:
+ self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
+ self.check_memory, (min(memlimits),))
+ self.alarms.append(_psyco.alarm(*self.memlimits_args))
+ if timelimits:
+ self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
+ self.time_out))
+ return 1
+
+ def stop(self):
+ for alarm in self.alarms:
+ alarm.stop(0)
+ for alarm in self.alarms:
+ alarm.stop(1) # wait for parallel threads to stop
+ del self.alarms[:]
+ if self.time is not None:
+ self.time -= now() - self.time_at_start
+ if self.memory is not None:
+ self.memory -= _psyco.memory() - self.memory_at_start
+
+ try:
+ self.do_stop()
+ except error:
+ return 0
+ return 1
+
+ def check_memory(self, limit):
+ if _psyco.memory() < limit:
+ return self.memlimits_args
+ go()
+
+ def time_out(self):
+ self.time = 0.0
+ go()
+
+ def limitreached(self, limitname):
+ try:
+ profilers.remove(self)
+ except ValueError:
+ pass
+ if logger:
+ logger.write('%s: disabled (%s limit reached)' % (
+ self.__class__.__name__, limitname), 4)
+ return 0
+
+
+class FullCompiler(Profiler):
+
+ def do_start(self):
+ _psyco.profiling('f')
+
+ def do_stop(self):
+ _psyco.profiling('.')
+
+
+class RunOnly(Profiler):
+
+ def do_start(self):
+ _psyco.profiling('n')
+
+ def do_stop(self):
+ _psyco.profiling('.')
+
+
+class ChargeProfiler(Profiler):
+
+ def __init__(self, watermark, parentframe):
+ self.watermark = watermark
+ self.parent2 = parentframe * 2.0
+ self.lock = thread.allocate_lock()
+
+ def init_charges(self):
+ _psyco.statwrite(watermark = self.watermark,
+ parent2 = self.parent2)
+
+ def do_stop(self):
+ _psyco.profiling('.')
+ _psyco.statwrite(callback = None)
+
+
+class ActiveProfiler(ChargeProfiler):
+
+ def active_start(self):
+ _psyco.profiling('p')
+
+ def do_start(self):
+ self.init_charges()
+ self.active_start()
+ _psyco.statwrite(callback = self.charge_callback)
+
+ def charge_callback(self, frame, charge):
+ tag(frame.f_code, frame.f_globals)
+
+
+class PassiveProfiler(ChargeProfiler):
+
+ initial_charge_unit = _psyco.statread('unit')
+ reset_stats_after = 120 # half-lives (maximum 200!)
+ reset_limit = initial_charge_unit * (2.0 ** reset_stats_after)
+
+ def __init__(self, watermark, halflife, pollfreq, parentframe):
+ ChargeProfiler.__init__(self, watermark, parentframe)
+ self.pollfreq = pollfreq
+ # self.progress is slightly more than 1.0, and computed so that
+ # do_profile() will double the change_unit every 'halflife' seconds.
+ self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
+
+ def reset(self):
+ _psyco.statwrite(unit = self.initial_charge_unit, callback = None)
+ _psyco.statreset()
+ if logger:
+ logger.write("%s: resetting stats" % self.__class__.__name__, 1)
+
+ def passive_start(self):
+ self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
+ self.do_profile)
+ self.alarms.append(_psyco.alarm(*self.passivealarm_args))
+
+ def do_start(self):
+ tag2bind()
+ self.init_charges()
+ self.passive_start()
+
+ def do_profile(self):
+ _psyco.statcollect()
+ if logger:
+ logger.dumpcharges()
+ nunit = _psyco.statread('unit') * self.progress
+ if nunit > self.reset_limit:
+ self.reset()
+ else:
+ _psyco.statwrite(unit = nunit, callback = self.charge_callback)
+ return self.passivealarm_args
+
+ def charge_callback(self, frame, charge):
+ trytobind(frame.f_code, frame.f_globals)
+
+
+class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
+
+ def do_start(self):
+ self.init_charges()
+ self.active_start()
+ self.passive_start()
+
+ def charge_callback(self, frame, charge):
+ tag(frame.f_code, frame.f_globals)
+
+
+
+#
+# we register our own version of sys.settrace(), sys.setprofile()
+# and thread.start_new_thread().
+#
+
+def psyco_settrace(*args, **kw):
+ "This is the Psyco-aware version of sys.settrace()."
+ result = original_settrace(*args, **kw)
+ go()
+ return result
+
+def psyco_setprofile(*args, **kw):
+ "This is the Psyco-aware version of sys.setprofile()."
+ result = original_setprofile(*args, **kw)
+ go()
+ return result
+
+def psyco_thread_stub(callable, args, kw):
+ _psyco.statcollect()
+ if kw is None:
+ return callable(*args)
+ else:
+ return callable(*args, **kw)
+
+def psyco_start_new_thread(callable, args, kw=None):
+ "This is the Psyco-aware version of thread.start_new_thread()."
+ return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
+
+original_settrace = sys.settrace
+original_setprofile = sys.setprofile
+original_start_new_thread = thread.start_new_thread
+sys.settrace = psyco_settrace
+sys.setprofile = psyco_setprofile
+thread.start_new_thread = psyco_start_new_thread
+# hack to patch threading._start_new_thread if the module is
+# already loaded
+if ('threading' in sys.modules and
+ hasattr(sys.modules['threading'], '_start_new_thread')):
+ sys.modules['threading']._start_new_thread = psyco_start_new_thread
Property changes on: psyco_win32\psyco\profiler.py
___________________________________________________________________
Added: svn:eol-style
+ LF
« 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