| Index: third_party/cherrypy/lib/profiler.py
|
| ===================================================================
|
| --- third_party/cherrypy/lib/profiler.py (revision 0)
|
| +++ third_party/cherrypy/lib/profiler.py (revision 0)
|
| @@ -0,0 +1,208 @@
|
| +"""Profiler tools for CherryPy.
|
| +
|
| +CherryPy users
|
| +==============
|
| +
|
| +You can profile any of your pages as follows::
|
| +
|
| + from cherrypy.lib import profiler
|
| +
|
| + class Root:
|
| + p = profile.Profiler("/path/to/profile/dir")
|
| +
|
| + def index(self):
|
| + self.p.run(self._index)
|
| + index.exposed = True
|
| +
|
| + def _index(self):
|
| + return "Hello, world!"
|
| +
|
| + cherrypy.tree.mount(Root())
|
| +
|
| +You can also turn on profiling for all requests
|
| +using the ``make_app`` function as WSGI middleware.
|
| +
|
| +CherryPy developers
|
| +===================
|
| +
|
| +This module can be used whenever you make changes to CherryPy,
|
| +to get a quick sanity-check on overall CP performance. Use the
|
| +``--profile`` flag when running the test suite. Then, use the ``serve()``
|
| +function to browse the results in a web browser. If you run this
|
| +module from the command line, it will call ``serve()`` for you.
|
| +
|
| +"""
|
| +
|
| +
|
| +def new_func_strip_path(func_name):
|
| + """Make profiler output more readable by adding ``__init__`` modules' parents"""
|
| + filename, line, name = func_name
|
| + if filename.endswith("__init__.py"):
|
| + return os.path.basename(filename[:-12]) + filename[-12:], line, name
|
| + return os.path.basename(filename), line, name
|
| +
|
| +try:
|
| + import profile
|
| + import pstats
|
| + pstats.func_strip_path = new_func_strip_path
|
| +except ImportError:
|
| + profile = None
|
| + pstats = None
|
| +
|
| +import os, os.path
|
| +import sys
|
| +import warnings
|
| +
|
| +from cherrypy._cpcompat import BytesIO
|
| +
|
| +_count = 0
|
| +
|
| +class Profiler(object):
|
| +
|
| + def __init__(self, path=None):
|
| + if not path:
|
| + path = os.path.join(os.path.dirname(__file__), "profile")
|
| + self.path = path
|
| + if not os.path.exists(path):
|
| + os.makedirs(path)
|
| +
|
| + def run(self, func, *args, **params):
|
| + """Dump profile data into self.path."""
|
| + global _count
|
| + c = _count = _count + 1
|
| + path = os.path.join(self.path, "cp_%04d.prof" % c)
|
| + prof = profile.Profile()
|
| + result = prof.runcall(func, *args, **params)
|
| + prof.dump_stats(path)
|
| + return result
|
| +
|
| + def statfiles(self):
|
| + """:rtype: list of available profiles.
|
| + """
|
| + return [f for f in os.listdir(self.path)
|
| + if f.startswith("cp_") and f.endswith(".prof")]
|
| +
|
| + def stats(self, filename, sortby='cumulative'):
|
| + """:rtype stats(index): output of print_stats() for the given profile.
|
| + """
|
| + sio = BytesIO()
|
| + if sys.version_info >= (2, 5):
|
| + s = pstats.Stats(os.path.join(self.path, filename), stream=sio)
|
| + s.strip_dirs()
|
| + s.sort_stats(sortby)
|
| + s.print_stats()
|
| + else:
|
| + # pstats.Stats before Python 2.5 didn't take a 'stream' arg,
|
| + # but just printed to stdout. So re-route stdout.
|
| + s = pstats.Stats(os.path.join(self.path, filename))
|
| + s.strip_dirs()
|
| + s.sort_stats(sortby)
|
| + oldout = sys.stdout
|
| + try:
|
| + sys.stdout = sio
|
| + s.print_stats()
|
| + finally:
|
| + sys.stdout = oldout
|
| + response = sio.getvalue()
|
| + sio.close()
|
| + return response
|
| +
|
| + def index(self):
|
| + return """<html>
|
| + <head><title>CherryPy profile data</title></head>
|
| + <frameset cols='200, 1*'>
|
| + <frame src='menu' />
|
| + <frame name='main' src='' />
|
| + </frameset>
|
| + </html>
|
| + """
|
| + index.exposed = True
|
| +
|
| + def menu(self):
|
| + yield "<h2>Profiling runs</h2>"
|
| + yield "<p>Click on one of the runs below to see profiling data.</p>"
|
| + runs = self.statfiles()
|
| + runs.sort()
|
| + for i in runs:
|
| + yield "<a href='report?filename=%s' target='main'>%s</a><br />" % (i, i)
|
| + menu.exposed = True
|
| +
|
| + def report(self, filename):
|
| + import cherrypy
|
| + cherrypy.response.headers['Content-Type'] = 'text/plain'
|
| + return self.stats(filename)
|
| + report.exposed = True
|
| +
|
| +
|
| +class ProfileAggregator(Profiler):
|
| +
|
| + def __init__(self, path=None):
|
| + Profiler.__init__(self, path)
|
| + global _count
|
| + self.count = _count = _count + 1
|
| + self.profiler = profile.Profile()
|
| +
|
| + def run(self, func, *args):
|
| + path = os.path.join(self.path, "cp_%04d.prof" % self.count)
|
| + result = self.profiler.runcall(func, *args)
|
| + self.profiler.dump_stats(path)
|
| + return result
|
| +
|
| +
|
| +class make_app:
|
| + def __init__(self, nextapp, path=None, aggregate=False):
|
| + """Make a WSGI middleware app which wraps 'nextapp' with profiling.
|
| +
|
| + nextapp
|
| + the WSGI application to wrap, usually an instance of
|
| + cherrypy.Application.
|
| +
|
| + path
|
| + where to dump the profiling output.
|
| +
|
| + aggregate
|
| + if True, profile data for all HTTP requests will go in
|
| + a single file. If False (the default), each HTTP request will
|
| + dump its profile data into a separate file.
|
| +
|
| + """
|
| + if profile is None or pstats is None:
|
| + msg = ("Your installation of Python does not have a profile module. "
|
| + "If you're on Debian, try `sudo apt-get install python-profiler`. "
|
| + "See http://www.cherrypy.org/wiki/ProfilingOnDebian for details.")
|
| + warnings.warn(msg)
|
| +
|
| + self.nextapp = nextapp
|
| + self.aggregate = aggregate
|
| + if aggregate:
|
| + self.profiler = ProfileAggregator(path)
|
| + else:
|
| + self.profiler = Profiler(path)
|
| +
|
| + def __call__(self, environ, start_response):
|
| + def gather():
|
| + result = []
|
| + for line in self.nextapp(environ, start_response):
|
| + result.append(line)
|
| + return result
|
| + return self.profiler.run(gather)
|
| +
|
| +
|
| +def serve(path=None, port=8080):
|
| + if profile is None or pstats is None:
|
| + msg = ("Your installation of Python does not have a profile module. "
|
| + "If you're on Debian, try `sudo apt-get install python-profiler`. "
|
| + "See http://www.cherrypy.org/wiki/ProfilingOnDebian for details.")
|
| + warnings.warn(msg)
|
| +
|
| + import cherrypy
|
| + cherrypy.config.update({'server.socket_port': int(port),
|
| + 'server.thread_pool': 10,
|
| + 'environment': "production",
|
| + })
|
| + cherrypy.quickstart(Profiler(path))
|
| +
|
| +
|
| +if __name__ == "__main__":
|
| + serve(*tuple(sys.argv[1:]))
|
| +
|
|
|
| Property changes on: third_party/cherrypy/lib/profiler.py
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|