Greg Heo

Benchmarking PHP

Featuring PEAR's Benchmark module.

I recently needed some quick code timing information so I wrapped some function calls with $current = time() and then subtracted the results. Then I tried it with microtime() instead. Then I decided to browse PEAR for some kind of benchmarking tool.

Here are some notes on what PEAR’s Benchmark has to offer.

Iterate

Benchmark_Iterate is the classic “run something n number of times” kind of benchmark. It returns the time each execution took as well as the mean.

require_once 'Benchmark/Iterate.php';

function doSomething($arg)
{  
    return $arg += 100;
}

$benchmark = new Benchmark_Iterate;
$benchmark->run(100000, 'doSomething', 100);
$results = $benchmark->get();

Timer

Benchmark_Timer allows you to set markers at various points in your code. It keeps track of the time elapsed between markers as my original time() and microtime() example did.

require_once 'Benchmark/Timer.php';

$timer = new Benchmark_Timer();

$timer->setMarker('start work');
for ($i=0; $i < 100000; $i++) {
  $a = sprintf("%.2f", $i);
}
$timer->setMarker('end word');

$results = $timer->getProfiling();
$timer->display();

The display() method will print out a table with your results. Or, you can access the raw results with getProfiling().

Profiler

Benchmark_Profiler is similar to Benchmark_Timer except it’s meant to be enclosed in function and methods. You can also nest various things.

require_once 'Benchmark/Profiler.php';
$profiler = new Benchmark_Profiler();

$profiler->start();
doSomething();
doSomethingElse();

$profiler->stop();
$profiler->output();

Not as simple as that though; doSomething() and doSomethingElse() look like this:

function doSomething() {
    global $profiler;

    $profiler->enterSection('doSomething');
    // do lots of work
    $profiler->leaveSection('doSomething');
}

function doSomethingElse() {
    global $profiler;

    $profiler->enterSection('doSomethingElse');
    doSomething();
    // do even more work
    $profiler->leaveSection('doSomethingElse');
}

Note the nested call in doSomethingElse(). Benchmark_Profiler will handle this correctly and show the profile results as expected.

As with Benchmark_Timer, the output() method will print out a table with your results. You can get at the data for a particular section by passing the section name to getSectionInformations() or data for all sections with getAllSectionsInformations().

That’s it

Remember, profile before optimizing.