|
I'm running an OSQA site as the sole resident of a reasonably beefy server (4 x 2.13GHz CPUs, 2GB RAM) and seeing execution times of close to a second to render the main page. This doesn't seem normal to me. I ran a profiler and found that most of this time is being spent in template.render:
I see this time and time again on subsequent refreshes. This seems odd to me. Should it be spending that much time rendering in the first place? Isn't the rendered output cacheable to some extent (I am running memcached and it is being used)? Is there something I can do to alleviate this? A little more information on my environment: apache2, worker MPM, mod_wsgi daemonized mode (though I have tried all sorts of permutations of apache2/wsgi configurations with negligible impact). All relevant software is from Ubuntu 10.10 repositories. I should add that this does not seem to be a problem that is appearing with Django in general; I can run django-cms and similar without seeing this sort of problem.
showing 5 of 7
show 2 more comments
|
|
I tracked down some of the slowness in my templates, but I don't think it's the same as yours. Still, this information might be useful to someone else. Firebug reported about 0.7 seconds to display the main forum page. That seems very long. I copied SocketServer.py into my top-level directory so I could edit it and override the system implementation. My change was an
and in serve_forever:
Basically, each request gets profiled, with the results in its own file. I used pyprof2calltree to turn that into something kcachegrind can use
and clear as day, posix.listdir and stat overwhelm the response time. I moved OSQA from the network filesystem to /tmp and Firebug reports 0.25s for the main page. With no obvious hotspots that I can see in the profile report. |
|
Templates are very complex stuff, the text have to be processed/compiled into some machine representation and then rendered, django 1.2 introduces template caching, but that won't affect much, the big bottleneck is the same as in most web applications. Database calls. Most of the data we pass into templates is not the complete data, but rather queryset objects, which are representations of lazy loaded lists. Only when you iterate through them for rendering, the query is performed. Also, stuff like And if you're wondering if memcached is being used, since you use django toolbar do the experience. Turn off cache, render the main page, see how much queries were executed. Turn it back on, render the main page again at least twice (the first so that things get cached). See the difference? I know that memcached is being used. I also know that the database fetches (which are mostly satisfied from cache and in fact never even become SQL queries) are a vanishingly small part of rendering the main page (all the SQL queries and cache fetches that happen for a main page load are finishing in 0.018s). It appears to be just the actual outer parsing and compiling of the template that is taking a lot of time. Database fetches are not to blame here.
(01 Dec '10, 19:56)
tgies
Actually SQL itself is taking way less than 0.018s; I was misreading my profiler output. Django SQL profiler says: "13 queries in 3.65ms". If I throw away memcached, that's still only "151 queries in 31.21ms".
(01 Dec '10, 20:04)
tgies
0.18s is the calculated time starting at when django delegates the query to the database driver, until it gets a result. Then it needs to loop through the result set and instantiate and populate the corresponding model classes. Also, each call to the cache server also takes its time, much less that a regular database call, but it can't be neglected. Then, as I said, templates are complex, and will take it's time to compile and render. Think what happens when a query arrives: django decides what's the best view function to render it based on the url (usually a very fast process). A request object is created, and a couple of very simple pieces of midleware are invoked. Then the view function is called, if you look at a view function they are usually very small and don't require very complex computations. Until now, everythin was pure python, already compiled and loaded in memory. Now, the template parser is asked to render a given template with a given data model. (Continues..)
(01 Dec '10, 20:05)
Hernani Cerq... ♦♦
Technically, the templates are strings that need to be parsed and rendered, think of them almost as an interpreted language being executed by another interpreted language. It's perfectly natural that the rendering process takes much longer than the rest of the application, and unless the logic in the views is extremely complex, that is something you will see in pretty much any django application.
(01 Dec '10, 20:07)
Hernani Cerq... ♦♦
2
0.018s, actually -- a tiny fraction of the total time spent in the renderer. I understand how all this works; I'm just wondering what it is about OSQA in particular that makes it take so much longer to render its templates than any other Django application I run.
(01 Dec '10, 20:45)
tgies
I've answered to that. Is the complexity of the templates. There's lots of options to be considered, and lots of logic in the templates, ifs/fors, etc, and lots of custom tags and filters, and I could go on all night :)
(01 Dec '10, 20:47)
Hernani Cerq... ♦♦
I have to wonder if the complexity of the templates is really that great compared to something like Django CMS (which is an order of magnitude faster in the same environment), and if there are any opportunities for optimization there.
(01 Dec '10, 21:36)
tgies
You really can't compare the amount of information OSQA has to process versus django-cms... If you want to optimize it, start by creating your template and striping out whatever you think you don't need.
(01 Dec '10, 21:48)
Hernani Cerq... ♦♦
showing 5 of 8
show 3 more comments
|
I've noticed the same thing. How do you enable the profiler for a Django request? I've just added a TODO to look into this myself, although likely not until next week.
I run the app in debug mode with Django debug_toolbar enabled and this gizmo that gives me a pane for the hotshot profiler: http://backslashn.com/post/505601626/profiling-execution-with-the-django-debug-toolbar
What version of django are you using? 1.2 introduces template caching (the "compiled" version)
I'm running django 1.2.3. Is there something I need to do to enable template caching?
as an experiment I stood up a mirror of my instance on a 24 x 1.6GHz with 12 GB's of RAM, still takes a little more than a second to render a page ^_^
1 second is to much. You have some other problem then.
most pages don't take that long, just /questions/ which is the page I'm benchmarking at the moment.