Created
November 13, 2009 23:57
-
-
Save mmalone/234279 to your computer and use it in GitHub Desktop.
Replacement Django runserver command that does profiling... because I've rewritten this too many times.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
>>> import pstats | |
>>> p = pstats.Stats('p.1258156459.52174278XcQE.prof') | |
>>> p.strip_dirs().sort_stats(-1).print_stats(5) | |
Fri Nov 13 15:54:20 2009 p.1258156459.52174278XcQE.prof | |
124278 function calls (122386 primitive calls) in 0.589 CPU seconds | |
Ordered by: standard name | |
List reduced from 1014 to 5 due to restriction <5> | |
ncalls tottime percall cumtime percall filename:lineno(function) | |
1 0.003 0.003 0.003 0.003 <string>:1(connect) | |
1 0.000 0.000 0.000 0.000 <string>:1(getpeername) | |
1 0.000 0.000 0.000 0.000 <string>:1(gettimeout) | |
2 0.000 0.000 0.000 0.000 <string>:1(settimeout) | |
29 0.000 0.000 0.000 0.000 <string>:8(__new__) | |
<pstats.Stats instance at 0x501260> | |
>>> p.strip_dirs().sort_stats('cumulative').print_stats(5) | |
Fri Nov 13 15:54:20 2009 p.1258156459.52174278XcQE.prof | |
124278 function calls (122386 primitive calls) in 0.589 CPU seconds | |
Ordered by: cumulative time | |
List reduced from 1014 to 5 due to restriction <5> | |
ncalls tottime percall cumtime percall filename:lineno(function) | |
1 0.000 0.000 0.589 0.589 basehttp.py:644(__call__) | |
1 0.000 0.000 0.589 0.589 wsgi.py:221(__call__) | |
1 0.000 0.000 0.580 0.580 base.py:66(get_response) | |
1 0.000 0.000 0.577 0.577 views.py:72(home) | |
1 0.000 0.000 0.577 0.577 base.py:311(__init__) | |
<pstats.Stats instance at 0x501260> | |
>>> p.strip_dirs().sort_stats('time').print_stats(5) | |
Fri Nov 13 15:54:20 2009 p.1258156459.52174278XcQE.prof | |
124278 function calls (122386 primitive calls) in 0.589 CPU seconds | |
Ordered by: internal time | |
List reduced from 1014 to 5 due to restriction <5> | |
ncalls tottime percall cumtime percall filename:lineno(function) | |
358 0.409 0.001 0.409 0.001 {built-in method read} | |
4098 0.026 0.000 0.039 0.000 posixpath.py:59(join) | |
4098 0.025 0.000 0.025 0.000 {posix.lstat} | |
1 0.015 0.015 0.015 0.015 {built-in method do_handshake} | |
387 0.012 0.000 0.095 0.000 posixpath.py:344(realpath) | |
<pstats.Stats instance at 0x501260> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ ./manage.py runserver --profile --profdir=./profiles/ --noprofmedia |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.management.base import BaseCommand, CommandError | |
from optparse import make_option | |
import os | |
import sys | |
class Command(BaseCommand): | |
option_list = BaseCommand.option_list + ( | |
make_option('--noreload', action='store_false', dest='use_reloader', default=True, | |
help='Tells Django to NOT use the auto-reloader.'), | |
make_option('--adminmedia', dest='admin_media_path', default='', | |
help='Specifies the directory from which to serve admin media.'), | |
make_option('--profile', action='store_true', dest='profile', | |
help='Enable profiling. Write profiles into system\'s temporary directory'), | |
make_option('--profdir', dest='profile_temp_dir', default=None, | |
help='Specifies the directory in which to store profile data.'), | |
make_option('--noprofmedia', action='store_false', dest='profile_media', default=True, | |
help='Disable profiling for requests if request path starts with settings.MEDIA_URL'), | |
) | |
help = "Starts a lightweight Web server for development." | |
args = '[optional port number, or ipaddr:port]' | |
# Validation is called explicitly each time the server is reloaded. | |
requires_model_validation = False | |
def handle(self, addrport='', *args, **options): | |
import django | |
from django.core.servers.basehttp import run, AdminMediaHandler, WSGIServerException | |
from django.core.handlers.wsgi import WSGIHandler | |
if args: | |
raise CommandError('Usage is runserver %s' % self.args) | |
if not addrport: | |
addr = '' | |
port = '8000' | |
else: | |
try: | |
addr, port = addrport.split(':') | |
except ValueError: | |
addr, port = '', addrport | |
if not addr: | |
addr = '127.0.0.1' | |
if not port.isdigit(): | |
raise CommandError("%r is not a valid port number." % port) | |
use_reloader = options.get('use_reloader', True) | |
admin_media_path = options.get('admin_media_path', '') | |
shutdown_message = options.get('shutdown_message', '') | |
profile = options.get('profile', False) | |
profile_temp_dir = options.get('profile_temp_dir', None) | |
profile_media = options.get('profile_media', True) | |
quit_command = (sys.platform == 'win32') and 'CTRL-BREAK' or 'CONTROL-C' | |
def inner_run(): | |
from django.conf import settings | |
from django.utils import translation | |
print "Validating models..." | |
self.validate(display_num_errors=True) | |
print "\nDjango version %s, using settings %r" % (django.get_version(), settings.SETTINGS_MODULE) | |
print "Development server is running at http://%s:%s/" % (addr, port) | |
print "Quit the server with %s." % quit_command | |
# django.core.management.base forces the locale to en-us. We should | |
# set it up correctly for the first request (particularly important | |
# in the "--noreload" case). | |
translation.activate(settings.LANGUAGE_CODE) | |
try: | |
if profile: | |
import cProfile, time, tempfile | |
if profile_temp_dir is not None: | |
tempfile.tempdir = profile_temp_dir | |
def make_profiler_handler(inner_handler): | |
def handler(environ, start_response): | |
path = environ['PATH_INFO'] | |
if not profile_media and path.startswith(settings.MEDIA_URL): | |
return inner_handler(environ, start_response) | |
path = path.strip('/').replace('/', '.') | |
if path: | |
prefix = 'p.%s.%3f' % (path, time.time()) | |
else: | |
prefix = 'p.%3f' % time.time() | |
fd, profname = tempfile.mkstemp('.prof', prefix) | |
os.close(fd) | |
prof = cProfile.Profile() | |
try: | |
return prof.runcall(inner_handler, environ, start_response) | |
finally: | |
prof.dump_stats(profname) | |
return handler | |
handler = make_profiler_handler(AdminMediaHandler(WSGIHandler(), admin_media_path)) | |
else: | |
handler = AdminMediaHandler(WSGIHandler(), admin_media_path) | |
run(addr, int(port), handler) | |
except WSGIServerException, e: | |
# Use helpful error messages instead of ugly tracebacks. | |
ERRORS = { | |
13: "You don't have permission to access that port.", | |
98: "That port is already in use.", | |
99: "That IP address can't be assigned-to.", | |
} | |
try: | |
error_text = ERRORS[e.args[0].args[0]] | |
except (AttributeError, KeyError): | |
error_text = str(e) | |
sys.stderr.write(self.style.ERROR("Error: %s" % error_text) + '\n') | |
# Need to use an OS exit because sys.exit doesn't work in a thread | |
os._exit(1) | |
except KeyboardInterrupt: | |
if shutdown_message: | |
print shutdown_message | |
sys.exit(0) | |
if use_reloader: | |
from django.utils import autoreload | |
autoreload.main(inner_run) | |
else: | |
inner_run() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# See http://www.vrplumber.com/programming/runsnakerun/ | |
$ runsnake p.1258156462.721626cTJ6rF.prof | |
# OR | |
$ runsnake p.* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
INSTALLED_APPS += ('profiler',) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment