PHP 10.0 Blog

What if…

More on PHP performance

Posted by Stas on July 13, 2009

After writing the post criticizing Google’s “performance advice” for PHP beginners, I started thinking – OK, I don’t like Google’s advice, what would I propose instead?

So here are my thoughts about what would be good for the beginner to consider when he starts with PHP performance optimizations. Note that I do not say it’s the only thing you should do – there are a bunch of articles, talks, blogs, etc. about PHP performance and many of them contain very good advice and go into much more details than I intend to go into. But I think the items below are ones that you should ensure you are doing to the full extent before you go to look around for performance tricks.

Also, from the start I want to say that I work for Zend Technologies and I participated in development of many Zend solutions, both free and commercial. I am going to mention both kinds in this article, where relevant. I am aware that there are alternative solutions, but I will mention the ones I know the best. So please do not take this as commercial advertisement or any claim on relative merits of other solutions – it is not the intent. The intent is to give general direction and some examples, if somebody prefers other solutions in the same direction – that’s fine.

Bytecode cache
If you care about performance and don’t use bytecode cache then you don’t really care about performance. Please get one and start using it. If you want ready-made commercially-supported solution with nice GUI, etc., look at Zend Server, if you’re more into compile-it-yourself command-line then you may want to look at APC, or other alternatives.

Profiling
Profile you code before you start optimizing it! Otherwise it would be like travelling around a foreign city with signs written in an unreadable language witout any map or GPS. You’ll probably get somewhere, but you wouldn’t have any idea where you are, where you should go and how far are you from the place you need to be. Profiling would allow you to know which parts of code are worth investing into and which aren’t. You can use Zend Studio/Debugger or Xdebug for that.

Caching
Most PHP installations run in “shared nothing” mode where as soon as the request processing ends, all the data associated with the request is gone. It has some advantages, but also one big disadvantage – you can not preserve results of repeated operations. That is, unless you use caching.
You should look into caching all operations which take considerable time and can return the same result for a prolonged period of time or same data set. That may include configurations, database queries, service requests, complex calculations, full pages or page fragments, etc., etc. Caching expensive operations is one of the most powerful performance improvements you can do.
There are numerous low-level caching solutions – memcached, APC, Zend Server (you can find a good guide to it on DevZone) and others. On top of it, you may look into Zend Framework’s caching infrastructure – which support the backends described above and more and makes caching much easier.

Optimize your data
Usually the most expensive places of the PHP application are where it accesses external data – namely, database or filesystem or network. Look hard into optimizing that – reduce number of queries, improve database structure, reduce filesystem accesses, try to bundle data to make one service call instead of several, etc. For more advanced in-depth look, use tools like strace (Unix) and Process Explorer (Windows) to look into system calls your script produces and think about ways to eliminate some of  them. You would not be able to eliminate all of them but each of them is a worthy target.

Don’t try to outsmart the engine
There are a lot of “tips” floating around about which constructs in PHP are faster or slower than others. I think you can safely ignore all of these tips, especially if you’re a beginner. Odd are, 9 cases out of 10 they won’t give you any improvement at all, and in the remaining one case it will be either not applicable in your code or not worth the time spent on it. Yes, there are ways to save couple of opcodes and remove couple of lookups here and there – but unless you’ve already done with all of the previous steps it is not worth it. And some of the advice out there will actually make you code slower, less robust and less secure without you even noticing. So I think for the beginners is better to stay away from trying to outsmart the engine altogether.

Benchmark in real life

Many of the advices I mentioned above have benchmarks as a proof. The problem is these benchmarks always test only a short piece of code. However, you would not be running that one-liner – you would be running the whole big application. This reminds me of a joke about a physicist that developed the model of a spherical horse in vacuum in order to use it to win bets on horse racing. If you want better chances to win than that physicist, test in real environment, not in vacuum. If you have an idea for some improvement, verify that this improvement actually improves your application, not just an artificial benchmark. If this is impossible, use profile results to estimate potential benefit – if you find a way to optimize function that summarily runs for 0.1% of overall execution time, you probably won’t do any good to the application as a whole.

Leverage the extensions
That seems too obvious, but I have seen a lot of code that duplicates functions available in some PHP extension. There are a lot of functions in PHP and if you do something that others may have done before, check in the manual. You have DOM/SimpleXML extensions for XML, JSON extension for JSON, SOAP extension for doing SOAP, etc., etc. Do not create custom serialization/deserialization if serialize()/deserialize() would work for you.
If you have some very performance-sensitive bit of script and you can do C programming (beginner in PHP doesn’t mean beginner in everything :), consider even making your own extension, it’s not that hard.

Avoid extra notices/errors/etc.
Even suppressed errors have cost in PHP, so try and write your code so it would not produce notices, strict notices, warnings, etc. You may want to enable logging of all errors to examine that. Never enable displaying errors in production though – it will only lead to a major public embarrassment.

Use php.ini-production as a start
If you need a set of php.ini settings which would not hurt your performance and not break anything, look into php.ini-production in PHP source. You may need to change a couple of details (e.g. include path) but it’s a good starting point.

Use big realpath cache
Realpath cache is very useful for the engine when it tries to find the unique full name of the file from just filename or relative path. By default, it’s 16K but if you have a lot of files with long pathes, it’s better to increase the size – it would save the expensive disk accesses.

There are probably more things that could be said, but this post is pretty long already, so I will end it here and you are welcome to add your opinion in comments.

About these ads

63 Responses to “More on PHP performance”

  1. Whisller said

    Nice article. In my opinion if your application are using database (mysql, postgresql what ever), in first step you should start from it. I saw some applications where database queries just killed them :-) Because someone didn’t know how to use ORM and so on.

  2. It all makes sense to me, nice list.

    Only if you get below 100-50ms of rendering time you can consider micro optimizations and other voodoo. I guess the problem is that people read presentations saying: ‘we reduced time by 50% changing from include_once to include …’. Although it might make difference to someone like facebook/flicker or other giant, you wont feel it unless your render time is sooooooo small there is nothing else left to improve.

    Nice article, bring us some more :- ))

    Art

  3. [...] PHP 10.0 Blog – PHP Performance [...]

  4. [...] this new post on the PHP 10.0 blog, Stas looks at performance in PHP applications as his own response to the [...]

  5. T. Crider said

    One simple optimization that most people miss is not using count($var) as a condition of for loops.


    // Wrong
    for ($i = 0; $i < count($Results); $i++)
    {
    // Do Something
    }

    // Correct
    $ResultCount = count($Results);
    for ($i = 0; $i < $ResultCount; $i++)
    {
    // Do Something
    }

    It’s very simple, and now you’re not counting the size of the stack every time you process the loop.

    • david said

      T. Crider this is one of the tips which are mentioned in the don’t try to outsmart the engine paragraph.

      And instead of adding a line you can set the ResultCount variable in the first segment of the for loop which makes the context of the variable clearer.

      for($i = 0, $j = count($Restults) ; $i < $j ; $i++)
      {
      // do something
      }

      • foo said

        Even better:

        for ($i=0; $j=count($Results); $i<$j; ++$i) {
            // do something
        }
        
      • Shane said

        @foo

        Ok, I’ll bite.. why is pre-incrementing better, exactly?

      • Bar said

        Again, 9+ times out of 10:

        foreach ($Results as $result) {
        // …
        }

      • Shocker said

        @ Shane:
        When using post-increment, the value of the variable is stored in a temporary location. With pre-increment the temporary variable isn’t needed.
        It’s not much, but with a couple of 100,000 cycles you see a little difference. ;)

  6. [...] this new post on the PHP 10.0 blog, Stas looks at performance in PHP applications as his own response to the [...]

  7. [...] Revisando los feeds de Bloglines encontre este post de PHP 10.0 Blog donde habla sobre la performance en PHP. [...]

  8. Ryan said

    I agree wholeheartedly on the whole benchmarking and profiling. I just wrote up an article last week or so on a few benchmarking tools we use and how we use them. It might help a few people take that first step into trying it out. just don;t spend all your time benchmarking and nor doing any coding :)

    http://blueprint.intereactive.net/benchmarking-our-php/

    Also really helpful was your take on leveraging extensions. I realize that I don’t know or use half the extensions out there that could help ease my coding.

    Great article!!!

  9. [...] More on PHP performance – PHP 10.0 Blog just some general php tips [via phpdeveloper.org ] [ programming, php ] 2084 Latest Updates from this link [...]

  10. [...] More on PHP performance After writing the post criticizing Google’s “performance advice” for PHP beginners, I started [...] [...]

  11. On PHP performance: use Zend Debugger…

    Stanislav Malyshev wrote some thoughts on PHP performance.

    He entitled one of it’s performance tips “Avoid extra notices/errors/etc.”.

    I would like to add here:
    Do not add in your application too much debugging capabilities.

    Most of you ar…

  12. On PHP performance……

    Stanislav Malyshev wrote some thoughts on PHP performance.

    He entitled one of it’s performance tips “Avoid extra notices/errors/etc.”.

    I would like to add here:
    Do not add in your application too much debugging capabilities.

    Most of you ar…

  13. Tom said

    Excellent post, thank you.

    We have dramatically increased our overall site performance by caching just a couple of expensive queries :-)

  14. [...] Interesting reads (PHP & more) and tools (Twitter & more) Gespeichert unter: Coding, Databases, Tools — Jonathan Gilbert @ 17:38 More on PHP Performance http://php100.wordpress.com/2009/07/13/php-performance/ [...]

  15. I really didn’t get on with XDebug as a profiler, it was so cumbersome to use thanks to having to send the results to a separate CacheGrind tool.

    Luckily I discovered XHProf, a recent open-source release from Facebook that provides a lightweight but extremely useful profiler, complete with a web-based interface for viewing the results:
    http://petewarden.typepad.com/searchbrowser/2009/07/speed-up-your-php-with-xhprof.html

  16. Jack said

    Caching is a must in any application. I currently use PEAR Cache Lite on my projects and it’s very fast and easy to integrate !
    Great post.

  17. [...] link: More on PHP performance « PHP 10.0 Blog Share and [...]

  18. Kevin said

    Great tips. Thanks!

  19. [...] 先だってのPHP高速化に関するポストの導入で、GoogleによるPHPのパフォーマンスTipsが物議をかもしている件を紹介しました。 先日、最初に疑問を投げかけたZendの技術者であるStanislav Malyshev氏が、自身のblog”PHP 10.0 Blog“上で、前述のGoogleのそれに対するアンチテーゼとして”More on PHP performance“という記事を書いています。つい小手先のシンタックスなどを期待してしまいがちな高速化Tipsですが、「初心者向けにまず」としながら、極めて本質的なパフォーマンスチューニング方法をまとめています。 とても良い記事だと思ったので、タイトルに沿ってまとめてみます。(翻訳ではないので注意して下さい) [...]

  20. Jamie Krasnoo said

    Some run servers in cgi mode with suphp so that scripts run in the name of the user. In that case which bytecode cache is the best to be used in a multi user environment?

    • Stas said

      I think cgi/suphp is currently not compatible with bytecode caches. It can be made to work, but AFAIKk right now it’s not supported by any of the major ones.

  21. Max-VII said

    –try and write your code so it would not produce notices–

    Does it mean that I should check if every $_POST or $_SERVER isset()? It creates a notice if it is not checked.

    It is not clear why I should do it. It seems to me it takes time to check if it set or not, while I am pretty sure that it is set even without this check.

    And I would mention one more item. While sanitizing an integer in PHP 4 it is enough to use casting $i=(int)$i;

    In PHP5 there are special sanitizing filters already, but on my production site it is still PHP4. So I use casting. I read somewhere that casting for integers is very fast and resources’ cheap.

    • Stas said

      I don’t know how you can be sure something in $_POST is set – you don’t control it, the client does. But if you _know_ it’s set (e.g., you checked it before) – then, of course, no point in checking twice :)
      Now, you can take all kinds of shortcuts, including not checking certain things and even risking producing some notices in some rare cases, and that may be ok. That’s your decision as an app developer. What I wanted to achieve here is for you to be aware that there’s a cost in it. If you’re OK with the cost and other consequences of not checking something – it’s fine.

      • Max-VII said

        Stas, thank you.

        For example, I want to make sure that a page is not shown via SSL (https://). I use this:

        if($_SERVER['HTTPS'] == ‘on’) {
        header(“Location: http://{$_SERVER["HTTP_HOST"]}{$s_root}”);
        }

        It creates a notice. But this does not create a notice:

        if(isset($_SERVER['HTTPS'])) {
        if($_SERVER['HTTPS'] == ‘on’) {
        header(“Location: http://{$_SERVER["HTTP_HOST"]}{$s_root}”);
        }
        }

        What is faster, to check if $_SERVER['HTTPS'] is set, or ignore this suppressed notice? I work on one server, and $_SERVER['HTTPS'] is sort of always set.

        Another situation: in the shopping cart are incoming variables $_POST['id'], $_POST['title'], $_POST['price'], $_POST['quantity'], $_POST['block_price'], $_POST['block_quantity'], $_POST['ifpackage'].

        I am checking now only if one is set, the $_POST['id']. If it is set I assume that others are set too. Then I do sanitation and use them.

        This creates suppressed notices. But if I check that all 7 $_POST incoming variables are set, then there is no notice. What is your opinion? Checking if 7 variables are set is cheaper than ignoring this notice? Or not.

        • Oleg said

          You can use small function for fetching data from $_POST.
          Something like:

          function post($field,$default=null){
          return isset($_POST[$field]) ? $_POST[$field] : $default;
          }

          1. it won’t generate any notices
          2. easier to write: just post(‘id’)
          3. easy to set default value.

      • Max-VII said

        Stas, I switched on in php.ini reporting of notices and rewrote my application so that notices are not generated.

        I removed several stupidities in my code at the same time, like: $link=mysql_connect(localhost,$username,$password)

        PHP thought that localhost a constant, an empty one, and actually substituted it with a string ‘localhost’.

        It was not that difficult to remake the code so that it does not produce any notice. Besides, I read somewhere yesterday that long code does not mean slow code, as it is compiled before execution. And the point is to write correct code.

        Thank you for pointing me in this direction.

        • William said

          A few years ago I worked on a large PHP based cms. After we spent a day fixing all the error notices, we noticed small but real improvement in performance.

          Will

  22. [...] More on PHP performance by Stas Malyshev [...]

  23. [...] Kortfattat handlar det hela om att Google under parollen “Let’s make the web faster” skrivit en del idiotiska tips på hur man bör skriva PHP-kod. En del bättre tips finns att läsa på PHP 10.0 bloggen. [...]

  24. [...] optimization advice from Google Zend about Google advises Tags: google, php, zend Comments (0) [...]

  25. [...] Hittade denna video via @nikke via PHP 10.0 Blog [...]

  26. Oleg said

    The biggest problem with improving performance is to find a spot where we have most time spent.

    Is there any software that can be installed on a production host and later can tell:
    which functions spent most time.

    Problem is that if you take only one request on dev. server, it will produce completely different results compared to what you get if you do 10 000+ requests on different modules of a server.

    Also it might be interesting to have availability to “replay” server load.
    For example: you record all user activities(on production) for a hour, then you use this data on development server to replay data after doing major performance changes.

  27. [...] More on PHP performance – PHP 10.0 Blog [...]

  28. Thanks for giving some hands on information for PHP performance optimizations.

  29. Phil said

    Cheers for the tips, never knew about realpath_cache_size or realpath_cache_ttl before :)

  30. matt said

    I am use zend frame work.When i surf that site some time site page is going to blank.But in view source i get all the code..

    Can any give reply

  31. Chris said

    Thanks for this post, really nice tips! I made the same experience by avoiding extra notices and errors. Performance was always much better than before.

  32. [...] den Beitrag von Stas Malyshev aufmerksam geworden. Bei seinem Beitrag mit dem schicken Titel “more on PHP performance” versucht er in einer Art Übersicht aufzuzeigen, worauf man achten kann bzw. sollte, [...]

  33. Bernd said

    It was interesting to read about the “smart tips” (I think you can safely ignore all of these tips).
    On the other hand – in these comments I found a better way to optimize the for loops.
    I have always done this in the simpel (and wrong / slow way).
    Therfore looking for hints and tips is not so bad. But in fact its right – most of the hints might not improve the performance.

  34. Klaus said

    Thanks for this usefull information, PHP performance optimizations is a very important topic in coding. Really nice tips.

  35. BTW. if you are squeezed by hardware limits you can consider cache optimizations like this early cache rebuild optimization

  36. Sarah said

    Great tips. Thanks!

  37. Marc said

    Performance is very important, thanks for your good ideas!

  38. uma kane said

    excellent post. u have really given very good tips to improve performance

  39. Collin said

    Really helpful tips. A good site performance is key nowadays!

  40. Cool guide.Good research work, thanks for sharing it.

  41. seoruchi said

    The bottlenecks are the Networks and not the CPU. If you monitor your CPU load, sending plain HTML pages over a network will not tax your CPU at all, the bottleneck will be the network.

  42. Marcel said

    Thanks for this usefull information, PHP performance optimizations is a very important topic in coding, especially for WP!

  43. learn said

    learn…

    [...]More on PHP performance « PHP 10.0 Blog[...]…

  44. [...] More on PHP performance,此人正好对 Google PHP 优化法则颇有微词,提出了自己的看法 [...]

  45. [...] More on PHP Performance – Stas Malyshev [...]

  46. Lars said

    I am use zend frame work.Thx for giving some hands on information for PHP performance optimizations.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

%d bloggers like this: