PHP Performance Tuning
Timing Program Execution by Statement
Problem
You have a block of code and you want to profile it to see how long each statement takes to execute.
Solution
Use the declare construct and the ticks directive:
function profile($display = false) {
static $times;
switch ($display) {
case false:
// add the current time to the list of recorded times
$times[] = microtime();
break;
case true:
// return elapsed times in microseconds
$start = array_shift($times);
$start_mt = explode(' ', $start);
$start_total = doubleval($start_mt[0]) + $start_mt[1];
foreach ($times as $stop) {
$stop_mt = explode(' ', $stop);
$stop_total = doubleval($stop_mt[0]) + $stop_mt[1];
$elapsed[] = $stop_total - $start_total;
}
unset($times);
return $elapsed;
break;
}
}
// register tick handler
register_tick_function('profile');
// clock the start time
profile();
// execute code, recording time for every statement execution
declare (ticks = 1) {
foreach ($_SERVER['argv'] as $arg) {
print "$arg: " . strlen($arg) ."\n";
}
}
// print out elapsed times
print "---\n";
$i = 0;
foreach (profile(true) as $time) {
$i++;
print "Line $i: $time\n";
}
Discussion
The ticks directive allows you to execute a function on a repeatable basis for a block of code. The number assigned to ticks is how many statements go by before the functions that are registered using register_tick_function() are executed.
In the Solution, we register a single function and have the profile() function execute for every statement inside the declare block. If there are two elements in $_SERVER['argv'], profile() is executed six times: once when the clocks starts; twice for the two times through the foreach loop; another two when the print strlen($arg) line is executed; and finally, once when foreach returns false:
Line 1: 5.3882598876953E-5
Line 2: 5.6982040405273E-5
Line 3: 6.2942504882812E-5
Line 4: 6.5803527832031E-5
Line 5: 6.7949295043945E-5
Line 6: 6.9856643676758E-5
You can also set things up to call two functions every three statements:
register_tick_function('profile');
register_tick_function('backup');
declare (ticks = 3) {
// code...
}
You can also pass additional parameters into the registered functions, which can be object methods instead of regular functions:
// pass "parameter" into profile()
register_tick_function('profile', 'parameter');
// call $car->drive();
$car = new Vehicle;
register_tick_function(array($car, 'drive'));
If you want to execute an object method, pass the object and the name of the method encapsulated within an array. This lets the register_tick_function() know you’re referring to an object instead of a function.
Call unregister_tick_function() to remove a function from the list of tick functions:
unregister_tick_function('profile');
No comments:
Post a Comment