| 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
 | 
| 
 | 
| 
 |