Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
pyramid-debugtoolbar / panels / performance.py
Size: Mime:
from __future__ import with_statement

try:
    import cProfile as profile
except ImportError: # pragma: no cover
    try:
        import profile
    except ImportError: # pragma: no cover
        profile = None
try:
    import resource
except ImportError: # pragma: no cover
    resource = None # Will fail on Win32 systems
try:
    import pstats
except ImportError: # pragma: no cover
    pstats = None # will fail on braindead Debian systems that package pstats
                  # separately from python for god-knows-what-reason

import threading
import time

from pyramid_debugtoolbar.panels import DebugPanel
from pyramid_debugtoolbar.utils import format_fname

_ = lambda x: x

lock = threading.Lock()

class PerformanceDebugPanel(DebugPanel):
    """
    Panel that looks at the performance of a request.

    It will display the time a request took and, optionally, the
    cProfile output.
    """
    name = 'performance'
    user_activate = True
    stats = None
    function_calls = None
    has_resource = bool(resource)
    has_content = bool(pstats and profile)
    template = 'pyramid_debugtoolbar.panels:templates/performance.dbtmako'
    title = _('Performance')
    nav_title = title

    def __init__(self, request):
        if profile is not None:
            self.profiler = profile.Profile()

    def _wrap_timer_handler(self, handler):
        if self.has_resource:
            def resource_timer_handler(request):
                _start_time = time.time()
                self._start_rusage = resource.getrusage(resource.RUSAGE_SELF)
                try:
                    result = handler(request)
                except:
                    raise
                finally:
                    self._end_rusage = resource.getrusage(resource.RUSAGE_SELF)
                    self.total_time = (time.time() - _start_time) * 1000

                return result

            return resource_timer_handler

        def noresource_timer_handler(request):
            _start_time = time.time()
            try:
                result = handler(request)
            except:
                raise
            finally:
                self.total_time = (time.time() - _start_time) * 1000
            return result

        return noresource_timer_handler

    def _wrap_profile_handler(self, handler):
        if not self.is_active:
            return handler

        def profile_handler(request):
            with lock:
                try:
                    result = self.profiler.runcall(handler, request)
                except:
                    raise
                finally:
                    stats = pstats.Stats(self.profiler)
                    function_calls = []
                    flist = stats.sort_stats('cumulative').fcn_list
                    for func in flist:
                        current = {}
                        info = stats.stats[func]

                        # Number of calls
                        if info[0] != info[1]:
                            current['ncalls'] = '%d/%d' % (info[1], info[0])
                        else:
                            current['ncalls'] = info[1]

                        # Total time
                        current['tottime'] = info[2] * 1000

                        # Quotient of total time divided by number of calls
                        if info[1]:
                            current['percall'] = info[2] * 1000 / info[1]
                        else:
                            current['percall'] = 0

                        # Cumulative time
                        current['cumtime'] = info[3] * 1000

                        # Quotient of the cumulative time divded by the number
                        # of primitive calls.
                        if info[0]:
                            current['percall_cum'] = info[3] * 1000 / info[0]
                        else:
                            current['percall_cum'] = 0

                        # Filename
                        filename = pstats.func_std_string(func)
                        current['filename_long'] = filename
                        current['filename'] = format_fname(filename)
                        function_calls.append(current)

                    self.stats = stats
                    self.function_calls = function_calls

                return result

        return profile_handler

    def wrap_handler(self, handler):
        handler = self._wrap_profile_handler(handler)
        handler = self._wrap_timer_handler(handler)
        return handler

    @property
    def nav_subtitle(self):
        return '%0.2fms' % (self.total_time)

    def _elapsed_ru(self, name):
        return getattr(self._end_rusage, name) - getattr(self._start_rusage,
                                                         name)

    def process_response(self, response):
        vars = {'timing_rows':None, 'stats':None, 'function_calls':[]}
        if self.has_resource:
            utime = 1000 * self._elapsed_ru('ru_utime')
            stime = 1000 * self._elapsed_ru('ru_stime')
            vcsw = self._elapsed_ru('ru_nvcsw')
            ivcsw = self._elapsed_ru('ru_nivcsw')
            ## minflt = self._elapsed_ru('ru_minflt')
            ## majflt = self._elapsed_ru('ru_majflt')

# these are documented as not meaningful under Linux.  If you're running BSD
# feel free to enable them, and add any others that I hadn't gotten to before
# I noticed that I was getting nothing but zeroes and that the docs agreed. :-(
#
#            blkin = self._elapsed_ru('ru_inblock')
#            blkout = self._elapsed_ru('ru_oublock')
#            swap = self._elapsed_ru('ru_nswap')
#            rss = self._end_rusage.ru_maxrss
#            srss = self._end_rusage.ru_ixrss
#            urss = self._end_rusage.ru_idrss
#            usrss = self._end_rusage.ru_isrss

            # TODO l10n on values
            rows = (
                (_('User CPU time'), '%0.3f msec' % utime),
                (_('System CPU time'), '%0.3f msec' % stime),
                (_('Total CPU time'), '%0.3f msec' % (utime + stime)),
                (_('Elapsed time'), '%0.3f msec' % self.total_time),
                (_('Context switches'), '%d voluntary, %d involuntary' % (
                    vcsw, ivcsw)),
#                (_('Memory use'), '%d max RSS, %d shared, %d unshared' % (
#                    rss, srss, urss + usrss)),
#                (_('Page faults'), '%d no i/o, %d requiring i/o' % (
#                    minflt, majflt)),
#                (_('Disk operations'), '%d in, %d out, %d swapout' % (
#                    blkin, blkout, swap)),
            )
            vars['timing_rows'] = rows
        if self.is_active:
            vars['stats'] = self.stats
            vars['function_calls'] = self.function_calls
        self.data = vars