summaryrefslogtreecommitdiff
path: root/cherrypy/lib/profiler.py
diff options
context:
space:
mode:
authorRobert Brewer <fumanchu@aminus.org>2005-06-10 19:54:04 +0000
committerRobert Brewer <fumanchu@aminus.org>2005-06-10 19:54:04 +0000
commitf29f394614a30fe5e77fa0f89caaca078d2bf5a8 (patch)
tree29b2f89dc380aee7d27f5f480133ae718506debf /cherrypy/lib/profiler.py
parent39670134d00e50350fac89de2e81061d67b27f68 (diff)
downloadcherrypy-git-f29f394614a30fe5e77fa0f89caaca078d2bf5a8.tar.gz
Merged new test suite from branches/ticket-177 into trunk.
Diffstat (limited to 'cherrypy/lib/profiler.py')
-rw-r--r--cherrypy/lib/profiler.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/cherrypy/lib/profiler.py b/cherrypy/lib/profiler.py
new file mode 100644
index 00000000..86403b64
--- /dev/null
+++ b/cherrypy/lib/profiler.py
@@ -0,0 +1,153 @@
+"""
+Copyright (c) 2004, CherryPy Team (team@cherrypy.org)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the CherryPy Team nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+
+"""Profiler tools for CherryPy.
+
+CherryPy users
+==============
+
+You can profile any of your pages as follows:
+
+ from cherrypy.lib import profile
+
+ 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!"
+
+ cpg.root = Root()
+
+
+CherryPy developers
+===================
+
+This module can be used whenever you make changes to CherryPy, to get a
+quick sanity-check on overall CP performance. Set the config entry:
+"profiling.on = True" to turn on profiling. 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.
+
+"""
+
+
+import hotshot
+import os, os.path
+import sys
+
+try:
+ import cStringIO as StringIO
+except ImportError:
+ import StringIO
+
+
+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)
+ self.count = 0
+
+ def run(self, func, *args):
+ """run(func, *args). Run func, dumping profile data into self.path."""
+ self.count += 1
+ path = os.path.join(self.path, "cp_%04d.prof" % self.count)
+ prof = hotshot.Profile(path)
+ prof.runcall(func, *args)
+ prof.close()
+
+ def statfiles(self):
+ """statfiles() -> 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'):
+ """stats(index) -> output of print_stats() for the given profile."""
+ from hotshot.stats import load
+ s = load(os.path.join(self.path, filename))
+ s.strip_dirs()
+ s.sort_stats(sortby)
+ oldout = sys.stdout
+ try:
+ sys.stdout = sio = StringIO.StringIO()
+ 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):
+ from cherrypy import cpg
+ cpg.response.headerMap['Content-Type'] = 'text/plain'
+ return self.stats(filename)
+ report.exposed = True
+
+
+def serve(path=None, port=8080):
+ from cherrypy import cpg
+ cpg.root = Profiler(path)
+ cpg.config.update({'/': {'server.serverPort': port,
+ 'server.threadPool': 10,
+ 'server.environment': "production",
+ 'session.storageType': "ram",
+ }
+ })
+ cpg.server.start()
+
+
+if __name__ == "__main__":
+ serve(*tuple(sys.argv[1:]))
+