Support Spidean |
Do you like our FREE downloads? How about the FREE support for the FREE downloads? Please help us out and donate any amount! It's fast and easy through PayPal.
|
anomaly
Newbie   Posts: 6 Registered: 7/29/2008 Status: Offline
|
posted on 8/31/2008 at 03:01 PM |
Hi all,
I've been working on moving/upgrading a site that was owned by a friend of
mine. During the move, I upgraded PN to .764, PNphpBB to latest, and
AT-Lite to latest. I've been trying to boost the site's performance, and
noticed that after I had optimized most other things that I could (database
configuration, postnuke configuration, etc), I noticed that the most
substantial speed culprit was AutoTheme.
Therefore, I downloaded/installed APD, which is a PHP debugger that allowed
me to analyze where the performance bottlenecks were. I found that in
almost all page loads, the str_replace calls in atAPI.php:atCommandReplace
were using up 1/2 to 2/3 of the total php page generation time (about
1500-2000 calls were made on each load).
First I tried to reduce the number of str_replace calls to 2 by doing all
the replacements in a single pass (and it was used in two places). Doing
so did not noticeably speed up my installation and I have yet to compare it
to the old implementation, but here are the changes I made to it:
========This may or may not speed up your installation========
function atCommandReplace($tmpcontent, $commands=array())
{
$runningconfig = atGetRunningConfig();
extract($runningconfig);
/* $search = '/{repeat [wd_]+) [wd:_]+)}(.*){repeat}/';
$replace = STARTPHP.' for($i=0; $i<count($$1["$2"]); $i++) {
eval(''.ENDPHP.'$3'); } '.ENDPHP;
$tmpcontent = preg_replace($search, $replace, $tmpcontent); */
$commands = array_merge((array)$command, (array)$commands);
$search = array();
$replace = array();
foreach ($commands as $cmd => $action) {
$search[] = "<!-- [$cmd] -->";
$search[] = "<!--[$cmd]-->";
$search[] = "<!-- {".$cmd."} -->";
$search[] = "<!--{".$cmd."}-->";
$search[] = "{".$cmd."}";
$replace[] = STARTPHP." $action ".ENDPHP;
$replace[] = STARTPHP." $action ".ENDPHP;
$replace[] = STARTPHP." $action ".ENDPHP;
$replace[] = STARTPHP." $action ".ENDPHP;
$replace[] = STARTPHP." $action ".ENDPHP;
}
$tmpcontent = str_replace($search, $replace, $tmpcontent);
foreach ($runningconfig as $cmd => $action) {
$search[] = "<!-- [$cmd] -->";
$search[] = "<!--[$cmd]-->";
$search[] = "<!-- {".$cmd."} -->";
$search[] = "<!--{".$cmd."}-->";
$search[] = "{".$cmd."}";
$replace[] = STARTPHP." echo $$cmd; ".ENDPHP;
$replace[] = STARTPHP." echo $$cmd; ".ENDPHP;
$replace[] = STARTPHP." echo $$cmd; ".ENDPHP;
$replace[] = STARTPHP." echo $$cmd; ".ENDPHP;
$replace[] = STARTPHP." echo $$cmd; ".ENDPHP;
}
$tmpcontent = str_replace($search, $replace, $tmpcontent);
return $tmpcontent;
}
================End atAPI modification====================
After some further investigation, I discovered that this *should* be
avoided via the AutoTheme template modification method (and indeed, one
call to this expensive method is). However, it turns out that this is the
general sequence of events:
1. If there is no cached template file, Autotheme takes the template data
for the page and performs all of the expensive replacement methods on
it.
2. If AutoTheme had to reparse the template data, it writes it out to a
cache file.
3. Before the page is displayed, autotheme takes the generic HTML.html
page and drops the previously generated data in the middle of it.
4. To catch the tags to be converted in the HTML.html file, autotheme runs
the expensive replacement methods again.
5. Autotheme outputs the code.
The problem is that while AutoTheme caches the generated page data, it in
fact runs the expensive methods over this data a second time to catch what
it missed in this HTML.html "wrapper".
Therefore, I simply set autotheme to run the expensive methods over
HTML.html, cache it, and then drop the already-parsed data in the middle of
this. Therefore, there should be no reason to run the expensive
atCommandReplace code each time a page is displayed. Doing this resulted
in substantial speedup for me. Obviously, perform this modification at
your own risk, but I'd like to hear if it works for others.
========In atExtended.php around line 58================
Change this code:
-------------
$HTML = atTemplateRead($file);
$HTML = eregi_replace('</head>', '', $HTML);
$HTML = preg_replace('/(<!--[ ]*[|{)display(}|][ ]*--> /', $display,
$HTML);
$output = atCommandReplace($HTML);
------------
To this:
------------
if (!$output = atCompileRead($file)) {
$HTML = atTemplatePrep($file,0);
$globalconfig = atGetGlobalConfig();
$output = atCommandReplace($HTML,
$globalconfig{'command'});
atCompileWrite($file, $output);
}
$output = preg_replace('/(<!--[ ]*[|{)display(}|][ ]*--> /', $display,
$output);
------------
================End Modification=================
Obviously, today is the first time I've looked at the AutoTheme source, so
if the author of the software has any comments on this I'd appreciate it as
there could be issues I'm not aware of.
|
| |
| |
Shawn
Administrator   Posts: 4575 Registered: 10/7/2002 Status: Online
|
posted on 8/31/2008 at 04:11 PM |
Hi,
Thanks for the write-up. Most of these issues are being eliminated in the
next AutoTheme version. What you see is a result of extending AutoTheme
over time without rewriting or optimizing. Here are some suggestions (not
tested):
1. atCommandReplace() has some lingering old code. You could do only one
replacement and search on only one tag type if you have only one (i.e.
<!-- [some-command] -->, or two tags maybe if you need to (i.e.
{some-command}). The current implementation is meant to be more
flexible.
function atCommandReplace($tmpcontent, $commands=array())
{
$runningconfig = atGetRunningConfig();
extract($runningconfig);
$commands = array_merge($runningconfig, (array)$command,
(array)$commands);
$search = $replace =array();
foreach ($commands as $cmd => $action) {
$search[] = "<!-- [$cmd] -->";
$replace[] = STARTPHP." $action ".ENDPHP;
}
return str_replace($search, $replace, $tmpcontent);
}
2. The sequence of events is this in AT-Lite:
a. Check for and load "compiled" template. A compiled template is a
template that has already had the replace run and the template saved. So
the PHP code is in the template, not the result of the PHP code.
b. If no compiled template exists, run the replace and save the compiled
template. a and b are done for every template type (i.e. main page
template, leftblock, rightblock, article, etc.).
c. At the end, insert the complete theme template into the DOCTYPE
template.
d. Run the replace again. The reason for this is to replace the dynamic
stuff like title, keywords, etc. and to allow people to use the AutoTheme
tags outside of the theme (i.e. in a module or other CMS code). You could
add somewhere in a module's code and AutoTheme would replace it when the
module is displayed. I thought this was a great feature, but like many of
the features I don't know how many people use it, if any.
FYI... The commercial AutoTheme 1.77 includes full page "caching", which
caches the entire page and after that never runs any code, only displays
the cached page. You can exclude pages from caching (i.e. admin pages,
forum, etc.) and set the cache expire time.
3. If you only run the replace at the end and save the compiled result,
then you only have one compiled template and data may be stagnant, like in
the title tag it might read My Cool Site always, instead of echo $title;.
You should test this and see how it works for you.
4. I'm going to test a preg_replace_callback() for the next version and see
if it outperforms the loop/str_replace() in atCommandReplace(). You might
try it. I haven't tried this but off the top of my head this is an example
for thought, YMMV:
function atCommandReplace($tmpcontent, $commands=array())
{
$runningconfig = atGetRunningConfig();
$GLOBALS['AT_RUNNING']['commands'] = array_merge($runningconfig,
(array)$runningconfig['command'], (array)$commands);
// the forum is removing my escape slashes so the pattern is not escaped
properly
$tmpcontent = preg_replace_callback('/(?:<!--[ ]*[|{)([^]}]+)(?:}|][
]*-->/', 'at_command_replace', $tmpcontent);
return $tmpcontent;
}
function at_command_replace($matches)
{
$cmd = $matches[1];
return $GLOBALS['AT_RUNNING']['commands'][$cmd];
}
Also, just curious, but to what extent do you need to optimize? What is
acceptable? My homepage is showing about 0.194570 Seconds execution time
now if you look in the footer. Is this fast or slow for you?
Thanks!
-Shawn
[Edited on 8/31/2008 by Shawn] |
| |
anomaly
Newbie   Posts: 6 Registered: 7/29/2008 Status: Offline
|
posted on 8/31/2008 at 05:41 PM |
That's hard to say. The page rendering time module uses as its endpoint
the calling of the atthemeclose function -- atthemeexit runs after this and
therefore the final parsing pass isn't counted into the render time -- so
technically I've noticed no improvement in the printed render time .
Around .15 to .25 seconds seems correct for me for the "regular" phase
though, with caching properly enabled.
Tom
[Edited on 31/8/2008 by anomaly] |
| |
Shawn
Administrator   Posts: 4575 Registered: 10/7/2002 Status: Online
|
posted on 8/31/2008 at 05:45 PM |
Well, turn on the postnuke render time (I think it's in footer.php,
uncomment a line). See what the difference is. Probably not much.
I'm not discounting your speed concerns, just trying to see if it is slow
or like many others you are trying to eek every nano second out of the
code.
-Shawn |
| |
anomaly
Newbie   Posts: 6 Registered: 7/29/2008 Status: Offline
|
posted on 8/31/2008 at 06:12 PM |
I couldn't figure out how to activate PN's render time evaluator, so I went
ahead and hardcoded another "end" function into atExtended.php right after
ob_end_clean();
You can see the results for the regular rendertime computation, followed by
mine that include the time for the last pass.
For the regular atExtended.php:
For my homepage:
Page created in 0.186643 Seconds
Rendered in 0.844961881638
For my main forums page:
Page created in 0.241903 Seconds
Rendered in 1.14929103851
For my modified atExtended.php:
For my homepage:
Page created in 0.187094 Seconds
Rendered in 0.20383310318
For my main forums page:
Page created in 0.228110 Seconds
Rendered in 0.250830888748
Of course, all figures are with page data already cached.
Personally, I think that's a fairly substantial difference.
Edit: after further testing, the first modification in atAPI.php yields no
noticeable speed increase, the important one is just the one in
atExtended.php
[Edited on 31/8/2008 by anomaly] |
| |
anomaly
Newbie   Posts: 6 Registered: 7/29/2008 Status: Offline
|
posted on 9/1/2008 at 10:48 PM |
what kind of a difference do you see on your site if you add another rendre
time calculation at the end of atThemeExit? |
| |
Shawn
Administrator   Posts: 4575 Registered: 10/7/2002 Status: Online
|
posted on 9/1/2008 at 11:05 PM |
Depends, I ran it many, many times on multiple pages. About .1 seconds
average.
-Shawn
|
| |
|
|
|
|