Created
September 13, 2013 23:20
-
-
Save rdominy/6557280 to your computer and use it in GitHub Desktop.
This command line PHP script tests algorithm times, keeping track of results in a histogram.
Each time a new worst case elapsed time is found, the script will print out metrics, including user cpu time, system cpu time and context switches.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(ticks = 1); | |
/* | |
* This command line PHP script tests algorithm times, keeping track of results in a histogram. | |
* Each time a new worst case elapsed time is found, the script will print out metrics, including | |
* user cpu time, system cpu time and context switches. | |
* | |
* Pressing Cntrl-Z will dump the current stats. | |
*/ | |
class InteruptTester | |
{ | |
const MEMORY_SIZE = 1048576; // 1MB | |
const ITERATION_LIMIT = 7000; | |
const SLEEP_BETWEEN_TESTS_MS = 100; // Amount of time to sleep between test runs (avoid abusing CPU) | |
public $worstEvent = null; | |
public $timeCounts = null; | |
public $timeBuckets = null; | |
public $worstTime = 0; | |
public $eatMemory = null; | |
protected $usageStart = null; | |
protected $usageEnd = null; | |
protected $tStart = 0; | |
protected $tEnd = 0; | |
protected $timeSum = 0; | |
protected $timeAverage = 0; | |
protected $iterations; | |
public function __construct() | |
{ | |
$this->timeBuckets = array(2,6,10,18,24,50,75,100,200,10000); | |
$this->timeCounts = array(0,0,0,0,0,0,0,0,0,0); | |
$this->eatMemory = array(); | |
$size = 0; | |
$chunkSize = 10000; | |
while ($size < self::MEMORY_SIZE) | |
{ | |
$this->eatMemory[] = str_pad('pig', $chunkSize, uniqid()); | |
$size += $chunkSize; | |
} | |
} | |
public function main() | |
{ | |
$uSleep = self::SLEEP_BETWEEN_TESTS_MS * 1000; | |
while(true) | |
{ | |
$this->timetest(); | |
usleep($uSleep); | |
} | |
} | |
protected function markStart() | |
{ | |
$this->usageStart = getrusage(); | |
$this->tStart = microtime(true); | |
} | |
protected function markEnd($iterations) | |
{ | |
$this->tEnd = microtime(true); | |
$this->usageEnd = getrusage(); | |
$elapsed = round($this->tEnd*1000 - $this->tStart*1000); | |
$usageDiffKeys = array('ru_nsignals' => 'signals','ru_nivcsw' =>'involSwitch', 'ru_nvcsw' =>'volSwitch', | |
'ru_minflt' =>'minFault', 'ru_majflt' =>'majFault'); | |
$info = array('elapsed' => $elapsed); | |
foreach($usageDiffKeys as $key =>$val) | |
{ | |
$info[$val] = $this->usageEnd[$key] - $this->usageStart[$key]; | |
} | |
$info['userCPUTime'] = (($this->usageEnd['ru_utime.tv_sec']*1e6+$this->usageEnd['ru_utime.tv_usec']) - ($this->usageStart['ru_utime.tv_sec']*1e6+$this->usageStart['ru_utime.tv_usec']))/1000; // in ms | |
$info['systemCPUTime'] = (($this->usageEnd['ru_stime.tv_sec']*1e6+$this->usageEnd['ru_stime.tv_usec']) - ($this->usageStart['ru_stime.tv_sec']*1e6+$this->usageStart['ru_stime.tv_usec']))/1000; | |
$this->countTime($elapsed); | |
if ($elapsed>$this->worstTime) | |
{ | |
$this->logEvent($info); | |
$this->worstEvent = $info; | |
$this->worstTime = $elapsed; | |
} | |
return $info; | |
} | |
public function countTime($t) | |
{ | |
$this->timeSum += $t; | |
$this->iterations++; | |
$this->timeAverage = $this->timeSum/$this->iterations; | |
for($i=0;$i<count($this->timeBuckets);$i++) | |
{ | |
if ($t<$this->timeBuckets[$i]) | |
{ | |
$this->timeCounts[$i]++; | |
break; | |
} | |
} | |
} | |
protected function logEvent($info) | |
{ | |
print_r($info); | |
} | |
public function sigint_handler($signo) | |
{ | |
$this->showStats(); | |
exit(); | |
} | |
public function sigstp_handler($signo) | |
{ | |
$this->showStats(); | |
} | |
public function showStats() | |
{ | |
print_r($this->worstEvent); | |
print("Average time: " . $this->timeAverage . "\n"); | |
$startRange = 0; | |
for($i=0;$i<count($this->timeBuckets);$i++) | |
{ | |
print($startRange . '-'. $this->timeBuckets[$i] . ' : ' . $this->timeCounts[$i] . "\n"); | |
$startRange = $this->timeBuckets[$i]+1; | |
} | |
} | |
/* | |
* This is the algorithm being measured. | |
* | |
* Replaces the contents of the loop with your code. | |
*/ | |
public function timetest() | |
{ | |
$this->markStart(); | |
$limit = self::ITERATION_LIMIT; | |
$iterations = 0; | |
while ($iterations < $limit) | |
{ | |
$iterations++; | |
$last=microtime(true); | |
} | |
$this->markEnd($iterations); | |
} | |
} | |
$gInteruptTester = new InteruptTester(); | |
pcntl_signal(SIGINT, array($gInteruptTester, 'sigint_handler')); | |
pcntl_signal(SIGTSTP, array($gInteruptTester, 'sigstp_handler')); | |
$gInteruptTester->main(); | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment