About the Author

Chris Shiflett

Chris Shiflett is an author and speaker who leads the web application security practice at OmniTI.


PHP Advent Calendar Day 14

Today's entry, provided by David Sklar, is entitled Timing and Profiling.

David Sklar

Name
David Sklar
Blog
sklar.com/blog/
Biography
David Sklar is a Software Architect at Ning, author of Learning PHP 5 (O'Reilly), PHP Cookbook (O'Reilly), and Essential PHP Tools (Apress), and a fan of half-sour pickles.
Location
New York, New York

You probably want your programs to run as fast as possible. This thrilling PHP Advent Calendar entry talks about ways to time and profile your code, so you can figure out what parts are slow and therefore deserving of your optimization efforts.

microtime() is a simple and direct way to track how long something takes, since it gives you a timestamp that includes milliseconds. (The actual precision varies based on the floating point representation on your system.) Just call microtime() before and after the code you want to time:

<?php
 
$start = microtime(TRUE);
preg_match('@^[a-z]+\.(php|html|js)$@', $filename);
$elapsed = microtime(TRUE) - $start;
printf("The regex match took %.06f seconds.\n", $elapsed);
 
?>

This produces something like:

The regex match took 0.000169 seconds.

Not bad, but only really useful when compared to something else. So, does the regular expression get faster or slower (or is there no change) if the subpattern is changed to non-capturing?

<?php
 
$start = microtime(TRUE);
preg_match('@^[a-z]+\.(php|html|js)$@', $filename);
$elapsed = microtime(TRUE) - $start;
printf("The regex match took %.06f seconds.\n", $elapsed);
 
$start = microtime(TRUE);
preg_match('@^[a-z]+\.(?:php|html|js)$@', $filename);
$elapsed = microtime(TRUE) - $start;
printf("The non-capturing regex match took %.06f seconds.\n", $elapsed);
 
?>

The result looks something like:

The regex match took 0.000170 seconds.
The non-capturing regex match took 0.000017 seconds.

One sample each doesn't provide much confidence, so better to run a loop of many iterations of each:

<?php
 
$iterations = 1000;
 
$elapsed = 0;
for ($i = 0; $i < $iterations; $i++) {
    $start = microtime(TRUE);
    preg_match('@^[a-z]+\.(php|html|js)$@', $filename);
    $elapsed += microtime(TRUE) - $start;
}
 
printf("capturing: %d iter in %.06f secs = %.06f iter/sec\n",
       $iterations, $elapsed, $iterations / $elapsed);
 
$elapsed = 0; 
for ($i = 0; $i < $iterations; $i++) {   
    $start = microtime(TRUE);
    preg_match('@^[a-z]+\.(?:php|html|js)$@', $filename);
    $elapsed += microtime(TRUE) - $start;
}
 
printf("non-capturing: %d iter in %.06f secs = %.06f iter/sec\n",
       $iterations, $elapsed, $iterations / $elapsed);
 
?>

This shows that the non-capturing version is faster, but not by that much:

capturing: 1000 iter in 0.003977 secs = 251472.150609 iter/sec
non-capturing: 1000 iter in 0.003459 secs = 289082.914053 iter/sec

You can enhance this in other ways, but the basic idea is to use microtime() to keep track of how long a bit of code takes to run, run that code a number of times, and keep track of the total elapsed time. This makes it easy to compare the speed of different solutions to a problem.

Critical to keep in mind when doing timing like this, however, is how much user-visible gain the your performance improvements will actually show. You don't want to make things intentionally slower with no benefit, but often a slower-running but easier-to-read solution is a better choice, especially when the performance difference may be minimal. If a regex match can be run 250,000 times a second or 290,000 times a second, choosing one regex over another isn't going to make much of a difference in practice.

A profiler such as Xdebug is very helpful for giving you the information you need to direct your performance enhancement efforts in the right direction. With Xdebug, you can identify what parts of your code run most frequently, or take up the biggest chunk of the processing time of a page. That way, you can work on speeding up what will actually make the biggest difference in total runtime.

Xdebug is a binary extension to PHP. You can download a library for Windows from xdebug.org. On other platforms, you can install it with the pecl tool. The full documentation on Xdebug's profiling capabilities is at xdebug.org/docs/profiler. Once you enable it in your PHP configuration, it observes PHP programs that execute, writing profiling data to individual text files (which can grow quite large). Then, you can load these files into a tool such as KCacheGrind or WinCacheGrind. These tools give you a pretty graphical view of the profiling data.

Profiling data is essential for effective performance optimization. It might seem bountiful to change a preg_match() call into some plain string manipulation functions, but if that code is executed infrequently, you won't see much speedup. Xdebug can show you which areas deserve your attention.

About This Post

PHP Advent Calendar Day 14 was posted on Fri, 14 Dec 2007 at 22:33:12 GMT.

1 Comments

1. Alexey Kupershtokh's GravatarAlexey Kupershtokh said:

Chris, David,

There's another tool in a row of KCacheGrind and WinCacheGrind:

CachegrindVisualizer

http://code.google.com/p/cachegrindvisualizer/

It would be great if you check it as well, and let know your opinion to it's author.

Mon, 17 Dec 2007 at 09:48:52 GMT Link


Post A Comment

Personal Details and Comment

Style Guide

Line breaks are converted to paragraphs. Also use:

  • <a href="" title="">text</a>1
  • <em>text</em>
  • <blockquote><p>text</p></blockquote>
  • <code>2  <?php  if ($foo) {      $foo = TRUE;  }  ?></code>
  1. Note: <code> can be used inline (e.g. in paragraphs) or in a block as shown. Include whitespace and newlines in blocks.

Please enter Chris (my first name) below. This is a primitive spam prevention technique, and I apologize for the inconvenience.

Preview and Submit

Upcoming Talks

php|tek

21 - 23 May 2008

At Sheraton Gateway Suites Chicago O'Hare, Chicago, Illinois.

DC PHP Conference

02 - 04 Jun 2008

At Cafritz Conference Center, Washington, District of Columbia.

O'Reilly Open Source Convention

21 - 25 Jul 2008

At Oregon Convention Center, Portland, Oregon.

ZendCon

15 - 18 Sep 2008

In Santa Clara, California.

PHP Appalachia

11 - 14 Oct 2008

At Big Bear Lodge, Gatlinburg, Tennessee.

New Comments

Joseph Crawford wrote:

404 not found :( What's with this OpenID thing, you know how long it took me to figure out I h...

Posted in Zend Framework Tutorial
Laurent Cottereau wrote:

I am very interested in the possibilities of this service. However, I am wondering about what is ...

Posted in OpenID with myVidoop
Zac wrote:

Awesome code! Thanks!

Posted in Convert Smart Quotes with PHP
Muttley wrote:

Thanks for this, Shiffers. I've been working on a similar thing, using a similar method, so it's ...

Posted in Allowing HTML and Preventing XSS
hossein wrote:

Hi! May you give me an example how to use mcrypt_encrypt() in order to save passwrod in databa...

Posted in OpenID with myVidoop

Browse Comments