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.

Spidean Forums

Board Index > Support (.87) > Substantial AT-Lite Speedup


 < Last Thread   Next Thread >New Topic  Post Reply
Author: Subject: Substantial AT-Lite Speedup

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.

 
Reply With Quote

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]

 
Reply With Quote

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]

 
Reply With Quote

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

 
Reply With Quote

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]

 
Reply With Quote

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?
 
Reply With Quote

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


 
Reply With Quote
New Topic    Post Reply


Main Menu

Get AutoTheme

Featured Item

Poll

How do you like the new look?

[ Results | Polls ]

Votes: 103
Comments: 0

Powered by the AutoTheme HTML Theme System
Page created in 0.129513 Seconds