<?php
class Bench {
protected $functions = [];
protected $cli;
public function __construct($cli = false) {
$this->cli = $cli;
}
public function add($label, \Closure $function) {
$this->functions[] = [$label, $function];
}
public function run($count) {
$function = function () {};
$stats = $this->getStats();
for ($i = $count; $i--;) $function();
$stats2 = $this->getStats();
$timeDiff = $stats2[4] - $stats[4];
$this->printStats('Empty test (delta time subtracted from subsequent test)', $stats, $stats2, 0);
// TODO: Split runs in pieces and interleave, to avoid bias with first/last runner.
foreach ($this->functions as list($label, $function)) {
$stats = $this->getStats();
for ($i = $count; $i--;) $function();
$stats2 = $this->getStats();
$this->printStats($label, $stats, $stats2, $timeDiff);
}
}
protected function getStats() {
return [memory_get_usage(), memory_get_usage(true), memory_get_peak_usage(), memory_get_peak_usage(true), microtime(1)];
}
protected function printStats($label, $stats1, $stats2, $timeDiff) {
list($mem, $memReal, $memPeak, $memRealPeak, $time) = $stats1;
list($memNew, $memRealNew, $memPeakNew, $memRealPeakNew, $timeNew) = $stats2;
$nl = "\n";
$labelLength = 20;
$resultsLength = 15;
// TODO: Better CLI support. Machine data export.
if (PHP_SAPI === 'CLI') {
ob_start();
}
echo '<p><b>' . $label . '</b></p>' . $nl;
echo '<code><p>' . $nl;
echo str_pad('Memory', $labelLength, '.', STR_PAD_RIGHT);
echo str_pad(number_format(($memNew - $mem) >> 10, 0), $resultsLength, '.', STR_PAD_LEFT) . ' kb<br>' . $nl;
echo str_pad('Memory Real', $labelLength, '.', STR_PAD_RIGHT);
echo str_pad(number_format(($memRealNew - $memReal) >> 10, 0), $resultsLength, '.', STR_PAD_LEFT) . ' kb<br>' . $nl;
echo str_pad('Memory Peak', $labelLength, '.', STR_PAD_RIGHT);
echo str_pad(number_format(($memPeakNew - $memPeak) >> 10, 0), $resultsLength, '.', STR_PAD_LEFT) . ' kb<br>' . $nl;
echo str_pad('Memory Real Peak', $labelLength, '.', STR_PAD_RIGHT);
echo str_pad(number_format(($memRealPeakNew - $memRealPeak) >> 10, 0), $resultsLength, '.', STR_PAD_LEFT) . ' kb<br>' . $nl;
echo str_pad('Time', $labelLength, '.', STR_PAD_RIGHT);
echo str_pad(number_format($timeNew - $time - $timeDiff, 5), $resultsLength, '.', STR_PAD_LEFT);
echo ' sec' . $nl . '</code></p>' . $nl . $nl;
if (PHP_SAPI === 'CLI') {
$content = ob_end_clean();
echo preg_replace('/<.*?>/', '', $content);
}
}
}
class Log {
private $has = []; // TODO: Can be replaced with a bitmask.
private $events = [];
public function __construct() {
}
/* (non-PHPdoc)
* @see \Solver\Logging\Log::log()
*/
public function log(array $event) {
$type = $event['type'];
if (!isset($this->has[$type])) $this->has[$type] = true;
$this->events[] = $event;
}
/* (non-PHPdoc)
* @see \Solver\Logging\MemoryLog::getEvents()
*/
public function getEvents($types = null) {
if ($types === null || !$this->events) {
return $this->events;
} else {
$types = array_flip($types);
// Special optimized case: the given $types mask matches or is a superset of the event types we have.
$optimized = true;
foreach ($this->has as $key => $val) if (!isset($types[$key])) {
$optimized = false;
break;
}
if ($optimized) {
return $this->events;
} else {
$events = [];
foreach ($this->events as $event) if (isset($types[$event['type']])) $events[] = $event;
return $events;
}
}
}
/* (non-PHPdoc)
* @see \Solver\Logging\MemoryLog::hasEvents()
*/
public function hasEvents($types = null) {
if ($types === null) {
return (bool) $this->has;
} else {
foreach ($types as $type) if (isset($this->has[$type])) return true;
return false;
}
}
/* (non-PHPdoc)
* @see \Solver\Logging\ErrorMemoryLog::getErrors()
*/
public function getErrors() {
return $this->getEvents(['error']);
}
/* (non-PHPdoc)
* @see \Solver\Logging\ErrorMemoryLog::hasErrors()
*/
public function hasErrors() {
$o = $this->hasEvents(['error']);
$this->events = [];
$this->has = [];
return $o;
}
/* (non-PHPdoc)
* @see \Solver\Logging\ErrorLog::error()
*/
public function error($path = null, $message = null, $code = null, array $details = null) {
$event = ['type' => 'error'];
if (isset($path)) $event['path'] = $path;
if (isset($message)) $event['message'] = $message;
if (isset($code)) $event['code'] = $code;
if (isset($details)) $event['details'] = $details;
$this->log($event);
}
}
$log = new Log();
$be = new Bench(true);
$be2 = new Bench();
$error = new stdClass();
$a = 0;
$b = 0;
$be->add('Sentinel', function () use ($error, & $a, & $b) {
$x = function ($error) {
return mt_rand(0, 1) ? 123 : $error;
};
$result = $x($error);
if ($result === $error) {
$a ++;
} else {
$b ++;
}
});
$be->add('Tuple', function () use (& $a, & $b) {
$x = function () {
return mt_rand(0, 1) ? [true, 123] : [false, null];
};
list($error, $result) = $x();
if ($error) {
$a ++;
} else {
$b ++;
}
});
$be->add('Exception', function () use (& $a, & $b) {
$x = function () {
if (mt_rand(0, 1)) throw new \Exception();
return 123;
};
try {
$result = $x();
$a ++;
} catch (\Exception $e) {
$b ++;
}
});
$be->add('Log', function () use ($log, & $a, & $b) {
$x = function ($log) {
if (mt_rand(0, 1)) {
$log->error();
return null;
} else {
return 123;
}
};
$result = $x($log);
if ($log->hasErrors()) {
$a ++;
} else {
$b ++;
}
});
if (PHP_VERSION === '7.0.0RC4') $be->run(500000);
var_dump($a);
var_dump($b);
- Output for 5.5.0 - 5.5.38, 5.6.0 - 5.6.40, 7.0.0 - 7.0.33, 7.1.0 - 7.1.33, 7.2.0 - 7.2.26, 7.3.0 - 7.3.13, 7.4.0 - 7.4.1
- int(0)
int(0)
- Output for 5.4.0 - 5.4.45
- Parse error: syntax error, unexpected 'list' (T_LIST) in /in/ceOLv on line 27
Process exited with code 255.
preferences:
164.14 ms | 401 KiB | 242 Q