Home > Articles

  • Print
  • + Share This

Performing Benchmarks

Problem

You want to perform a benchmark on a snippet of code to see how fast it runs.

Solution

Use the microtime() function to find the time in seconds and microseconds before and after your snippet is run:

<?php

function get_microtime()
{
  $mtime = microtime();
  $mtime = explode(" ",$mtime);
  $mtime = doubleval($mtime[1]) + doubleval($mtime[0]);
  return ($mtime);
}

$time1 = get_microtime();

for ($i=0; $i<99999; $i++) {
  $ar[ ] = $i;
}

$time2 = get_microtime();

$diff = abs ($time2-$time1);

print "<br> For Loop: $diff seconds.\n";

$i = 0;
unset ($ar);
$time1 = get_microtime();
while ($i<99999) {
  $ar[ ] = $i;
  $i++;
}
$time2 = get_microtime();

$diff = abs ($time2-$time1);
print "<br>While Loop: $diff seconds.\n";
?>

Discussion

This code reports the time difference between using a while loop and using a for loop (the while loop is the faster of the two). The solution (not the code for testing whether a while loop was faster than a for loop) could have been slimmed down to the following:

<?php
$time1 = get_microtime() 
//... do the things that you want to time here
$time2 = get_microtime() ;

$diff = abs ($time2 - $time1);
?>

We use the get_microtime() function (you can't use microtime() directly because it returns seconds and microseconds in a string, separated by a space) to return the number of seconds since the UNIX epoch began. (This is known as epoch seconds, and is equal to the number of seconds since January 1, 1970.) We assign this value to the first time, execute the code that we want to benchmark, and then calculate the microtime again. We take the absolute value of the difference between the two times by using the abs() function and assigning that value to $diff.

If you are timing two different code segments in one script, you should use the unset() function between the different timings (see the solution for an example of this). That way you don't have any extra memory set aside for those variables when you run the second portion of your script.

If you find yourself benchmarking your code execution often, you can make use of this handy function contributed by someone on the PHP mailing list (formatted slightly):

<?php
/*============================================================*  Function:  debug_timing
  Purpose:  Utility function for timing the script
  Input:   $label - text label marking point in execution
        if 'init' - initializes a new run
        if 'print' - dumps timing information
\*============================================================*/
function debug_timing ($label) {
  static $basetime,
      $totaltime,
      $rpttimes;

  if ($label == 'init') {
    $rpttimes = array();
    $basetime = microtime();
    $totaltime = 0;
    ereg ("^([^ ]+) (.+)", $basetime, $r);
    $basetime = doubleval ($r[2]) + doubleval ($r[1]);

    return;
  }

  if ($label == 'print') {
    // send to screen
    echo "<B>Timing results:</B><BR>\n";
    for ($i=0; $i < count ($rpttimes); $i++) {
      echo " $rpttimes[$i]\n";
    }
    echo "total: $totaltime\n";

    return;
  }

  // record current elapsed time, accumulate
  $newtime = microtime();
  ereg ("^([^ ]+) (.+)", $newtime, $r);
  $newtime = doubleval ($r[2]) + doubleval ($r[1]);

  $diff = $newtime - $basetime;
  $rpttimes[ ] = sprintf ("%-20s %s", $label, $diff);
  $basetime = $newtime;
  $totaltime += $diff;
}

?>

You use it like this:

<?php

debug_timing('init');
for ($i=1000; $i>0; $iā€”) {
  $ar[ ] = $i;
}
debug_timing('array_populated');
sort($ar);
debug_timing('array_sorted');
debug_timing('print');

?>

The output of this script will be something like this:

array_populated   0.047430038452148
array_sorted      0.019858956336975
total:      0.067288994789124

debug_timing() helps you measure intervals between execution points in your code.

As this book was being released two new classes came out at Pear. They were authored by Sebastian Bergmann of phpOpenTracker.de and called Benchmark_Timer and Benchmark_Iterate. The Benchmark_Timer class offers similar functionality to that described above. You can instantiate a new Benchmark_Timer class and then start and stop timing as well as setting timer flags.

<?php
require_once("Benchmark/Timer.php");

$timer = new Benchmark_Timer;

// Start the timer
$timer->start();

$timer->set_marker("Begin For Loop");
for ($i = 0; $i < 10000; $i++) {
   print "$i\n";
}
$timer->set_marker("End For Loop");

$timer->set_marker("Begin While Loop");
$i = 0;
while ($i < 10000) {
  print "$i\n";
  $i++;
}
$timer->set_marker("End While Loop");

$profiling = $timer->get_profiling();

for ($i = 0; $i < count($profiling); $i++) {
  print "Marker Name: {$profiling[$i][name]}\n";
  print "Time Index: {$profiling[$i][time]}\n";
  print "Difference: {$profiling[$i][diff]}\n";
  print "Total: {$profiling[$i][total]}\n";
}
?>

The Benchmark_Iterate class inherits from the Benchmark_Timer class and allows you to time a singular function over a period of $x iterations.

<?php
require_once("Benchmark/Iterate.php");

function print_hello() {
  print "Hello World!!";
}

$bench = new Benchmark_Iterate;
$bench->run("print_hello", 200);

$result = $bench->get();

print "Iteration 6 took $result[6], whereas iteration ";
print "20 took $result[20]\n";

print "The mean execution time was $result[mean] over a";
print " total of $result[iterations] iterations...";
?>
  • + Share This
  • 🔖 Save To Your Account

Related Resources

There are currently no related titles. Please check back later.