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..."; ?>