Ravens PHP Scripts: Forums
 

 

View next topic
View previous topic
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Ravens PHP Scripts And Web Hosting Forum Index -> Making Nuke Efficient
Author Message
fkelly
Former Moderator in Good Standing



Joined: Aug 30, 2005
Posts: 3312
Location: near Albany NY

PostPosted: Tue Nov 21, 2006 10:07 am Reply with quote

We all know about those mysterious white screens of death! Behind the scenes there is a field mismatch between what's in a MYSQL table and what's in a PHP SQL statement. Or something else, it could be many things, wrong with the SQL. Someone upgrades a table without changing the PHP. Someone changes the PHP and forgets to update the table. It happens all the time. And despite what you set error reporting to, at least as far as I can see, the SQL error sits behind the scenes and you are left to guess work.

Now, I don't know what the right approach to future versions of Nuke are in a production environment but for testing here's a hack I've come up with that seems to work. Obviously you don't want to have to go thru every SQL statement or query in Nuke to modify it to test "if(!$result) { echo ... the error} ". Especially since we use !$result and $result2 etc. willy nilly throughout Nuke. There is just no global search and replace that will accomplish this and if you did insert error checking throughout and wanted to turn it off you'd be back to going thru all the code. Oh, okay you could put a switch into config but that's added complexity too.

So, this morning I forced myself to take a look at mysql.php that's in the db directory. Now ... disclaimer ... don't do this to anything but a test system. But if you find the function sql_query in there and go down to where it tests for not result you can modify the block of code to say:

Code:
      if($this->query_result)

      {
         unset($this->row[$this->query_result]);
         unset($this->rowset[$this->query_result]);
         return $this->query_result;
      }
      else
      {
            echo 'sql failed . <br />';
            echo 'query was ' . $query . '<br />';
            echo mysql_errno() . '<br />';
            echo mysql_error() . '<br />';
            die();
         // return ( $transaction == END_TRANSACTION ) ? true : false;
      }


The four lines of echoes and the die are what I added and I commented out the transaction part (which I doubt is really used, probably we should just be returned false).

I tested this by creating an error by changing the field name of main_module in the _main table to main_modulexx with PHPmyadmin.

This is just an incipient idea at this stage. I don't even know if it's a good idea to "trap" errors like this in a production system or if we do whether we want to display them and "die" or go to a log file or what. But for testing it seems like it would work and I'm off to see if I can find any real mysql errors in RN 2.10.

Comments welcome.
 
View user's profile Send private message Visit poster's website
Gremmie
Former Moderator in Good Standing



Joined: Apr 06, 2006
Posts: 2415
Location: Iowa, USA

PostPosted: Tue Nov 21, 2006 10:32 am Reply with quote

Good idea. This is why it is a good idea to use classes or functions to wrap common operations. If you had naked SQL calls everywhere you'd go crazy trying to track down problems.

You could even add a method on the database class to enable logging, and then conditionally execute your logging code inside sql_query() based on that. So right after the global $db variable is created (new'ed up), you could add a line of code like:

$db->enableLogging($enableDbLogging);

where $enableDbLogging is a new global variable that is set in config.php.
 
View user's profile Send private message
Gremmie







PostPosted: Tue Nov 21, 2006 10:44 am Reply with quote

You probably wouldn't want to do this logging on a production system, as dumping out the query string would expose the database structure for people wanting to do SQL injection attacks. But then again, this is open source software. But they would see your $prefix though.
 
technocrat
Life Cycles Becoming CPU Cycles



Joined: Jul 07, 2005
Posts: 511

PostPosted: Tue Nov 21, 2006 10:48 am Reply with quote

Take a look at what we did in Evo. It writes the error to the log, also what file and line it was generated from.

We have had it since v1 and it has proven invaluable.

_________________
Only registered users can see links on this board! Get registered or login!
Only registered users can see links on this board! Get registered or login! / Only registered users can see links on this board! Get registered or login! 
View user's profile Send private message
fkelly







PostPosted: Tue Nov 21, 2006 3:47 pm Reply with quote

Okay, I will Technocrat. Thanks for the lead. Heck, I just discovered a bug today in a recent change to RN2.10 that I'm helping to test. It would be easy enough, I'm pretty sure to just put in a check for is_admin and not echo the warning or do the die() but instead return false and thus "bypass" the error. But I'm only running this on test systems so I don't really care.

And Gremmie, well it would be a lot more work to put in checks for "if(!result) { echo the error strings } in all the SQL calls in Nuke if you were making native calls but once it was done it would be done. As with what I responded to Technocrat, you could enclose those with admin tests and/or set a flag in config.php or rnconfig.php and only run that section of code if the flag was raised. It's another thread but I'm not sure that whole db abstraction layer is worth keeping. If you watch Nuke execute it just hammers mysql.php over and over again, hundreds of times during the simple loading of a home page and any overhead that could be eliminated from that would be paying dividends over and over.

And as for exposing the db structure well anybody can download the tables and the programs (but I know you mentioned it being open source). It's subject to debate but I'm wondering if it wouldn't be better to have a user report an error with "here's what it says on the screen" where they give you the actual SQL and error numbers and text than just have them complaining about a white screen of death. My approach is certainly open to refinement and improvement but it was just done for testing purposes at this point.
 
Guardian2003
Site Admin



Joined: Aug 28, 2003
Posts: 6799
Location: Ha Noi, Viet Nam

PostPosted: Tue Nov 21, 2006 3:58 pm Reply with quote

See also Dragonfly CMS they have used this type of approcah since the beginning (wrapped in an admin check) and it also echo's variables and POST vars.

I never got around to looking at the code too much but I'd guess they would be using a class.
 
View user's profile Send private message Send e-mail
Gremmie







PostPosted: Tue Nov 21, 2006 4:28 pm Reply with quote

fkelly wrote:
And Gremmie, well it would be a lot more work to put in checks for "if(!result) { echo the error strings } in all the SQL calls in Nuke if you were making native calls but once it was done it would be done.


Well, no, because future maintenance not to mention new modules, blocks, etc, would have to do that same thing over and over and over again. I'm not saying keep the current db abstraction layer, but I would wrap all db access in a class so you can easily instrument code, add new features, tweak the implementation, etc all in one place rather than have 1000's of naked sql calls to maintain.

There is such a thing as premature optimization. We could write everything in assembly language cause its faster. But you have to weigh productivity benefits, maintenance costs, portability concerns, and many other things against speed. Sure, the db layer probably does get called a lot, but has anyone measured how much it costs vs naked sql calls? And then you have to decide if the portability and maintence benefits it brings is worth the extra cost, or if speed is more important. This depends very much on your application and what is important to you.

In the real-time embedded systems world that I live in, we try find the hot spots in our code, and optimize those. The rule of thumb is that 90% of your CPU time is spent in only 10% of your code. I would suspect that most of the time spent in a PHP-MySQL application is spent inside the MySQL database engine (especially for complicated queries). But again I'm speculating. Need to profile to know for sure. A few extra PHP function calls should not hurt things too much, and in most cases will make your application easier to maintain, debug, port, and more flexible.
 
fkelly







PostPosted: Tue Nov 21, 2006 4:37 pm Reply with quote

LOL Gremmie, I'm sure you know this but this is a debate folks have had since they were programming vacuum tubes and someone said "let's write an assembler". I don't have a particularly strong preference, it's just that the current abstraction layer really doesn't work so I started questioning whether we even needed it. But heck when I wanted to echo out the errors I plugged right into it rather than modifying thousands of lines of code in hundreds of different php programs and that sort of proves your point.

By the way I am working on profiling Nuke ... and it was profiling that pointed out that mysql.php was a "hot spot" as well as some oddities like setlocale().
 
Gremmie







PostPosted: Tue Nov 21, 2006 5:14 pm Reply with quote

LOL..yes, an eternal debate...I eat this stuff up so don't confuse my enthusiasm for any criticisms...I tend to get passionate about this kind of stuff....LOL.

It does sound like the current database abstraction layer doesn't really abstract the database, since some of the target backends don't seem to work (or so some people say), and the fact that a lot of the actual queries are MySQL specific anyway. And now your profiling shows it is hot. Maybe we could write a somewhat faster class for MySQL. I would still argue for a class though. It allows you to insert instrumentation or make changes in one spot vs hundreds or thousands. I guess a good test for it would be to benchmark it against naked mysql calls.

I just know that in my own work, we spent the time to write a C++ OS abstraction layer (threads, semaphores, mutexes, etc). And we have target backends for various operating systems (POSIX, Win32, VxWorks, etc). This has proved immensely powerful and allowed us to run on all kinds of platforms with zero changes to our application code. It turns out that most of the time spent is inside the actual OS call, so the thin OS wrapper layer did not hurt our performance that much compared to sprinkling naked OS calls everywhere in our code. The portability aspect was much more valuable to us than the small performance hit (that in fact we didn't even notice).

The current DB layer though is a slightly different animal and would require different thinking. I just hate duplicating code and prefer it all in one place, except when performance reasons say to do otherwise.

Are there hosts out there that refuse to let people run Nuke for performance reasons? And if so, you find another host, right? Wink I know my own site is just a hobbyist site with only a few hundred users. At most 28 have been on at one time (so far). Of course that doesn't mean we should be sloppy, and we should be efficient when possible, so Nuke will scale to larger sites with lots of users.

Okay, I'm rambling. Good discussion. Smile
 
fkelly







PostPosted: Tue Nov 21, 2006 6:38 pm Reply with quote

It is good stuff to get passionate about. I'll try to drag out some performance test I ran and post the code here but for tonight I'll just say that the "native call" ran about 25% faster than the one thru the layer in many cases but in one case out of 4 (or so) the native call would run about 400% faster. I don't know PHP internals at all but I'm guessing maybe in those 400% cases the object had to be loaded from memory. That will require further testing.

I also spent about 3 hours one Saturday morning converting a Ravennuke site over from the database abstraction calls to native calls. Mostly it was just global search and replaces and if I had known more about making the connection thru native means I probably could have done it in a hour. This was just for testing purposes and I haven't followed thru to get performance figures. But the process is easily replicated.

We could talk about abstraction generally and as a general matter I'd agree with you abstractly (LOL) that it's better but just spend some time with mysql.php and looking at what happens there (as well as in db.php) and then consider that there are few if any Nuke sites that run anything but MYSQL and also very few instances of anyone doing anything creative with the abstraction layer and see what you think.
 
montego
Site Admin



Joined: Aug 29, 2004
Posts: 9457
Location: Arizona

PostPosted: Tue Nov 21, 2006 6:59 pm Reply with quote

Yeah, I am wondering if it wouldn't be a good idea to see exactly where within the $db object where the delays you are seeing are coming from. Is it in the instantiation? Connection? Passing of variables? Etc.? I haven't looked at it in a very long time, but wonder if it couldn't be improved with just a little tweaking.

For example, I have never understood why the connection handle had to be passed back-and-forth all over the place within nuke. Why couldn't this be stored in the class itself? I wonder if some things could also be passed by reference (but too be quite honest, I have not looked at whether this is allowed in classes - might be).

For example, I changed one thing within the GoogleTap "stuff" for TegoNuke(tm) ShortLinks to pass by reference and wow, what a difference, especially when talking about eliminating copying of large amounts of data in a variable.

_________________
Only registered users can see links on this board! Get registered or login!
Only registered users can see links on this board! Get registered or login! 
View user's profile Send private message Visit poster's website
fkelly







PostPosted: Tue Nov 21, 2006 8:19 pm Reply with quote

I will look into this Montego, those are great questions that I don't know the answer to. Anyone else, please feel free to join in. There are a couple of unsets done in that class and I don't know if they are really needed. Nor do I think the whole "transaction" thing is but I'd need to read the MYSQL manual to see why that's in there.

Just like we recently found with $_SESSION variables, if you use array variables performance is horrible but with regular (non array) ones performance is close to "normal" variables. The devil is in the details and you can't take anything for granted.
 
montego







PostPosted: Tue Nov 21, 2006 8:40 pm Reply with quote

Ah, but techocrat also showed us where arrays were much faster than defines. Like you said, the "devil is in the details" and really in how these constructs are used.
 
Gremmie







PostPosted: Tue Nov 21, 2006 8:49 pm Reply with quote

montego wrote:

For example, I have never understood why the connection handle had to be passed back-and-forth all over the place within nuke. Why couldn't this be stored in the class itself?


Not sure what you mean? In the (mysql version of the) sql_db class there is a db_connect_id member variable that is used internally when making mysql calls.

Yes it would be interesting to profile the sql_db class member functions and see if there are hot spots. Those unsets do look weird. But besides those, it is a pretty thin wrapper.
 
fkelly







PostPosted: Tue Nov 21, 2006 8:50 pm Reply with quote

Not $_session variables that are arrays. For some strange reason that gets to the internals of PHP, these are extremely inefficient. And not comparable to regular array variables at all.
 
montego







PostPosted: Tue Nov 21, 2006 9:16 pm Reply with quote

Gremmie, never mind. I was only looking at sql_layer.php. I'm tired. Bona Petite...
 
Gremmie







PostPosted: Tue Nov 21, 2006 9:45 pm Reply with quote

fkelly, how are you profiling? Are there PHP profiling tools available?

Its probably no surprise that mysql.php gets called a lot, after all Nuke is pretty database intensive. But how does the time spent in the functions compare to other stuff going on? Does your profile show you how much time is spent in the PHP mysql_* functions too?

Fascinating stuff!
 
fkelly







PostPosted: Wed Nov 22, 2006 10:33 am Reply with quote

Here is some code I was using and had posted in internal forums to measure performance. I was looking at storing the config values that are read from mainfile in session variables and making them available that way throughout a users session. This is kind of on hold till RN 2.10 is out because I want to have a "finished" mainfile to base my experiments off of but you could tailor the code to test pretty much anything.

Code:
<?PHP

session_start();
include ('config.php');
define('INCLUDE_PATH', './');
require_once(INCLUDE_PATH.'db/db.php');
// test of 100 queries
st();
for ($i=0; $i<100; $i++) {
$result = $db->sql_query('SELECT * FROM nuke_config');
$row = $db->sql_fetchrow($result);
// $sitename = $row['sitename'];
// echo 'sitename: ' . $sitename . '<br />';
 }
echo 'test of 100 sql calls <br />';
et();

// test of 100 loads from a session variable
st();
for ($i=0; $i<100; $i++) {
$_SESSION['avariable'] = 'abc'; }
echo 'test of 100 loads into a session variable <br />';
et();

// test of 100 loads from a session variable into a plain variable
st();
for ($i=0; $i<100; $i++) {
$abc = $_SESSION['avariable'];
// echo $abc . '<br />';
}
echo 'echo test of 100 loads of a session variable into a plain variable <br />';
et();

// now lets simulate the mainfile load of config values to variables 100 times
st();
for ($i=0; $i<100; $i++) {
$result = $db->sql_query('SELECT * FROM '.$prefix.'_config');
$row = $db->sql_fetchrow($result);
$sitename = $row['sitename'];
$nukeurl = $row['nukeurl'];
$site_logo = $row['site_logo'];
$slogan = $row['slogan'];
$startdate = $row['startdate'];
$adminmail = stripslashes($row['adminmail']);
$anonpost = $row['anonpost'];
$Default_Theme = $row['Default_Theme'];
$foot1 = $row['foot1'];
$foot2 = $row['foot2'];
$foot3 = $row['foot3'];
$commentlimit = intval($row['commentlimit']);
$anonymous = $row['anonymous'];
$minpass = intval($row['minpass']);
$pollcomm = intval($row['pollcomm']);
$articlecomm = intval($row['articlecomm']);
$broadcast_msg = intval($row['broadcast_msg']);
$my_headlines = intval($row['my_headlines']);
$top = intval($row['top']);
$storyhome = intval($row['storyhome']);
$user_news = intval($row['user_news']);
$oldnum = intval($row['oldnum']);
$ultramode = intval($row['ultramode']);
$banners = intval($row['banners']);
$backend_title = $row['backend_title'];
$backend_language = $row['backend_language'];
$language = $row['language'];
$locale = $row['locale'];
$multilingual = intval($row['multilingual']);
$useflags = intval($row['useflags']);
$notify = intval($row['notify']);
$notify_email = $row['notify_email'];
$notify_subject = $row['notify_subject'];
$notify_message = $row['notify_message'];
$notify_from = $row['notify_from'];
$moderate = intval($row['moderate']);
$admingraphic = intval($row['admingraphic']);
$httpref = intval($row['httpref']);
$httprefmax = intval($row['httprefmax']);
$CensorMode = intval($row['CensorMode']);
$CensorReplace = $row['CensorReplace'];
$copyright = $row['copyright'];
// $Version_Num = floatval($row['Version_Num']);
$Version_Num = htmlentities(strip_tags($row['Version_Num']));
$domain = str_replace('http://', '', $nukeurl);
}
echo 'echo test of 100 sql calls and loading to plain variables <br />';
et();

// load config values once to session array

// force this for testing purposes
unset($_SESSION['config']);
st();
// session_start();
if (!isset($_SESSION['config'])) {
$result = $db->sql_query('SELECT * FROM '.$prefix.'_config');
$row = $db->sql_fetchrow($result);
echo 'below is time for a single sql call reading config table <br />';
et();

st();
$_SESSION['sitename'] = $row['sitename'];
$_SESSION['nukeurl'] = $row['nukeurl'];
$_SESSION['site_logo'] = $row['site_logo'];
$_SESSION['slogan'] = $row['slogan'];
$_SESSION['startdate'] = $row['startdate'];
$_SESSION['adminmail'] = stripslashes($row['adminmail']);
$_SESSION['anonpost'] =$row['anonpost'];
$_SESSION['Default_Theme'] = $row['Default_Theme'];
$_SESSION['foot1'] = $row['foot1'];
$_SESSION['foot2'] = $row['foot2'];
$_SESSION['foot3'] = $row['foot3'];
$_SESSION['commentlimit'] = intval($row['commentlimit']);
$_SESSION['anonymous'] = $row['anonymous'];
$_SESSION['minpass'] = intval($row['minpass']);
$_SESSION['pollcomm'] = intval($row['pollcomm']);
$_SESSION['articlecomm'] = intval($row['articlecomm']);
$_SESSION['broadcast_msg'] = intval($row['broadcast_msg']);
$_SESSION['my_headlines'] = intval($row['my_headlines']);
$_SESSION['top'] = intval($row['top']);
$_SESSION['storyhome'] = intval($row['storyhome']);
$_SESSION['user_news'] = intval($row['user_news']);
$_SESSION['oldnum'] = intval($row['oldnum']);
$_SESSION['ultramode'] = intval($row['ultramode']);
$_SESSION['banners'] = intval($row['banners']);
$_SESSION['backend_title'] = $row['backend_title'];
$_SESSION['backend_language'] = $row['backend_language'];
$_SESSION['language'] = $row['language'];
$_SESSION['locale'] = $row['locale'];
$_SESSION['multilingual'] = intval($row['multilingual']);
$_SESSION['useflags'] = intval($row['useflags']);
$_SESSION['notify'] = intval($row['notify']);
$_SESSION['notify_email'] = $row['notify_email'];
$_SESSION['notify_subject'] = $row['notify_subject'];
$_SESSION['notify_message'] = $row['notify_message'];
$_SESSION['notify_from'] = $row['notify_from'];
$_SESSION['moderate'] = intval($row['moderate']);
$_SESSION['admingraphic'] = intval($row['admingraphic']);
$_SESSION['httpref'] = intval($row['httpref']);
$_SESSION['httprefmax'] = intval($row['httprefmax']);
$_SESSION['CensorMode'] = intval($row['CensorMode']);
$_SESSION['CensorReplace'] = $row['CensorReplace'];
$_SESSION['copyright'] = $row['copyright'];
$_SESSION['Version_Num'] = htmlentities(strip_tags($row['Version_Num']));
$_SESSION['domain'] = str_replace('http://', '', $row['nukeurl']);
echo 'echo test of loading config table once to individual session variables (NOT) array <br />';
et();


st();
$_SESSION['config'] = array (
"sitename" => $row['sitename'],
"nukeurl" => $row['nukeurl'],
"site_logo" => $row['site_logo'],
"slogan" => $row['slogan'],
"startdate" => $row['startdate'],
"adminmail" => stripslashes($row['adminmail']),
"anonpost" =>$row['anonpost'],
"Default_Theme" => $row['Default_Theme'],
"foot1" => $row['foot1'],
"foot2" => $row['foot2'],
"foot3" => $row['foot3'],
"commentlimit" => intval($row['commentlimit']),
"anonymous" => $row['anonymous'],
"minpass" => intval($row['minpass']),
"pollcomm" => intval($row['pollcomm']),
"articlecomm" => intval($row['articlecomm']),
"broadcast_msg" => intval($row['broadcast_msg']),
"my_headlines" => intval($row['my_headlines']),
"top" => intval($row['top']),
"storyhome" => intval($row['storyhome']),
"user_news" => intval($row['user_news']),
"oldnum" => intval($row['oldnum']),
"ultramode" => intval($row['ultramode']),
"banners" => intval($row['banners']),
"backend_title" => $row['backend_title'],
"backend_language" => $row['backend_language'],
"language" => $row['language'],
"locale" => $row['locale'],
"multilingual" => intval($row['multilingual']),
"useflags" => intval($row['useflags']),
"notify" => intval($row['notify']),
"notify_email" => $row['notify_email'],
"notify_subject" => $row['notify_subject'],
"notify_message" => $row['notify_message'],
"notify_from" => $row['notify_from'],
"moderate" => intval($row['moderate']),
"admingraphic" => intval($row['admingraphic']),
"httpref" => intval($row['httpref']),
"httprefmax" => intval($row['httprefmax']),
"CensorMode" => intval($row['CensorMode']),
"CensorReplace" => $row['CensorReplace'],
"copyright" => $row['copyright'],
"Version_Num" => htmlentities(strip_tags($row['Version_Num'])),
"domain" => str_replace('http://', '', $row['nukeurl']));

echo 'echo test of loading config table once to session array <br />';
et();
 }
 
// take out of session array and put into plain variables
st();
foreach ($_SESSION['config'] as $key => $value) {
      $a = $key;
      kaching!a = $value;
   }
echo 'test of loading from session array into plain variables <br />';
et();   

echo 'just curious .. comparison test of various sql functions <br />';
st();
for ($i=0; $i<100; $i++) {
$result = $db->sql_query('SELECT * FROM nuke_config');
 }
echo 'test of 100 sql selects using db->sql_query<br />';
et();

st();

for ($i=0; $i<100; $i++) {
$result = mysql_query('SELECT * FROM nuke_config');
 }
echo 'test of 100 sql selects using "native" mysql_query<br />';
et();

st();
for ($i=0; $i<100; $i++) {
$row = $db->sql_fetchrow($result);
 }
echo 'test of 100 fetchrows<br />';
et();


// now lets simulate the mainfile load of config values to variables 100 times
    



function et() {
   global $start_time;
$mtime = microtime();
   $mtime = explode(' ',$mtime);
   $mtime = $mtime[1] + $mtime[0];
   $end_time = $mtime;
   $total_time = ($end_time - $start_time);
   $total_time = 'PAGE GENERATION ' . substr($total_time,0,6). ' SECONDS <br /><br />';
   echo $total_time;
}   
function st() {
   global $start_time;   
$mtime = microtime();
$mtime = explode(' ',$mtime);
$mtime = $mtime[1] + $mtime[0];
$start_time = $mtime;
return $start_time;
}

?>


And here are some sample results that I also posted:

Quote:
test of 100 sql calls
PAGE GENERATION 0.0299 SECONDS

test of 100 loads into a session variable
PAGE GENERATION 0.0001 SECONDS

echo test of 100 loads of a session variable into a plain variable
PAGE GENERATION 0.0001 SECONDS

echo test of 100 sql calls and loading to plain variables
PAGE GENERATION 0.0342 SECONDS

below is time for a single sql call reading config table
PAGE GENERATION 0.0003 SECONDS

echo test of loading config table once to individual session variables (NOT) array
PAGE GENERATION 0.0001 SECONDS

echo test of loading config table once to session array
PAGE GENERATION 8.7976 SECONDS

test of loading from session array into plain variables
PAGE GENERATION 0.0001 SECONDS

just curious .. comparison test of various sql functions
test of 100 sql selects using db->sql_query
PAGE GENERATION 0.0224 SECONDS

test of 100 sql selects using "native" mysql_query
PAGE GENERATION 0.0191 SECONDS

test of 100 fetchrows
PAGE GENERATION 0.0007 SECONDS


I am also using the editor that's available at Nusphere.com to profile performance but I've just gotten into that. It shows incredible detail (and promise) and the only real problem I have with it is that it's difficult to derive summaries sometimes. However, I could use it to do what Montego suggested which is look at individual lines in mysql.php and how they contribute to the picture. It's just a matter of having the time to do it.
 
fkelly







PostPosted: Wed Nov 22, 2006 3:55 pm Reply with quote

I tool a little time this afternoon to use my profiling tool specifically to look at performance within mysql.php. I'm doing this on a home windows system with Apache and using PHPed from Nusphere. I'm running against a test Ravennuke 2.10 system although the results should be relatively consistent for any recent PHPnuke based system.

First one thing to note: the footer in Nuke systems reports page generation time. However the start time is collected halfway down mainfile.php after a number of database accesses have been made. Therefore, the page generation time I was originally getting wasn't correlating with the profile times I was getting, it was much lower, so I moved the collection point up to the top of mainfile. The code is:

Code:
$mtime = microtime();

$mtime = explode(' ',$mtime);
$mtime = $mtime[1] + $mtime[0];
$start_time = $mtime;


This makes sense to me (moving it does) but I realize I may not be taking something into account in terms of why it was placed where it was.

At any rate the page generation time I get is: .96 seconds. There are 113 queries executed to generate the home page.

From the profiling tool what I see is:

mysql.php 722 ms (milliseconds)
mainfile.php 74 ms
theme.php 31 ms
index.php 23 ms
footer.php 23 ms
nukesentinel 20 ms
block_modules.php 14 ms
block_oldarticles 10 ms

and on.

Looking within mysql.php the biggie is: $this->query_result = @mysql_query($query, $this->db_connect_id);

this gets hit 113 times and takes 690 of the 722 ms. The other statement that consumes a lot of resources (relatively) is: $this->db_connect_id = @mysql_connect($this->server, $this->user, $this->password);

this only gets hit once but uses 14 ms.

Oh after typing all the above I realized I had the setlocale function commented out in mainfile so I ran it again with that in.

In mainfile the three statements taking the greatest resources are the include of nukesentinel, the include of "include_once('blocks/'.$blockfile);" which gets hit 4 times and the setlocale function which gets hit 10 times. The total times for these three statments are 18.57, 8.89 and 8.74 ms respectively.

What are we to conclude from all this? Well the most obvious way to optimize Nuke is to reduce queries. In RN 2.10 we've already eliminated some, especially in the block-modules.php area. There is still work to do with the is_user and is_admin functions since the static variables don't do what they are supposed to do in those functions (prevent the SQL from being repeatedly executed). I have a sessions based proposal to make for storing config variables once 2.10 is out ... that should reduce the repeated reading of the config table each time thru mainfile but we have address security and portability (does every server support sessions?) issues.

That's all for one Wednesday in November. Happy Thanksgiving everyone.
 
Display posts from previous:       
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Ravens PHP Scripts And Web Hosting Forum Index -> Making Nuke Efficient

View next topic
View previous topic
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2007 phpBB Group
All times are GMT - 6 Hours
 
Forums ©