Есть фрагмент программы, и необходимо провести его исследование, чтобы определить время выполнения каждого оператора.
Для этого предназначен модуль PEAR Benchmark:
require 'Benchmark/Timer.php';
$timer =& new Benchmark_Timer(true);
$timer -> start();
// некоторый установочный код
$timer -> setMarker('setup');
// еще часть исполняемого кода
$timer -> setMarker('middle');
// еще одна часть исполняемого кода
$timer -> setmarker('done');
// и наконец последняя часть исполняемого кода
$timer -> stop();
$timer -> display();
Вызов функции etMarker() записывает время. Метод display() выводит на печать список маркеров, время их установки и время, прошедшее с момента установки предыдущего маркера:
маркер | время установки | прошедшее время | проценты |
---|---|---|---|
Start | 1029433375.42507400 | - | 0.00% |
setup | 1029433375.42554800 | 0.00047397613525391 | 29.77% |
middle | 1029433375.42568700 | 0.00013899803161621 | 8.73% |
done | 1029433375.42582000 | 0.00013303756713867 | 8.36% |
Stop | 1029433375.42666600 | 0.00084602832794189 | 53.14% |
total | - | 0.0015920400619507 | 100.00% |
Модуль Benchmark также включает класс Benchmark_Iterate, позволяющий определить время многократного выполнения одной функции:
require 'Benchmark/Iterate.php';
$timer =& new Benchmark_Iterate;
// простая функция определения времени выполнения
function use_preg($ar) {
for ($i = 0, $j = count($ar); $i < $j; $i++) {
if (preg_match('/gouda/',$ar[$i])) {
// it's gouda
}
}
}
// еще одна простая функция определения времени выполнения
function use_equals($ar) {
for ($i = 0, $j = count($ar); $i < $j; $i++) {
if ('gouda' == $ar[$i]) {
// it's gouda
}
}
}
// запускаем функцию use_preg() 1000 раз
$timer -> run(1000,'use_preg',
array('gouda','swiss','gruyere','muenster','whiz'));
$results = $timer -> get();
print "Mean execution time for use_preg(): $results[mean]\n";
// запускаем функцию use_equals() 1000 раз
$timer -> run(1000,'use_equals',
array('gouda','swiss','gruyere','muenster','whiz'));
$results = $timer -> get();
print "Mean execution time for use_equals(): $results[mean]\n";
Метод Benchmark_Iterate::get() возвращает ассоциативный массив.
Элемент mean этого массива содержит значение времени выполнения
каждой итерации функции. Элемент iterations содержит количество
итераций. Время выполнения каждой итерации хранится в элементе
массива с целочисленным ключом. Например, время первой итерации
находится в элементе $results[1], а время 37-й итерации находится
в элементе $results[37].
Для автоматической записи времени, прошедшего после выполнения
каждой строки программы, применяется конструкция declare с параметром ticks:
function profile($display = false) {
static $times;
switch ($display) {
case false:
// добавляем текущее время к списку записанных значений времени
$times[ ] = microtime();
break;
case true:
// возвращаем прошедшее время в микросекундах
$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_function('profile');
// определяем время старта
profile( );
// выполняем код, записывая время выполнения каждого оператора
declare (ticks = 1) {
foreach ($_SERVER['argv'] as $arg) {
print strlen($arg);
}
}
// печатаем прошедшее время
$i = 0;
foreach (profile(true) as $time) {
$i++;
print "Line $i: $time\n";
}
Параметр ticks позволяет многократно выполнять функцию для блока
кода. Число ticks показывает, сколько тактов должно пройти между
вызовами функции, зарегистрированной с помощью register_tick_function().
В предыдущем примере мы регистрируем единственную функцию и
выполняем функцию profile() для каждого оператора внутри блока
declare. Если в массиве $_SERVER['argv'] два элемента, то функция profile() выполняется четыре раза: одно выполнение при каждом проходе цикла foreach и один раз при каждом выполнении строки printstrlen($arg).
Можно также определить вызов двух функций на каждые три оператора:
register_tick_function('profile');
register_tick_function('backup');
declare (ticks = 3) {
// code...
}
Можно также передать дополнительные параметры в зарегистрированные функции, которые могут быть методами объекта вместо обычных функций:
// передаем "parameter" в функцию profile()
register_tick_function('profile', 'parameter');
// вызываем $car -> drive();
$car = new Vehicle;
register_tick_function(array($car, 'drive'));
Если необходимо выполнить метод объекта, передайте объект и имя
инкапсулированного внутри массива метода. Это даст возможность
функции register_tick_function() узнать, что вы ссылаетесь на объект,
а не на функцию.
Для удаления функции из списка тактовых функций надо вызвать
функцию unregister_tick_function():
unregister_tick_function('profile');
Информацию о классе PEAR Benchmark на
http://pear.php.net/package-info.php?package=Benchmark; документацию по функции register_tick_function() на http://www.php.net/register-tick-function, по
функции unregister_tick_function() на http://www.php.net/ unregister-tick-function и по конструции declare на http://www.php.net/declare.