Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save manticorp/5142959 to your computer and use it in GitHub Desktop.
Save manticorp/5142959 to your computer and use it in GitHub Desktop.
A simple timing class. It's fairly self explanatory. It allows you set 'checks' and then print a list of those checks.It also supports iterations, so if you want to benchmark code fairly you can use the iterator function to do so.Simply set up a normal for loop, wrap it with startIteration and stopIteration, call the setIteration method with the…
<!-- styles for the timer -->
<style>
body{margin:0;padding:0}.manticorp-timing-container{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif}.manticorp-timing-container table{border-collapse:collapse;border:3px solid #555}.manticorp-timing-container tr:first-child td,.manticorp-timing-container tr:first-child th{text-align:center;border-bottom:2px solid #555}
.manticorp-timing-container tr:first-child:hover td,.manticorp-timing-container tr:first-child:hover th{background:#efefef}.manticorp-timing-container tr:hover td,.manticorp-timing-container tr:hover th{background:#ddd}.manticorp-timing-container td,.manticorp-timing-container th{padding:.4em 1em;-webkit-transition:background .06s;transition:background .06s;border-left:1px solid #555}
.manticorp-timing-container th{text-align:right;background:#efefef}.manticorp-timing-container .manticorp-timing-time{font-family:'Courier New',Courier,'Lucida Sans Typewriter','Lucida Typewriter',monospace}
.manticorp-timing-container .manticorp-timing-title{font-family:Georgia,Times,'Times New Roman',serif;font-size:1.6em;display:block;margin:.3em 0;padding:.1em 0}.manticorp-timing-container.manticorp-timing-bottom-bar{font-size:13px;position:fixed;bottom:0;left:0;display:block;overflow-y:hidden;width:100%;max-height:1.6em;margin:0;padding:4px 3px 0;-webkit-transition:all .7s;transition:all .7s;color:#ddd;border-top:1px solid #c50;background:#222}
.manticorp-timing-container.manticorp-timing-bottom-bar:hover{overflow:scroll;max-height:640px}.manticorp-timing-container.manticorp-timing-bottom-bar table{clear:both;margin-top:1em;margin-bottom:2em;padding-top:1em}.manticorp-timing-container.manticorp-timing-bottom-bar .manticorp-timing-overall-stats div{display:block;float:left;padding-right:.5em}
.manticorp-timing-container.manticorp-timing-bottom-bar .manticorp-timing-overall-stats{font-size:1em;display:block;clear:both;overflow:hidden;width:100%;min-height:1px;margin-bottom:1.2em}.manticorp-timing-container.manticorp-timing-bottom-bar .manticorp-timing-title.manticorp-timing-title-summary{display:none}
.manticorp-timing-container.manticorp-timing-bottom-bar .manticorp-timing-title{font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:1em;font-weight:900;display:block;float:left;margin:-1px .5em 0 1em;margin:0;padding:0;padding:0 .5em 0 1em;color:#c50}
.manticorp-timing-container.manticorp-timing-bottom-bar tr:first-child td,.manticorp-timing-container tr:first-child th{text-align:center;border-bottom:2px solid #444}.manticorp-timing-container.manticorp-timing-bottom-bar tr:first-child:hover td,.manticorp-timing-container tr:first-child:hover th{background:#222}
.manticorp-timing-container.manticorp-timing-bottom-bar td,.manticorp-timing-container th{padding:.4em 1em;-webkit-transition:background .06s;transition:background .06s;border-left:1px solid #555}.manticorp-timing-container.manticorp-timing-bottom-bar tr:hover td,.manticorp-timing-container tr:hover th{background:#111}
.manticorp-timing-container.manticorp-timing-bottom-bar th{text-align:right;background:#333}
</style>
<?php
/**
* Timer
*/
class Timer {
/**
* accuracy
* @var datatype
*/
protected $accuracy = 10;
/**
* setAccuracy
* @param int $value
* @return Timer
*/
public function setAccuracy($value) {
$this->accuracy = $value;
return $this;
}
/**
* getAccuracy
* @return $this->accuracy
*/
public function getAccuracy() {
return $this->accuracy;
}
/**
* lineBreak
* @var string
*/
private static $lineBreak;
/**
* setLineBreak
* @param $value
* @return Timer
*/
public static function setLineBreak($value) {
$this->lineBreak = $value;
return $this;
}
/**
* getLineBreak
* @return string
*/
public static function getLineBreak() {
return $this->lineBreak;
}
/**
* outputStyle
* @var string
*/
protected static $outputStyle;
/**
* getOutputStyle
* @return string
*/
public static function getOutputStyle() {
return $this->outputStyle;
}
/**
* outputStyle
* @var string
*/
private $printAllIterations = false;
/**
* getPrintAllIterations
* @return boolean
*/
public static function getPrintAllIterations() {
return $this->printAllIterations;
}
/**
* setPrintAllIterations
* @param $value
* @return Timer
*/
public function setPrintAllIterations($value) {
$this->printAllIterations = $value;
return $this;
}
/**
* outputStyle
* @var string
*/
private $printSummary = true;
/**
* getPrintSummary
* @return boolean
*/
public static function getPrintSummary() {
return $this->printSummary;
}
/**
* setPrintSummary
* @param $value
* @return Timer
*/
public function setPrintSummary($value) {
$this->printSummary = $value;
return $this;
}
/**
* outputStyle
* @var string
*/
private $printTables = true;
/**
* getPrintTables
* @return boolean
*/
public static function getPrintTables() {
return $this->printTables;
}
/**
* setPrintTables
* @param $value
* @return Timer
*/
public function setPrintTables($value) {
$this->printTables = $value;
return $this;
}
/**
* iteration
* @var int
*/
private $iteration = 0;
/**
* setIteration
* @param $value
* @return Timer
*/
public function setIteration($value) {
$this->iteration = $value;
return $this;
}
/**
* getIteration
* @return int
*/
public function getIteration() {
return $this->iteration;
}
/**
* startTime
* @var int
*/
private $startTime;
/**
* setStartTime
* @param $value
* @return Timer
*/
public function setStartTime($value) {
$this->startTime = $value;
return $this;
}
/**
* getStartTime
* @return int
*/
public function getStartTime() {
return $this->startTime;
}
/**
* stopTime
* @var int
*/
private $stopTime;
/**
* setStopTime
* @param $value
* @return Timer
*/
public function setStopTime($value) {
$this->stopTime = $value;
return $this;
}
/**
* getStopTime
* @return int
*/
public function getStopTime() {
return $this->stopTime;
}
/**
* checks
* @var array
*/
private $checks = array();
/**
* setChecks
* @param array $value
* @return Timer
*/
public function setChecks(array $value) {
$this->checks = $value;
return $this;
}
/**
* getChecks
* @return array
*/
public function getChecks() {
return $this->checks;
}
/**
* isIterating
* @var boolean
*/
private $isIterating = false;
/**
* getIsIterating
* @return boolean
*/
public function getIsIterating() {
return $this->isIterating;
}
/**
* on
* @var boolean
*/
private $on = false;
/**
* getOn
* @return boolean
*/
public function getOn() {
return $this->on;
}
/**
* relative
* @var boolean
*/
private $relative = true;
/**
* setRelative
* @param $value
* @return Timer
*/
public function setRelative($value) {
$this->relative = $value;
return $this;
}
/**
* getRelative
* @return boolean
*/
public function getRelative() {
return $this->relative;
}
/**
* bottomBar
* @var boolean
*/
private $bottomBar = true;
/**
* setBottomBar
* @param $value
* @return Timer
*/
public function setBottomBar($value) {
$this->bottomBar = $value;
return $this;
}
/**
* getBottomBar
* @return boolean
*/
public function getBottomBar() {
return $this->bottomBar;
}
/**
* html
* @var boolean
*/
private $html = true;
/**
* setHtml
* @param $value
* @return Timer
*/
public function setHtml($value) {
$this->html = $value;
return $this;
}
/**
* getHtml
* @return boolean
*/
public function getHtml() {
return $this->html;
}
/**
* isIters
* @var boolean
*/
private $isIters = false;
/**
* getIsIters
* @return boolean
*/
public function getIsIters() {
return $this->isIters;
}
/**
* __construct
* @param string $check = null
* @return Timer
*/
public function __construct($check = null, $lbreak = "\n") {
$this->lbreak = $lbreak;
if($check !== null){
$this->start($check);
}
// Set timezone
date_default_timezone_set('UTC');
return $this;
}
/**
* start
* @param string $check = null
* @return Timer
*/
public function start($check = null) {
$this->startTime = microtime(true);
$this->iteration = 0;
$this->on = true;
$this->iterating = false;
$this->isIters = false;
if ($check != null)
$this->setCheck($check);
return $this;
}
/**
* stop
* @param string $check = null
* @return Timer
*/
public function stop($check = "Shut Down Timer") {
if ($check !== null)
$this->setCheck($check);
$this->stopTime = microtime(true);
$this->on = false;
$this->iterating = false;
return $this;
}
/**
* isOn
* @return boolean
*/
public function isOn() {
return $this->on;
}
/**
* setCheck
* @param string $check
* @param int|boolean $iteration
* @return Timer
*/
public function setCheck($check, $iteration = false) {
if ($this->iterating === true) {
end($this->checks["_functionIteration"]);
$lastKey = key($this->checks["_functionIteration"]);
$this->checks["_functionIteration"][$lastKey][$this->iteration][] = array(
"name" => $check,
"time" => $this->getElapsedTime()
);
} else {
$this->checks[] = array(
"name" => $check,
"time" => $this->getElapsedTime()
);
}
return $this;
}
/**
* addCheck
* @param string $check
* @param boolean $iteration
* @return Timer
*/
public function addCheck($check, $iteration = false) {
return $this->setCheck($check);
}
/**
* startIteration
* @param string $check
* @return Timer
*/
public function startIteration($check = "Starting Iteration") {
if($check !== null) $this->setCheck($check);
$this->iterating = true;
if($this->isIters === false) {
$this->checks["_functionIteration"] = array();
}
end($this->checks["_functionIteration"]);
$lastKey = key($this->checks["_functionIteration"]);
$this->checks["_functionIteration"][$lastKey]["_start"] = array(
"time" => $this->getElapsedTime()
);
$this->isIters = true;
return $this;
}
/**
* stopIteration
* @param string $check
* @return Timer
*/
public function stopIteration($check = "Stopping Iteration") {
$this->iterating = false;
$this->iteration = 0;
if($check !== null) $this->setCheck($check);
return $this;
}
/**
* startIters
* @param string $check
* @return Timer
*/
public function startIters($check = "Starting Iteration") {
return $this->startIteration();
}
/**
* stopIters
* @param string $check
* @return Timer
*/
public function stopIters($check = "Stopping Iteration") {
return $this->stopIteration();
}
/**
* stopIters
* @return Timer
*/
public function iterate() {
$this->iteration++;
return $this;
}
/**
* printChecks
* @return Timer
*/
public function printChecks() {
if($this->html === true){
echo $this->getChecksFormatted();
} else {
$this->printrChecks();
}
}
/**
* printChecksComment
* @return Timer
*/
public function printChecksComment() {
echo $this->getChecksComments($relative);
return $this;
}
/**
* printrChecks
* @return Timer
*/
public function printrChecks() {
echo "<pre>";
print_r($this->checks);
echo "</pre>";
return $this;
}
/**
* printElapsedTime
* @return Timer
*/
public function printElapsedTime() {
echo $this->getElapsedTime();
return $this;
}
/**
* printTotalExecutionTime
* @return Timer
*/
public function printTotalExecutionTime() {
echo $this->getTotalExecutionTime();
return $this;
}
/**
* printFullStats
* @return Timer
*/
public function printFullStats() {
if (! $this->stopTime) {
return false;
}
echo $this->lbreak . $this->lbreak;
echo "Script start date and time: " .
$this->getDateTime($this->startTime);
echo $this->lbreak;
echo "Script stop end date and time: " .
$this->getDateTime($this->stopTime);
echo $this->lbreak . $this->lbreak;
echo "Total execution time: " . $this->getExecutionTime(
$this->stopTime);
echo $this->lbreak . $this->lbreak;
return $this;
}
/**
* getChecksFormatted
* @return string
*/
public function getChecksFormatted() {
$container = "<div class='manticorp-timing-container";
if($this->bottomBar){
$container .= " manticorp-timing-bottom-bar";
}
$container .= "' style='" . self::$outputStyle . "'>";
$overallStats = array(
"totalExecutionTime" => $this->getTotalExecutionTime()
);
if($this->isIters) $overallStats["iterations"] = array();
$output = "";
$t = 0;
$this->relative ? $text = "Taken" : $text = "Elapsed";
if ($this->isIters) {
foreach($this->checks["_functionIteration"] as $itNum => $it){
$t = $it["_start"]["time"];
unset($it["_start"]);
$itNum = $itNum+1;
$output .= "<div class='manticorp-timing-iterators-table-title manticorp-timing-title'>Iterator $itNum</div>";
$amntChecks = count(current($it));
$amntIters = count($it);
reset($it);
$firstIter = key($it);
$checkNames = array();
foreach (current($it) as $check) {
$checkNames[] = $check["name"];
}
$output .= "<table class='mainticorp-timing-iterators-table'>
<tr><th>Check Name</th>";
if($this->printAllIterations){
for ($i = $firstIter; $i <= $firstIter + $amntIters - 1; $i ++) {
$output .= "<th>Iteration $i</th>";
}
}
$output .= "<th>avg</th><th>max</th><th>min</th></tr>";
foreach ($checkNames as $key => $check) {
$output .= "<tr><th> $check </th>";
$val = array();
for ($i = $firstIter; $i <= $firstIter + $amntIters - 1; $i ++) {
$prevIter = $firstIter;
if ($key == 0) {
$prevKey = $amntChecks - 1;
if ($i != $firstIter)
$prevIter --;
} else {
$prevKey = $key - 1;
}
$prevIter += $i - 1;
if ($this->relative && ! ($key == 0 && $i == $firstIter))
$t = $it[$prevIter][$prevKey]["time"];
$val[$i] = $it[$i][$key]["time"] -
$t;
if($this->printAllIterations)
$output .= "<td>" . number_format($val[$i], $this->accuracy) . "</td>";
}
$overallStats["iterations"][$itNum]["avgExecutionTime"] = array_sum($val) / $amntIters;
$overallStats["iterations"][$itNum]["totalExecutionTime"] = array_sum($val);
$overallStats["iterations"][$itNum]["maxExecutionTime"] = max($val);
$overallStats["iterations"][$itNum]["minExecutionTime"] = min($val);
$output .= "<td class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["avgExecutionTime"], $this->accuracy) .
"</td>";
$output .= "<td class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["maxExecutionTime"], $this->accuracy) . "</td>";
$output .= "<td class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["minExecutionTime"], $this->accuracy) . "</td>";
$output .= "</tr>";
}
$output .= "</table>";
}
}
$this->isIters ? $add = 1 : $add = 0;
if (count($this->checks) <= $add) {
return;
}
$t = 0;
$output .= "<div class='manticorp-timing-checks-table-title manticorp-timing-title'>Checks</div><table class='mainticorp-timing-checks-table'><tr><th>Check Name</th><th>Time $text (s)</th>";
foreach ($this->checks as $key => $check) {
if ($key !== "_functionIteration") {
$output .= "<tr><th>" . $check["name"] . "</th><td class='manticorp-timing-time'>" .
number_format(($check["time"] - $t), $this->accuracy) . "</td></tr>";
if ($this->relative)
$t = $check["time"];
}
}
$output .= "</table>";
if($this->printSummary){
$container .= "<div class='manticorp-timing-overall-stats'><span class='manticorp-timing-title manticorp-timing-title-summary'>Summary</span>";
$container .= "<div class='manticorp-timing-overall-stats-overall'>";
$container .= "<div><span>Overall Execution Time: \t</span><span class='manticorp-timing-time'>" . number_format($overallStats["totalExecutionTime"], $this->accuracy) . "s</span></div>";
$container .= "<div><span>Number of Checks: </span><span class='manticorp-timing-time'>" . count($this->checks) . "</span></div>";
$container .= "</div>";
foreach($overallStats["iterations"] as $itNum => $itStats){
$container .= "<div class='manticorp-timing-overall-stats-iterators'><span class='manticorp-timing-title'>Iterator $itNum</span>";
$container .= "<div><span>Total: <span class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["totalExecutionTime"], $this->accuracy) . "s</span></span></div>";
$container .= "<div><span>Avg: <span class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["avgExecutionTime"], $this->accuracy) . "s</span></span></div>";
$container .= "<div><span>Min: <span class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["minExecutionTime"], $this->accuracy) . "s</span></span></div>";
$container .= "<div><span>Max: <span class='manticorp-timing-time'>" . number_format($overallStats["iterations"][$itNum]["maxExecutionTime"], $this->accuracy) . "s</span></span></div>";
$container .= "</div>";
}
$container .= "</div>";
} // if($this->printSummary)
if($this->printTables){
$container .= $output;
}
$container .= "</div>";
return $container;
}
/**
* getChecksComment
* @return string
*/
public function getChecksComment() {
$output = "";
$t = 0;
$this->relative ? $text = "Taken" : $text = "Elapsed";
if ($this->isIters) {
$amntChecks = count(current($this->checks["_functionIteration"]));
$amntIters = count($this->checks["_functionIteration"]);
$firstIter = key($this->checks["_functionIteration"]);
$checkNames = array();
foreach (current($this->checks["_functionIteration"]) as $check) {
$checkNames[] = $check["name"];
}
$output .= "-----------------------------------\n
|\tCheck Name\t|";
for ($i = $firstIter; $i <= $firstIter + $amntIters - 1; $i ++) {
$output .= "\tIteration $i\t|\t";
}
$output .= "\tavg\t|\tmax\t|\tmin\t|\t\n";
foreach ($checkNames as $key => $check) {
$t = 0;
$output .= "|\t $check \t|\t";
$val = array();
for ($i = $firstIter; $i <= $firstIter + $amntIters - 1; $i ++) {
$prevIter = $firstIter;
if ($key == 0) {
$prevKey = $amntChecks - 1;
if ($i != $firstIter)
$prevIter --;
} else {
$prevKey = $key - 1;
}
$prevIter += $i - 1;
if ($this->relative && ! ($key == 0 && $i == $firstIter))
$t = $this->checks["_functionIteration"][$prevIter][$prevKey]["time"];
$val[$i] = $this->checks["_functionIteration"][$i][$key]["time"] -
$t;
$output .= "|\t" . number_format($val[$i], 10) . "\t";
}
$output .= "|\t" . number_format(array_sum($val) / $amntIters, 10) .
"\t";
$output .= "|\t" . number_format(max($val), 10) . "\t";
$output .= "|\t" . number_format(min($val), 10) . "\t";
$output .= "|\n";
}
$output .= "-----------------------------------";
}
$this->isIters ? $add = 1 : $add = 0;
if (count($this->checks) <= $add) {
return;
}
$t = 0;
$maxLength = 0;
foreach ($this->checks as $key => $check) {
if (strlen($check["name"]) > $maxLength)
$maxLength = strlen($check["name"]);
}
$numTabs = ($maxLength - 17);
$horizontal = "";
for ($i = 0; $i <= $numTabs+47; $i ++) {
$horizontal .= "-";
}
$output .= "$horizontal\n|\tCheck Name";
for ($i = 0; $i <= $numTabs; $i ++) {
$output .= " ";
}
$output .= "\t| Time $text (s)\t|\n";
$output .= "$horizontal\n";
foreach ($this->checks as $key => $check) {
if ($key !== "_functionIteration") {
$numTabs = ($maxLength - strlen($check["name"]));
$output .= "| " . $check["name"];
for ($i = 1; $i <= $numTabs; $i ++) {
$output .= " ";
}
$output .= "\t| " . number_format(($check["time"] - $t), 10) . "s \t|\n";
if ($this->relative) {
$t = $check["time"];
}
}
}
$output .= "$horizontal";
return $output;
}
/**
* getElapsedTime
* @return int|boolean
*/
public function getElapsedTime() {
return $this->getExecutionTime(microtime(true));
}
/**
* getTotalExecutionTime
* @return int
*/
public function getTotalExecutionTime() {
if ($this->stopTime === false) {
return false;
}
return $this->getExecutionTime($this->stopTime);
}
/**
* getExecutionTime
* @return int
*/
public function getExecutionTime($time) {
return $time - $this->startTime;
}
/**
* getFullStats
* @return array
*/
public function getFullStats() {
if (! $this->stopTime) {
return false;
}
$stats = array();
$stats['startTime'] = $this->getDateTime($this->startTime);
$stats['stopTime'] = $this->getDateTime($this->stopTime);
$stats['total_execution_time'] = $this->getExecutionTime(
$this->stopTime);
return $stats;
}
/**
* getDateTime
* @param int $time
* @return DateTime
*/
public function getDateTime(int $time) {
return date("Y-m-d H:i:s", $time);
}
}
// Examples:
$timing = new Timer();
$timing->setAccuracy(6)
->setPrintAllIterations(false)
->start("Starting testing");
$timing->addCheck("Starting recursive function");
// $timing->recurseStart();
$r = recursiveFunction(0,1000);
// $timing->recurseStop();
$timing->addCheck("Finished recursive");
$timing->startIteration("Starting iteration");
$l = iteratingFunction(10);
$timing->stopIteration("Finished iteration");
function recursiveFunction($i, $max){
usleep(10);
if($i>$max) return $i;
else return recursiveFunction($i+1, $max);
}
function iteratingFunction($loops){
global $timing;
for($i = 0; $i < $loops; $i++){
functionToIterate();
}
return $i;
}
function functionToIterate(){
global $timing;
$timing->iterate();
usleep(100000);
$timing->addCheck("Iteration check");
return true;
}
$timing->printChecks();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment