Skip to content

Instantly share code, notes, and snippets.

@mschultheiss83
Created September 5, 2013 14:23
Show Gist options
  • Save mschultheiss83/6450776 to your computer and use it in GitHub Desktop.
Save mschultheiss83/6450776 to your computer and use it in GitHub Desktop.
Calculate script execution time (PHP class)
<?php
/**
* http://codeaid.net/php/calculate-script-execution-time-(php-class)
* Created by tripuls.
* User: m.schultheiss
* Date: 05.09.13
* Time: 16:20
*/
class Timer
{
// command constants
/**
*
*/
const CMD_START = 'start';
/**
*
*/
const CMD_STOP = 'end';
// return format constants
/**
*
*/
const SECONDS = 0;
/**
*
*/
const MILLISECONDS = 1;
/**
*
*/
const MICROSECONDS = 2;
/**
* number of microseconds in a second
*
* @var
*/
const USECDIV = 1000000;
/**
* Stores current state of the timer
*
* @var boolean
*/
private $_running = false;
/**
* Contains the queue of times
*
* @var array
*/
private $_queue = array();
/**
* Start the timer
*
* @return void
*/
public function start ()
{
// push current time
$this->_pushTime( self::CMD_START );
}
/**
* Stop the timer
*
* @return void
*/
public function stop ()
{
// push current time
$this->_pushTime( self::CMD_STOP );
}
/**
* Reset contents of the queue
*
* @return void
*/
public function reset ()
{
// reset the queue
$this->_queue = array();
}
/**
* Add a time entry to the queue
*
* @param string $cmd Command to push
*
* @return void
*/
private function _pushTime ( $cmd )
{
// capture the time as early in the function as possible
$mt = microtime();
// set current running state depending on the command
if ( $cmd == self::CMD_START ) {
// check if the timer has already been started
if ( $this->_running === true ) {
trigger_error( 'Timer has already been started', E_USER_NOTICE );
return;
}
// set current state
$this->_running = true;
}
else if ( $cmd == self::CMD_STOP ) {
// check if the timer is already stopped
if ( $this->_running === false ) {
trigger_error( 'Timer has already been stopped/paused or has not yet been started', E_USER_NOTICE );
return;
}
// set current state
$this->_running = false;
}
else {
// fail execution of the script
trigger_error( 'Invalid command specified', E_USER_ERROR );
return;
}
// recapture the time as close to the end of the function as possible
if ( $cmd === self::CMD_START ) {
$mt = microtime();
}
// split the time into components
list( $usec, $sec ) = explode( ' ', $mt );
// typecast them to the required types
$sec = (int)$sec;
$usec = (float)$usec;
$usec = (int)( $usec * self::USECDIV );
// create the array
$time = array(
$cmd => array(
'sec' => $sec,
'usec' => $usec,
),
);
// add a time entry depending on the command
if ( $cmd == self::CMD_START ) {
array_push( $this->_queue, $time );
}
else if ( $cmd == self::CMD_STOP ) {
$count = count( $this->_queue );
$array =& $this->_queue[$count - 1];
$array = array_merge( $array, $time );
}
}
/**
* Get time of execution from all queue entries
*
* @param int $format Format of the returned data
*
* @return int|float
*/
public function get ( $format = self::SECONDS )
{
// stop timer if it is still running
if ( $this->_running === true ) {
trigger_error( 'Forcing timer to stop', E_USER_NOTICE );
$this->stop();
}
// reset all values
$sec = 0;
$usec = 0;
// loop through each time entry
foreach ( $this->_queue as $time ) {
// start and end times
$start = $time[self::CMD_START];
$end = $time[self::CMD_STOP];
// calculate difference between start and end seconds
$sec_diff = $end['sec'] - $start['sec'];
// if starting and finishing seconds are the same
if ( $sec_diff === 0 ) {
// only add the microseconds difference
$usec += ( $end['usec'] - $start['usec'] );
}
else {
// add the difference in seconds (compensate for microseconds)
$sec += $sec_diff - 1;
// add the difference time between start and end microseconds
$usec += ( self::USECDIV - $start['usec'] ) + $end['usec'];
}
}
if ( $usec > self::USECDIV ) {
// move the full second microseconds to the seconds' part
$sec += (int)floor( $usec / self::USECDIV );
// keep only the microseconds that are over the self::USECDIV
$usec = $usec % self::USECDIV;
}
switch ( $format ) {
case self::MICROSECONDS:
return ( $sec * self::USECDIV ) + $usec;
case self::MILLISECONDS:
return ( $sec * 1000 ) + (int)round( $usec / 1000, 0 );
case self::SECONDS:
default:
return (float)$sec + (float)( $usec / self::USECDIV );
}
}
/**
* Get the average time of execution from all queue entries
*
* @param int $format Format of the returned data
*
* @return float
*/
public static function getAverage ( $format = self::SECONDS )
{
$count = count( $this->_queue );
$sec = 0;
$usec = $this->get( self::MICROSECONDS );
if ( $usec > self::USECDIV ) {
// move the full second microseconds to the seconds' part
$sec += (int)floor( $usec / self::USECDIV );
// keep only the microseconds that are over the self::USECDIV
$usec = $usec % self::USECDIV;
}
switch ( $format ) {
case self::MICROSECONDS:
$value = ( $sec * self::USECDIV ) + $usec;
return round( $value / $count, 2 );
case self::MILLISECONDS:
$value = ( $sec * 1000 ) + (int)round( $usec / 1000, 0 );
return round( $value / $count, 2 );
case self::SECONDS:
default:
$value = (float)$sec + (float)( $usec / self::USECDIV );
return round( $value / $count, 2 );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment