I added some timing code to see how expensive a cold app startup is.
This is a Django1.x app so YMMV.
The typical numbers are:
Zipimport of Django: 180ms
Appengine-django-helper monkeypatching: 430ms
Misc imports, app-specific patching, etc: 20ms
------------------------------------------------------------------------
Total app startup: 630ms
This is for startup only, not the time it takes to then process the
request, so this is a fixed expense. Also, this is real time not cpu
quota time which is much higher.
The biggest hog is the django-helper monkeypatcher. I'm eventually
going to try appengine-patch with the hope that it will be faster.
Additionally, on a cold startup my app processes a request in about
500ms, but on a warm app it only takes 10ms due to some aggressive
caching. I think that when all your app instances expire so does all
it's memcached data.
If anybody has done something similar and found different numbers
please post the results and let me know what I did wrong.
Here's the main.py I'm using in case you'd like to point out any
errors in my methodology:
----------------------------------------
from time import clock
t_main_start = clock()
# Standard Python imports.
import os
import sys
import logging
import settings
logging.getLogger().setLevel(settings.LOGGING_LEVEL)
# Fix (hack) for missing unlink
if
os.name == 'nt':
os.unlink = lambda: None
# TODO (after gathering stats): remove this since appengine_django
does it for us
# Import Django 1.x from a zipfile and get rid of v.96.
t_zip_start = clock()
django_zip_path = os.path.abspath('django.zip')
if django_zip_path not in sys.path:
sys.path.insert(0, django_zip_path)
for k in [k for k in sys.modules if k.startswith('django')]:
del sys.modules[k]
# TODO (after gathering stats): remove this line
from django import template # provoke django zipimport
t_zip = (clock() - t_zip_start) * 1000
# Install appengine_django. Patches Django 1.x for use with GAE
t_patch_start = clock()
from appengine_django import InstallAppengineHelperForDjango
InstallAppengineHelperForDjango()
t_patch = (clock() - t_patch_start) * 1000
# Patch the appengine_django patch to fix User object creation
# Remove this when switching to appengine-patch
from monkeypatch import patch
patch()
# Google App Engine imports.
from google.appengine.ext.webapp import util
# Import the part of Django that we use here.
import django.core.handlers.wsgi
t_main = (clock() - t_main_start) * 1000
logging.info('[TIME] main.py startup: %.1fms (zipimport: %.1fms,
appengine-django: %.1fms)' % (t_main,t_zip,t_patch))
def real_main():
t_request_start = clock()
# Create a Django application for WSGI.
application = django.core.handlers.wsgi.WSGIHandler()
# Run the WSGI CGI handler with that application.
util.run_wsgi_app(application)
t_request = (clock() - t_request_start) * 1000
logging.info('[TIME] request: %.1fms' % t_request)
def profile_main():
# Rename this to main() for profiling
import cProfile, pstats
prof = cProfile.Profile()
prof = prof.runctx("real_main()", globals(), locals())
print "<pre>"
stats = pstats.Stats(prof)
stats.sort_stats("time") # Or cumulative
stats.print_stats(80) # 80 = how many to print
# The rest is optional.
#stats.print_callees()
#stats.print_callers()
print "</pre>"
main = real_main
if __name__ == '__main__':
main()