Re^2: Profiling/Benchmarking web applications.
by jryan (Vicar) on Aug 25, 2004 at 06:05 UTC
|
Thanks for the tips, but the bottleneck turned out to be Template Toolkit. It's taking up an unbelievable 60% of the total invocation time. I'm actually pretty shocked; I knew TT was pretty heavyweight, but I'm not even embedding Perl code within the templates! I'm totally stumpted.
| [reply] |
|
|
You don't mention whether your application runs under CGI or a persistent framework such as mod_perl, FastCGI or PersistentPerl.
If you care about performance, I assume you're avoiding CGI so you can reuse database connections and other things that take some time to initialise. Template Toolkit objects are such things: calling Template->new() for each request will make your application run more slowly.
Template Toolkit is used on plenty of high volume Web sites: it's certainly possible to have it run quickly. Unless your application is very simple, TT shouldn't take up 60% of the application's run time.
| [reply] |
|
|
Thanks for the tips, but the bottleneck turned out to be Template Toolkit. It's taking up an unbelievable 60% of the total invocation time. I'm actually pretty shocked
That's high. Are you:
- Only creating the Template instance once (I'm assuming you're using mod_perl)?
- Caching compiled templates (take a look at the COMPILE_EXT and COMPILE_DIR configuration options)?
| [reply] |
|
|
| [reply] |
|
|
If you're not using some of the more advanced features of TT, perhaps you can switch to a lighter-weight Templating engine? We use HTML::Template, and it does the job for us. Obviously it has a lot less features. I can't guarantee that it's faster, though. Perhaps you can determine what features you MUST-HAVE in your templating system, then install all the ones that meet your needs, and do a comparison of their performance? If you do this, report your findings, since I'm sure others would be interested in the results.
| [reply] |
|
|
The other replies have addressed some of the reactions I have regarding TT taking 60% of the response time. I have a few further questions.
- 60% of what? Is it 10 seconds? 1 minute? 1 second?
- Are you using mod_perl? That one single item will often cut 50% of your response time. And, it's a change that's transparent to the CGI scripts.1
- Are you using a ton of nested BLOCK directives?
- Are you doing things like
[% foo = $bar.baz %]
[% baz = qux.$foo %]
That does a lot of eval work behind the scenes, which can be expensive.
- How deep are your nested loops? Nesting loops don't scale linearly, in any templating system. HTML::Template, which is arguably the most efficient commonly used templating system has serious performance problems with loops nested 3+ deep.
- Can you compile and/or cache the output from some of your templates?
- Are you making calls to the database in your templates using the DBI plugin?
- Assuming, of course, you used sane coding standards. Persistence can be a bitch if you're converting the first CGI script you ever wrote to run under MP::Registry.
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
I shouldn't have to say this, but any code, unless otherwise stated, is untested
| [reply] [d/l] |
|
|
Well...
- Approx 1.25 seconds; caching the compiled templates took it down to approx 1 second.
- yes
- no
- no, I'm use .item when working with nested hashes
- Now that's something I didn't know. The main data section has nested loops four-deep. Column order is defined in a config file, so we do something like this:
[% FOREACH set IN [data_header.top_priority,
data_header.middle_priority] %]
[% FOREACH fieldno IN set %]
[% field = data_header.field.slice(fieldno, fieldno).0 %]
[% value = order.item(make_key(field.title))
...
Which probably isn't very nice to the TT processor.
- I wasn't, but I am now.
- No, calls to the database are made through callback functions.
| [reply] [d/l] |
|
|
|
|
|
Re^2: Profiling/Benchmarking web applications.
by kappa (Chaplain) on Aug 25, 2004 at 17:31 UTC
|
Are you suggesting optimizing non-profiled code? While experience usually helps you identify bottlenecks with mere eye-grep, you'd better not encourage others to do the same.
One of the most strong laws of performance tuning is: never ever even think of optimizing before profiling. You just gonna spend your time on the code that could potentially not affect performance at all. And you usually skip those things that are considered fast and quick, but in fact suck. You probably know about those gotchas with Cache::SharedMemoryCache or HTML::Template's global_vars. Weren't they surprises? Just examples of how important profiling is (and how rarely it is really carried on).
| [reply] |
|
|
You are absolutely correct - nothing is a substitute for good profiling, and everyone should become familiar with ways of profiling their application. (The same goes for testing, too.)
However, there are certain constructs which are known to be performance hogs. For example, using $sth->fetchall_arrayref({}); is practically the slowest way to get data from a database, when compared with other methods. Another is H::T's global_vars, as you mentioned. These don't need to be profiled because they are known performance hits.
I would suggest merging our two approaches. Setting up a good profiling scenario can be time-consuming. In my experience, tackling the usual suspects has almost always provided enough improvement without needing to do a full profiling of a webapp.
However, after hitting the usual suspects, profiling is most definitely the way to go. And, frankly, I'm not surprised that output generation is expensive. But, I suspect that most webapps are getting bogged down in other areas.
------
We are the carpenters and bricklayers of the Information Age.
Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose
I shouldn't have to say this, but any code, unless otherwise stated, is untested
| [reply] [d/l] |