Posts Tagged ‘performance’

Using APC to store your data

August 31st, 2010

Sometimes you have large amount of generated data that you don’t want to create on every web request.


An examples would be a home page with several news posts on it.
The text would be in a database, but all the ‘extra’ things you did like bbtags present in the text, information about the user that posted it, etc etc requires extra processing.


If these queries and calculation only have to be done once then it would mean a big performance gain. Especially if it’s on pages that get requested allot.


The solution for this is shared memory. APC has this, if you do not know what APC is, please read this blog post about opcode cachers.

So, we have data and we want to store it in memory, what we need is a small wrapper class that does all the work for us, explanation is in the code:

<?php
/**
 * Contains the APCCache class to store, retrieve and delete data from the APC shared memory
 * @package    Tools
 * @author     Crazy <crazytje@gmail.com>
 * @copyright  2000-2010 Crazy
 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @filesource
 * @link       http://www.php.net/manual/en/book.apc.php
 */
/**
 * used to store, retrieve and delete data from the APC shared memory
 *
 * @package    Tools
 * @author     Crazy <crazytje@gmail.com>
 * @copyright  2000-2010 Crazy
 * @license    http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link       http://www.php.net/manual/en/book.apc.php
 */
class APCCache {
    /**
     * Contains the prefix that will be prepended to the identifiers
     * @var string
     */
    private static $prefix = 'MyPrefix';
 
    /** 
     * Stores a variable in the shared memory
     * 
     * @param string $pKey Unique identifier for the data
     * @param mixed $pValue Data to store
     *
     */
    public static function SetVar($pKey, $pValue) {
        return apc_store(self::$prefix.'.'.$pKey, $pValue);
    }
 
    /**
     * Returns a stored variable from the shared memory
     *
     * @param string Data identifier
     * 
     * @return mixed stored data
     *
     */
    public static function GetVar($pKey) {
        return apc_fetch(self::$prefix.'.'.$pKey);
    }
 
 
    /**
     * Removed data from the shared memory
     *
     * @param string Data identifier
     *
     */
    public static function Destroy($pKey) {
        return apc_delete(self::$prefix.'.'.$pKey);
    }
 
    /**
     * Sets a prefix for your identifiers
     * This is to prevent conflicts with software also using apc
     *
     * @param string $pValue prefix 
     */
    public static SetPrefix($pValue) {
        self::$prefix = $pValue;
    }
}
?>

Example usage:

<?php
 
APCCache::SetVar('MyTest', 'wOOt');
$var = APCCache::GetVar('MyTest');
 
 
//outputs 'MyTest'
echo $var;
?>

Easy right?

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

Optimizing your web server: Part 2 – Keep Alives

November 22nd, 2009
Once your site begins to grow, it will most likely contain dozens of images, css and js files, and many other requests. Keep alives allows those requests to happen over the same tcp/ip connection. So what is keep alive exactly? As mentioned before, keep alive is an option in the apache config, this was added to the http protocol to solve a huge performance problem. In the original http protocol a new tcp connection needed to be set up for each request(image, css, html file). Due to the nature of the tcp protocol it takes a while to set up a connection(3 packets are always send, SYN/SYN-ACK/ACK). If the latency to the server is 200ms, then it takes about 600ms before a connection is set up and data can be requested. By using keep alives, this can be minimized. So on almost all of the webservers it gives a performance boost, as sites nowadays exist out of allot of files. Enabling keep alives is pretty easy. Apache has 3 settings that involve keep alive:
  • KeepAlive
  • KeepAliveTimeout
  • MaxKeepAliveRequests
The first "KeepAlive" has has two settings, On or Off, obviously we're going to put in on 'On'. The second "KeepAliveTimeout", is the number of seconds a connection stays open for the client. Setting this greatly depends on your website. If it loads in less then a second, settings this on 2 or 3 seconds is enough. I've put this on 5(default is 30) in my configuration and the site in question loads under one second. The third "MaxKeepAliveRequests", are the maximum number of requests that can be made on an open connection. This can be put on '0' meaning unlimited, or if you really want to put a number, take a look at how many requests your site makes. 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