Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
profile.py258 linesDownload Raw Back to green
1# Copyright (c) 2010, CCP Games2# All rights reserved.3#4# Redistribution and use in source and binary forms, with or without5# modification, are permitted provided that the following conditions are met:6#     * Redistributions of source code must retain the above copyright7#       notice, this list of conditions and the following disclaimer.8#     * Redistributions in binary form must reproduce the above copyright9#       notice, this list of conditions and the following disclaimer in the10#       documentation and/or other materials provided with the distribution.11#     * Neither the name of CCP Games nor the12#       names of its contributors may be used to endorse or promote products13#       derived from this software without specific prior written permission.14#15# THIS SOFTWARE IS PROVIDED BY CCP GAMES ``AS IS'' AND ANY16# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED17# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE18# DISCLAIMED. IN NO EVENT SHALL CCP GAMES BE LIABLE FOR ANY19# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES20# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;21# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND22# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS24# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.25 26"""This module is API-equivalent to the standard library :mod:`profile` module27lbut it is greenthread-aware as well as thread-aware.  Use this module28to profile Eventlet-based applications in preference to either :mod:`profile` or :mod:`cProfile`.29FIXME: No testcases for this module.30"""31 32profile_orig = __import__('profile')33__all__ = profile_orig.__all__34 35from eventlet.patcher import slurp_properties36slurp_properties(profile_orig, globals(), srckeys=dir(profile_orig))37 38import sys39import functools40 41from eventlet import greenthread42from eventlet import patcher43import six44 45thread = patcher.original(six.moves._thread.__name__)  # non-monkeypatched module needed46 47 48# This class provides the start() and stop() functions49class Profile(profile_orig.Profile):50    base = profile_orig.Profile51 52    def __init__(self, timer=None, bias=None):53        self.current_tasklet = greenthread.getcurrent()54        self.thread_id = thread.get_ident()55        self.base.__init__(self, timer, bias)56        self.sleeping = {}57 58    def __call__(self, *args):59        """make callable, allowing an instance to be the profiler"""60        self.dispatcher(*args)61 62    def _setup(self):63        self._has_setup = True64        self.cur = None65        self.timings = {}66        self.current_tasklet = greenthread.getcurrent()67        self.thread_id = thread.get_ident()68        self.simulate_call("profiler")69 70    def start(self, name="start"):71        if getattr(self, "running", False):72            return73        self._setup()74        self.simulate_call("start")75        self.running = True76        sys.setprofile(self.dispatcher)77 78    def stop(self):79        sys.setprofile(None)80        self.running = False81        self.TallyTimings()82 83    # special cases for the original run commands, makin sure to84    # clear the timer context.85    def runctx(self, cmd, globals, locals):86        if not getattr(self, "_has_setup", False):87            self._setup()88        try:89            return profile_orig.Profile.runctx(self, cmd, globals, locals)90        finally:91            self.TallyTimings()92 93    def runcall(self, func, *args, **kw):94        if not getattr(self, "_has_setup", False):95            self._setup()96        try:97            return profile_orig.Profile.runcall(self, func, *args, **kw)98        finally:99            self.TallyTimings()100 101    def trace_dispatch_return_extend_back(self, frame, t):102        """A hack function to override error checking in parent class.  It103        allows invalid returns (where frames weren't preveiously entered into104        the profiler) which can happen for all the tasklets that suddenly start105        to get monitored. This means that the time will eventually be attributed106        to a call high in the chain, when there is a tasklet switch107        """108        if isinstance(self.cur[-2], Profile.fake_frame):109            return False110            self.trace_dispatch_call(frame, 0)111        return self.trace_dispatch_return(frame, t)112 113    def trace_dispatch_c_return_extend_back(self, frame, t):114        # same for c return115        if isinstance(self.cur[-2], Profile.fake_frame):116            return False  # ignore bogus returns117            self.trace_dispatch_c_call(frame, 0)118        return self.trace_dispatch_return(frame, t)119 120    def SwitchTasklet(self, t0, t1, t):121        # tally the time spent in the old tasklet122        pt, it, et, fn, frame, rcur = self.cur123        cur = (pt, it + t, et, fn, frame, rcur)124 125        # we are switching to a new tasklet, store the old126        self.sleeping[t0] = cur, self.timings127        self.current_tasklet = t1128 129        # find the new one130        try:131            self.cur, self.timings = self.sleeping.pop(t1)132        except KeyError:133            self.cur, self.timings = None, {}134            self.simulate_call("profiler")135            self.simulate_call("new_tasklet")136 137    def TallyTimings(self):138        oldtimings = self.sleeping139        self.sleeping = {}140 141        # first, unwind the main "cur"142        self.cur = self.Unwind(self.cur, self.timings)143 144        # we must keep the timings dicts separate for each tasklet, since it contains145        # the 'ns' item, recursion count of each function in that tasklet.  This is146        # used in the Unwind dude.147        for tasklet, (cur, timings) in six.iteritems(oldtimings):148            self.Unwind(cur, timings)149 150            for k, v in six.iteritems(timings):151                if k not in self.timings:152                    self.timings[k] = v153                else:154                    # accumulate all to the self.timings155                    cc, ns, tt, ct, callers = self.timings[k]156                    # ns should be 0 after unwinding157                    cc += v[0]158                    tt += v[2]159                    ct += v[3]160                    for k1, v1 in six.iteritems(v[4]):161                        callers[k1] = callers.get(k1, 0) + v1162                    self.timings[k] = cc, ns, tt, ct, callers163 164    def Unwind(self, cur, timings):165        "A function to unwind a 'cur' frame and tally the results"166        "see profile.trace_dispatch_return() for details"167        # also see simulate_cmd_complete()168        while(cur[-1]):169            rpt, rit, ret, rfn, frame, rcur = cur170            frame_total = rit + ret171 172            if rfn in timings:173                cc, ns, tt, ct, callers = timings[rfn]174            else:175                cc, ns, tt, ct, callers = 0, 0, 0, 0, {}176 177            if not ns:178                ct = ct + frame_total179                cc = cc + 1180 181            if rcur:182                ppt, pit, pet, pfn, pframe, pcur = rcur183            else:184                pfn = None185 186            if pfn in callers:187                callers[pfn] = callers[pfn] + 1  # hack: gather more188            elif pfn:189                callers[pfn] = 1190 191            timings[rfn] = cc, ns - 1, tt + rit, ct, callers192 193            ppt, pit, pet, pfn, pframe, pcur = rcur194            rcur = ppt, pit + rpt, pet + frame_total, pfn, pframe, pcur195            cur = rcur196        return cur197 198 199def ContextWrap(f):200    @functools.wraps(f)201    def ContextWrapper(self, arg, t):202        current = greenthread.getcurrent()203        if current != self.current_tasklet:204            self.SwitchTasklet(self.current_tasklet, current, t)205            t = 0.0  # the time was billed to the previous tasklet206        return f(self, arg, t)207    return ContextWrapper208 209 210# Add "return safety" to the dispatchers211Profile.dispatch = dict(profile_orig.Profile.dispatch, **{212    'return': Profile.trace_dispatch_return_extend_back,213    'c_return': Profile.trace_dispatch_c_return_extend_back,214})215# Add automatic tasklet detection to the callbacks.216Profile.dispatch = dict((k, ContextWrap(v)) for k, v in six.viewitems(Profile.dispatch))217 218 219# run statements shamelessly stolen from profile.py220def run(statement, filename=None, sort=-1):221    """Run statement under profiler optionally saving results in filename222 223    This function takes a single argument that can be passed to the224    "exec" statement, and an optional file name.  In all cases this225    routine attempts to "exec" its first argument and gather profiling226    statistics from the execution. If no file name is present, then this227    function automatically prints a simple profiling report, sorted by the228    standard name string (file/line/function-name) that is presented in229    each line.230    """231    prof = Profile()232    try:233        prof = prof.run(statement)234    except SystemExit:235        pass236    if filename is not None:237        prof.dump_stats(filename)238    else:239        return prof.print_stats(sort)240 241 242def runctx(statement, globals, locals, filename=None):243    """Run statement under profiler, supplying your own globals and locals,244    optionally saving results in filename.245 246    statement and filename have the same semantics as profile.run247    """248    prof = Profile()249    try:250        prof = prof.runctx(statement, globals, locals)251    except SystemExit:252        pass253 254    if filename is not None:255        prof.dump_stats(filename)256    else:257        return prof.print_stats()258 
codekingpro/portable-devtools · Team Ai