Posts Tagged ‘PHP’

Optimizing your web server: Part 4b – XDebug Profiler

November 23rd, 2009

Here we are, part 4b. By using XDebug, a pecl extension, our php code can be analyzed pinpointing the slower functions.

Installing XDebug is easy:

pecl install xdebug

Now, you’ll have to enable it in the php.ini file:

extension=xdebug.so
xdebug.profiler_enable=1
xdebug.profiler_output_name=profiler-%s-%t.cache
xdebug.profiler_output_dir=/tmp/xdebug

Don’t forget to create the directory and give apache enough permissions to write in it.

So after restarting apache you’ll see new files showing up under ‘/tmp/xdebug/’.
These are, as the XDebug documentation says ‘cachegrind compatible files’.

As I’m using putty on windows to connect to my webserver and the webserver does not run a GUI, I’ll be using wincachegrind to display the information.

To make it easy for myself, I use winscp and make it so that the cachegrind files are opened with WinCacheGrind.
Setting this up goes beyond the scope of this post and greatly depends on your setup/way of working.

Anyway, up till now we managed to install XDebug, enabling the extension, generate the cachegrind files and now opening them with WinCacheGrind.

Upon opening such a file in wingrind, you’ll see something similar to this:

main(click to enlarge)

As this blog post was made while I was profiling one of my own sites, I’ll use a real world example.
In the right hand side, the {main} takes 89ms to process.

Let us expand this to see what function is taking the most time.
functions

When looking at the functons that take the most time. I noticed, as you can see in the screenshot above, the Component->startup and the beforeFilter both take 13ms.
The component is the cakephp cookie class, it seems the startup of this class takes 12ms. To be exact, it’s the decrypting of the cookie that takes 11ms.
The same is true for the beforeFilter, in that method I read the cookie, taking 12ms, because it decrypts again.

cookie

After seeing this, I changed the code so that on the first hit on the site the information in the cookie is is copied into the session, as this was super fast(less then 1ms). Saving me 2 times 12ms.

That comes down to 27% faster!

To put things even more in context. This was a base class, all my pages inherited from that class, so it saved me those 24ms on EACH request.

Imagine doing that to all pages, or one of those heavy visited pages on your own site.
Worth the 10 minutes it takes to install XDebug with WinCacheGrind, no?

Optimizing your web server: Part 1 – Gzip
Optimizing your web server: Part 2 – Keep Alives
Optimizing your web server: Part 3 – Opcode Caching
Optimizing your web server: Part 4a – PHP
Optimizing your web server: Part 4b – XDebug Profiler

Optimizing your web server: Part 4a – PHP

November 23rd, 2009

Let me start by saying, I won’t bore you with the list of what I call stupid optimizations.

That’s why I call this 4a, I recommend skipping 4a and go directly to 4b :)

When I first when on my quest to optimize my code, I was disappointed at what I found.
Let me give you a short list of ‘tips’ you find when searching for ‘php optimize code’.

Some have a little value, others are crap.
The results will state things like this:

  • echo vs print
  • pass objects by reference
  • remove comments from your code
  • use single quotes
  • error suppression with @
  • use assosiative arrays
  • use for loops with the count before the loop
  • unset your variables

Now, seriously, the echo vs print again??, yes, totally worthless. If I want to make my site faster, there are better ways then to replace print with echo, for the amazing 0.001 second.

The pass objects by reference, this one is true, but only IF you know what you’re doing. For base types even if you pass by reference it won’t make a difference. Only use it for objects and even then, you have to watch out, in many cases you’ll actually slow your script down by forcing a copy when it wouldn’t otherwise be made.

Removing comments from your code. Well, I had a good laugh with this one. If you’re going to do that, then you might want to install an opcode cacher, see my other blog posts about them. They don’t cache this, so instead, document your code!, as much as possible. More (good)comment makes it readable 5 to 10 years from now, not to mention causing less issues/bugs in the process.

Use single quotes. This is true, if you’re interested in that soooo little difference. Personally I made a habit of using the single quotes, but that’s just so that I don’t have to press the shift key to type them(Yea, I’m lazy).

Error suppression with @. It is slow, yes, but I never use the @. When writing your code, error handling is part of it. You should not suppress them, you should fix them!. And if errors do happen, then use a try/catch and handle the error, do NOT ignore errors.

Use assosiative arrays, I hear that using [5] is 7 times slower then ['me'], haven’t run any benchmarks, but might be a good idea to use this when having big arrays.

Use for loops with the count before the loop, when using for($i=0; $i< count(array); $i++) the count(array) is executed every time. It’s useful to put this outside of the for loop. But then again, you could count backwards, $i=count(array);0<=$i; $i–, or something similar.

The last one on the list, unset your variables, is only if you use var’s with allot of data in them, or when using big objects.
You won’t win anything if you unset ALL your variables, your script would be spending more time unsetting them then actually keeping them in memory.
This is more the case when doing large queries on a database for example. Unsetting a couple of MB of data might be a good idea :)
If my memory serves me right, php6 will implement garbage collection, making this unnecessary.

So, this post was about optimizing your php code right?, well, instead of doing all those ridicules things listed above, we’ll do it the right way. A profiler!, see where your code is slow, and try and make it faster on those places!.
Optimizing your code that way is WAY more efficient then doing all those small silly things.

Don’t get me wrong, if you like coding in those small optimizations, go ahead. I just find it stupid to go and change those things afterwards.

So on to part 4b :) , where I’ll be using XDebug to find the slow spots in the php code.

Optimizing your web server: Part 1 – Gzip
Optimizing your web server: Part 2 – Keep Alives
Optimizing your web server: Part 3 – Opcode Caching
Optimizing your web server: Part 4a – PHP
Optimizing your web server: Part 4b – XDebug Profiler

Single Instance PHP Script

November 12th, 2009

When using php scripts on the command line or in the cron, there are often times that you do not want to allow the same script to run more then once at a the same time.

So a single instance application in php.

Personally I use php scripts like this allot. My cron is filled with all kind of tasks that run from the cron.
From backups to just database cleanup scripts and many other.

But most of those scripts will cause problems when running it multiple times.

This small php class has helped me in allot of cases to prevent just that:

class Process {
    private $strPIDFile;
 
    function __construct($pProcessIdFile) {
        $this->strPIDFile = $pProcessIdFile;
        if(file_exists($this->strPIDFile)) {
            if(!is_writable($this->strPIDFile)) {
                throw new Exception('File Not Writable', 101);
            }
 
            $pid = trim(file_get_contents($this->strPIDFile));
            if(posix_kill($pid, 0)) {
                if($this->is_alive($pid)) {
                    //process is alive
                    throw new Exception('Process Already Running', 100);
                } else {
                    //cleanup
                    unlink($this->strPIDFile);
                }
            }
        } else {
            if(!is_writable(dirname($this->strPIDFile))) {
                throw new Exception('Directory Is Not Writeable', 102);
            }
        }
 
        $id = getmypid();
        file_put_contents($this->strPIDFile, $id);
 
    }
 
    public function __destruct() {
        if(file_exists($this->strPIDFile)) {
            unlink($this->strPIDFile);
        }
    }
 
    private function is_alive($pId){
        exec('ps '.$pId, $ProcessState);
        return(count($ProcessState) >= 2);
    }
}

An example on how to use it:

try {
    $Process = new Process('/tmp/myphpscript.pid');
} catch(Exception $ex) {
    switch($ex-&gt;getCode()) {
        case 100:
            echo 'Script already running...';
            return;
        case 101:
            echo 'File Not Writable';
            return;
        case 102:
            echo 'Folder Not Writable';
            return;
    }
}

Many people will say that working with exceptions this way isn’t good practice, it’s easy to modify to your own needs if needed.

Now lets break it in small pieces, well, not that many, the class contains a constructor and deconstructor, nothing more.

First the constructor, it takes the full path to the pid file as a parameter.
This pid file is something used by most applications running on your linux machine.
A couple of checks happen to see if the file and directory are writable, once verified that they are, the fun starts.

If the pid file exists, your php script is already running, that is ‘most of the time’ the case.
The file is left behind if your script crashes, so some extra work is required to make sure the process is still alive or not.
If the process can’t be found, then your php script crashed the last time it ran.

Second, the deconstructor. This does the cleanup when your script finishes. All this does is remove the pid file, meaning it will allow the script to be started again by another process.

That’s it!, nothing more to it.
Copy pasting the class and the small try/catch will make your php script a single instance

Changing the Session ID in CakePHP

October 20th, 2009

Ever wanted to set your own session id?

Well, I did. I was creating a webservice where authentication would be done with a ‘token’.

This token would simply be a random guid given to that user after he logged on with his username/password.
Now, this random guid/string would be the session ID.
That way, if the user does an action with that token, we can easily know who it is.

But enough with the ‘why I’ wanted to do it. You’re here for yourself right?, so you’ll be interested in some sample code.

In basic php you’d do it by giving the ID parameter to the session_id() method

//taken from php.net
string session_id  ([ string $id  ] )

But how can we do this in CakePHP?
One possibility would be by implementing sessions ourself. But then why use a framework that all those nice components?

The session component has the ability to set the session id. This must be done in the beforefilter method of your controller.
Doing it later would be to late, as the session would already be started.

So in your controller you’d have something like this:

public $components = array('Session');
    public function beforeFilter() {
        $sessionid = 'myownsessionid';
 
        if($sessionid != null && $sessionid != '') {
            $this->Session->id($sessionid);
        }
    }

There you go :) , it’s that easy!

CakePHP: Extending the AppController

October 19th, 2009

Ever wanted to split off functionality to a base class other then AppController?

This is what was needed to prevent typing the same code over and over again in a project of mine.

The app controller is great and all, but it’s just one class and you might want some functionality in only a part of your controllers.

So lets get to work, what do we have?

  • AppController(app/app_controller.php)
  • ExtendedAppController(app/extended_app_controller.php)
  • MyController(app/my_controller.php)

Extending the app controller isn’t much work, all you need to know really is to put “App::import(‘Controller’, ‘ExtendedApp);” above the MyController.

Lets put it in code:

//app controller
class AppController extends Controller {
}
 
//extended app controller
class ExtendedAppController extends AppController {
 
}
 
//MyController
App::import('Controller', 'ExtendedApp);
class MyController extends PipeMsgHandlerController {
 
}

You don’t necessarily need to extend from AppController. If you have functionality in your app controller that you do not want to share with the ExtenedAppController then another option is to extend Controller.

Although I don’t recommend it, it’s better to split off the functionality you don’t want in the ExtendedController in another controller that inherits from the app controller for those controllers.