Меню

Php счетчик времени выполнения



Определяем время работы скрипта PHP

Доброго времени суток, коллеги! 🙂

Сегодня я решил затронуть такую тему, как время выполнения скрипта PHP и его определение.

Не скажу, что данная необходимость возникает каждый день, но время от времени на практике возникают ситуации, когда нужно получить время работы скрипта PHP.

Особенно часто за таким занятием можно застукать разработчиков, занимающихся рефакторингом кода и оптимизацией существующих алгоритмов, когда время выполнения PHP скрипта является ключевым фактором при выборе конечного варианта.

Ну, и ещё иногда данные цифры требуют менеджеры и заказчики, желающие выяснить, сколько времени потребуется на то или иное действие в коде.

Поэтому я и решил написать данную коротенькую заметку, в которой решил изложить порядок действий в аналогичной ситуации.

Сперва мы рассмотрим сам алгоритм определения времени исполнения PHP скрипта, а затем я приведу код, с помощью которого он будет реализовываться.

Время выполнения PHP скрипта — алгоритм определения

Порядок наших действий будет предельно прост:

  1. определяем текущее серверное время в PHP коде перед выполнением действий, прописанных в скрипте;
  2. после того, как скрипт выполнится, снова узнаём серверное время;
  3. вычисляем средствами PHP разницу времени между завершением выполнения скрипта и его запуском.

Полученное в итоге значение как раз и будет временем выполнения PHP скрипта, которое можно будет принимать во внимание при дальнейшей оптимизации и прочих действиях.

Время работы PHP скрипта — реализация алгоритма

Для вывода текущего времени в PHP коде я решил воспользоваться стандартной PHP функцией microtime(), которая возвращает текущую метку времени в Unix формате с микросекундами.

Зачем такая точность?

Затем, чтобы уловить малейшие изменения времени выполнения скриптов, т.к. иногда доли секунды могут быть фатальны и привести к большим потерям при использовании медленного кода в больших масштабах.

Ну, и плюс, учёт микросекунд при вычислениях влияет на точность калькуляций в положительную сторону.

Для демонстрации своих теоретических повествований я написал простенький скриптик, который вычисляет время прогона пустого цикла с 30 000 000 итераций (решил взять побольше для наглядности):

Как сказано в официальной документации PHP, по умолчанию microtime() возвращает строку в формате «msec sec», где sec — количество секунд с начала эпохи Unix (1 января 1970 0:00:00 GMT), а msec — это количество микросекунд, прошедших после sec.

Функция PHP microtime() имеет всего один параметр get_as_float, при указании которому значения true можно получить текущее время PHP в секундах, прошедших с начала эпохи Unix с точностью до микросекунд.

Поскольку мне нужно было именно текущее время, а не количество секунд с начала эпохи Unix, то я воспользовался данным параметром, что можно видеть в моём коде.

В итоге, с помощью функции echo(), на экран вывелось следующее сообщение: Скрипт был выполнен за 1.3156361579895 секунд.

Чтобы определить, что данная методика работает верно, я решил задать фиксированное время выполнения скрипта с помощью функции sleep(), которая делает задержку выполнения скрипта на указанное количество секунд.

В итоге, следующая конструкция вернула сообщение Скрипт был выполнен за 2.0000510215759 секунд:

Превышение указанной задержки на микроскопические доли секунд можно списать на время вызова кодовых конструкций и обработку результатов их выполнения серверным железом, поэтому на них вполне можно закрыть глаза.

Если они будут всё-таки раздражать вас или вашего заказчика, то можете воспользоваться хаком в виде банального округления до сотых или тысячных долей с помощью PHP функции round(), задействовав её следующим образом:

Результатом выполнения данного куска кода для вышеприведённого примера станет значение в кругленькие 2 секунды, что устроит самых искушённых перфекционистов 🙂

На этом сегодняшняя информация о том, как можно определить время выполнения скрипта PHP, подходит к концу.

Пишите свои отзывы в комментариях и задавайте интересующие вас вопросы в пабликах проекта в социальных сетях.

Всем удачи и до новых встреч! 🙂

P.S.: если вам нужен сайт либо необходимо внести правки на существующий, но для этого нет времени и желания, могу предложить свои услуги.

Более 5 лет опыта профессиональной разработки сайтов. Работа с PHP, OpenCart, WordPress, Laravel, Yii, MySQL, PostgreSQL, JavaScript, React, Angular и другими технологиями web-разработки.

Опыт разработки проектов различного уровня: лендинги, корпоративные сайты, Интернет-магазины, CRM, порталы. В том числе поддержка и разработка HighLoad проектов. Присылайте ваши заявки на email cccpblogcom@gmail.com.

И с друзьями не забудьте поделиться 😉

Источник

microtime

(PHP 4, PHP 5, PHP 7)

Читайте также:  Счетчик электрической энергии однофазный электронный класс точности 1

microtime — Возвращает текущую метку времени Unix с микросекундами

Описание

Функция microtime() возвращает текущую метку времени Unix с микросекундами. Эта функция доступна только на операционных системах, в которых есть системный вызов gettimeofday().

Для измерения производительности рекомендуется использовать hrtime() .

Список параметров

Если указано и установлено в true , microtime() возвратит число с плавающей точкой ( float ) вместо строки ( string ), как описано в разделе возвращаемых значений ниже.

Возвращаемые значения

По умолчанию microtime() возвращает строку ( string ) в формате «msec sec», где sec представляет собой количество секунд с начала эпохи Unix (1 января 1970 0:00:00 GMT), а msec — это количество микросекунд, прошедших после sec .

Если параметр getAsFloat установлен в true , то microtime() возвратит результат в вещественном виде ( float ), представляющий собой текущее время в секундах, прошедших с начала эпохи Unix с точностью до микросекунд.

Примеры

Пример #1 Замер времени выполнения скрипта с помощью функции microtime()

/**
* Простая функция для реализации поведения из PHP 5
*/
function microtime_float ()
<
list( $usec , $sec ) = explode ( » » , microtime ());
return ((float) $usec + (float) $sec );
>

// Спим некоторое время
usleep ( 100 );

$time_end = microtime_float ();
$time = $time_end — $time_start ;

echo «Ничего не делал $time секунд\n» ;
?>

Пример #2 Замер времени выполнения скрипта в PHP 5

// Спим некоторое время
usleep ( 100 );

$time_end = microtime ( true );
$time = $time_end — $time_start ;

echo «Ничего не делал $time секунд\n» ;
?>

Пример #3 Пример использования microtime() и REQUEST_TIME_FLOAT (начиная с PHP 5.4.0)

// Выбираем время сна случайным образом
usleep ( mt_rand ( 100 , 10000 ));

// Начиная с PHP 5.4.0 в суперглобальном массиве $_SERVER доступно значение REQUEST_TIME_FLOAT.
// Оно содержит временную метку начала запроса с точностью до микросекунд.
$time = microtime ( true ) — $_SERVER [ «REQUEST_TIME_FLOAT» ];

echo «Ничего не делал $time секунд\n» ;
?>

Смотрите также

  • time() — Возвращает текущую метку системного времени Unix
  • hrtime() — Получить системное время высокого разрешения

User Contributed Notes 18 notes

You can use one variable to check execution $time as follow:

= — microtime ( true );
$hash = 0 ;
for ( $i = 0 ; $i rand ( 1000 , 4000 ); ++ $i ) <
$hash ^= md5 ( substr ( str_shuffle ( «0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ» ), 0 , rand ( 1 , 10 )));
>
$time += microtime ( true );
echo «Hash: $hash iterations: $i time: » , sprintf ( ‘%f’ , $time ), PHP_EOL ;
?>

All these timing scripts rely on microtime which relies on gettimebyday(2)

This can be inaccurate on servers that run ntp to syncronise the servers
time.

For timing, you should really use clock_gettime(2) with the
CLOCK_MONOTONIC flag set.

This returns REAL WORLD time, not affected by intentional clock drift.

This may seem a bit picky, but I recently saw a server that’s clock was an
hour out, and they’d set it to ‘drift’ to the correct time (clock is speeded
up until it reaches the correct time)

Those sorts of things can make a real impact.

Any solutions, seeing as php doesn’t have a hook into clock_gettime?

Using microtime() to set ‘nonce’ value:

Need a mini benchmark ?
Use microtime with this (very smart) benchmark function :

mixed mini_bench_to(array timelist[, return_array=false])
return a mini bench result

-the timelist first key must be ‘start’
-default return a resume string, or array if return_array= true :
‘total_time’ (ms) in first row
details (purcent) in next row

example :
unset( $t ); // if previous used

//— zone to bench
$t [ ‘start’ ] = microtime ( true );
$tab_test =array( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 );
$fact = 1 ;
$t [ ‘init_values’ ] = microtime ( true );
foreach ( $tab_test as $key => $value )
<
$fact = $fact * $value ;
>
$t [ ‘loop_fact’ ] = microtime ( true );
echo «fact = » . $fact . «\n» ;
//— END zone to bench

echo «—- string result—-\n» ;
$str_result_bench = mini_bench_to ( $t );
echo $str_result_bench ; // string return
echo «—- tab result—-\n» ;
$tab_result_bench = mini_bench_to ( $t , true );
echo var_export ( $tab_result_bench , true );
?>
this example return:

—- string result—-
total time : 0.0141 ms
start -> init_values : 51.1 %
init_values -> loop_fact : 48.9 %
—- tab result—-
array (
‘total_time’ => 0.0141,
‘start -> init_values’ => 51.1,
‘init_values -> loop_fact’ => 48.9,
)

The function to include :

function mini_bench_to ( $arg_t , $arg_ra = false )
<
$tttime = round (( end ( $arg_t )- $arg_t [ ‘start’ ])* 1000 , 4 );
if ( $arg_ra ) $ar_aff [ ‘total_time’ ]= $tttime ;
else $aff = «total time : » . $tttime . «ms\n» ;
$prv_cle = ‘start’ ;
$prv_val = $arg_t [ ‘start’ ];

Читайте также:  Сломался счетчик газа штраф

foreach ( $arg_t as $cle => $val )
<
if( $cle != ‘start’ )
<
$prcnt_t = round ((( round (( $val — $prv_val )* 1000 , 4 )/ $tttime )* 100 ), 1 );
if ( $arg_ra ) $ar_aff [ $prv_cle . ‘ -> ‘ . $cle ]= $prcnt_t ;
$aff .= $prv_cle . ‘ -> ‘ . $cle . ‘ : ‘ . $prcnt_t . » %\n» ;
$prv_val = $val ;
$prv_cle = $cle ;
>
>
if ( $arg_ra ) return $ar_aff ;
return $aff ;
>
?>

But note that the default ‘precision’ setting of PHP* — which is used when a float is converted to a stringy format by echo()ing, casting or json_encode()ing etc — is not enough to hold the six digit accuracy of microtime(true).

Out of the box, microtime(true) will echo something like:

Which is obviously less than microsecond accuracy. You’ll probably want to bump the ‘precision’ setting up to 16 which will echo something like:

*Internally* it will be accurate to the six digits even with the default ‘precision’, but a lot of things (ie. NoSQL databases) are moving to all-text representations these days so it becomes a bit more important.

* 14 at the time of writing

While doing some experiments on using microtime()’s output for an entropy generator I found that its microsecond value was always quantified to the nearest hundreds (i.e. the number ends with 00), which affected the randomness of the entropy generator. This output pattern was consistent on three separate machines, running OpenBSD, Mac OS X and Windows.

The solution was to instead use gettimeofday()’s output, as its usec value followed no quantifiable pattern on any of the three test platforms.

I have been getting negative values substracting a later microtime(true) call from an earlier microtime(true) call on Windows with PHP 5.3.8

It is important to note that microtime(TRUE) does NOT always return a float (at least in PHP 5.x; I have not tested 7.x). If it happens to land on an exact second, it returns an integer instead.

Here is some simple code to illustrate this:
for ( $i = 0 ; $i 5000 ; $i ++) <
echo microtime ( TRUE ) . «\n» ;
usleep ( 100 ); // Adjust this if your PC is too fast/slow
>
?>

When you run this at a command line, you’ll see output like this (and you’ll know EXACTLY when I ran this):
1588881290.9992
1588881290.9994
1588881290.9996
1588881290.9998
1588881291 = DateTime :: createFromFormat ( ‘U.u’ , microtime ( TRUE )); // This line will not create an object when microtime returns an integer because it depends on the number being a float, including a decimal point!
$today = $raw_time -> format ( ‘Y-m-d H:i:s.u’ ); // This will die when format is attempted on a non-object
?>

The fix is to format the microtime output to force it to always be a float:
= sprintf ( ‘%.4f’ , microtime ( TRUE ));
$raw_time = DateTime :: createFromFormat ( ‘U.u’ , $utime );
$today = $raw_time -> format ( ‘Y-m-d H:i:s.u’ );
?>

Paraphrasing the characters on Silicon Valley, «Always Float! Always Float! Always Float!»

As previously pointed out, setting the parameter $get_as_float as true will not allow microseconds precision (what would mean 6 decimal digits). It happens because the float returned has a big integer section, what crops the decimal one leaving it with less than 6 digits.

Here is a solution to easily calculate the execution time of a script without having to alter any configuration parameter. It uses the former way of getting microseconds.

private $timeStart ;
private $microsecondsStart ;
private $timeStop ;
private $microsecondsStop ;

public function __construct () <
$this -> start ();
>

public function start (): void <
[ $this -> microsecondsStart , $this -> timeStart ] = explode ( ‘ ‘ , microtime ());
$timeStop = null ;
$microsecondsStop = null ;
>

public function stop (): void <
[ $this -> microsecondsStop , $this -> timeStop ] = explode ( ‘ ‘ , microtime ());
>

public function getTime (): float <
$timeEnd = $this -> timeStop ;
$microsecondsEnd = $this -> microsecondsStop ;
if (! $timeEnd ) <
[ $microsecondsEnd , $timeEnd ] = explode ( ‘ ‘ , microtime ());
>

$seconds = $timeEnd — $this -> timeStart ;
$microseconds = $microsecondsEnd — $this -> microsecondsStart ;

// now the integer section ($seconds) should be small enough
// to allow a float with 6 decimal digits
return round (( $seconds + $microseconds ), 6 );
>
>

$t = new Timer ();
usleep ( 250 );
echo $t -> getTime ();

I like to use bcmath for it
function micro_time () <
$temp = explode ( » » , microtime ());
return bcadd ( $temp [ 0 ], $temp [ 1 ], 6 );
>

Читайте также:  Счетчик печати мфу hp

$time_start = micro_time ();
sleep ( 1 );
$time_stop = micro_time ();

$time_overall = bcsub ( $time_stop , $time_start , 6 );
echo «Execution time — $time_overall Seconds» ;
?>

Get date time with milliseconds

$micro_date = microtime();
$date_array = explode(» «,$micro_date);
$date = date(«Y-m-d H:i:s»,$date_array[1]);
echo «Date: $date:» . $date_array[0];

Test accuracy by running it in a loop.

I use this for measure duration of script execution. This function should be defined (and of couse first call made) as soon as possible.

/**
* get execution time in seconds at current point of call in seconds
* @return float Execution time at this point of call
*/
function get_execution_time ()
<
static $microtime_start = null ;
if( $microtime_start === null )
<
$microtime_start = microtime ( true );
return 0.0 ;
>
return microtime ( true ) — $microtime_start ;
>
get_execution_time ();

?>

However it is true that result depends of gettimeofday() call. ([jamie at bishopston dot net] wrote this & I can confirm)
If system time change, result of this function can be unpredictable (much greater or less than zero).

Of the methods I’ve seen here, and thought up myself, to convert microtime() output into a numerical value, the microtime_float() one shown in the documentation proper(using explode,list,float,+) is the slowest in terms of runtime.

I implemented the various methods, ran each in a tight loop 1,000,000 times, and compared runtimes (and output). I did this 10 times to make sure there wasn’t a problem of other things putting a load spike on the server. I’ll admit I didn’t take into account martijn at vanderlee dot com’s comments on testing accuracy, but as I figured the looping code etc would be the same, and this was only meant as a relative comparison, it should not be necessary.

The above method took on average 5.7151877 seconds, while a method using substr and simply adding strings with . took on average 3.0144226 seconds. rsalazar at innox dot com dot mx’s method using preg_replace used on average 4.1819633 seconds. This shows that there are indeed differences, but for normal use noone is going to notice it.

Note that the substr method mentioned isn’t quite the one given anonymously below, but one I made based on it:
= microtime ();
$timeval = substr ( $time , 11 ). substr ( $time , 1 , 9 );
?>

Also worth noting is that the microtime_float() method gets faster, and no less accurate, if the (float) conversions are taken out and the variables are simply added together.

Any of the methods that used + or array_sum ended up rounding the result to 2 digits after the decimal point, while (most of) the ones using preg_replace or substr and . kept all the digits.

For accurate timing, since floating-point arithmetic would lose precision, I stored microtime results as-is and calculated time difference with this function:
function microtime_used ( $before , $after ) <
return ( substr ( $after , 11 )- substr ( $before , 11 ))
+( substr ( $after , 0 , 9 )- substr ( $before , 0 , 9 ));
>
?>

For further information, the script itself, etc, see http://edorfaus.xepher.net/div/convert-method-test.php

A convenient way to write the current time / microtime as formatted string in your timezone as expression?

= ‘DateTime now is: ‘ . (new \ DateTime ( null ,(new \ DateTimeZone ( ‘Europe/Berlin’ ))))-> format ( ‘Y-m-d H:i:s’ );

$microDate = ‘Microtime now is: ‘ . date_create_from_format ( ‘U.u’ , number_format ( microtime ( true ), 6 , ‘.’ , » ))-> setTimezone ((new \ DateTimeZone ( ‘Europe/Berlin’ )))-> format ( ‘ymd H:i:s.u e’ );
?>

For the microtime expression only the procedural style can be used. If you do not use namespaces the backslashes may be removed.
PHP >= 5.4 needed due to accessing a member of a newly created object in a single expression «(new DateTime())->format(‘Y-m-d H:i:s.u’)»

DateTime now is: 2018-06-01 14:54:58 Europe/Berlin
Microtime now is: 180601 14:54:58.781716 Europe/Berlin

//Function to convert microtime return to human readable units
//функция для конвертации времени, принимает значения в секундах

function convert_time($time)
<
if($time == 0 ) <
return 0;
>
//допустимые единицы измерения
$unit=array(-4=>’ps’, -3=>’ns’,-2=>’mcs’,-1=>’ms’,0=>’s’);
//логарифм времени в сек по основанию 1000
//берем значение не больше 0, т.к. секунды у нас последняя изменяемая по тысяче величина, дальше по 60
$i=min(0,floor(log($time,1000)));

//тут делим наше время на число соответствующее единицам измерения т.е. на миллион для секунд,
//на тысячу для миллисекунд
$t = @round($time/pow(1000,$i) , 1);
return $t.$unit[$i];
>

Источник

Adblock
detector