@ 2017-12-07T04:48:27Z <?php
namespace Lavoiesl\PhpBenchmark;
class Profiler
{
private $start_memory = 0;
private $max_memory = 0;
private $start_time = null;
private $end_time = null;
public function start()
{
$this->start_memory = $this->max_memory = memory_get_usage(true);
$this->start_time = microtime(true);
register_tick_function( array( $this, "tick" ) );
}
public function tick()
{
$this->max_memory = max($this->max_memory, memory_get_usage(true));
}
public function stop()
{
$this->tick();
$this->end_time = microtime(true);
unregister_tick_function( array( $this, "tick" ) );
}
function getMemoryUsage()
{
return $this->max_memory - $this->start_memory;
}
function getTime()
{
return $this->end_time - $this->start_time;
}
}
abstract class AbstractTest
{
/**
* @var string
*/
private $name;
private $profiler;
public function __construct($name)
{
$this->name = $name;
$this->profiler = new Profiler;
}
public function getName()
{
return $this->name;
}
public function run($n = 1)
{
$this->prepare();
gc_collect_cycles(); // clear memory before start
$this->profiler->start();
for ($i=0; $i < $n; $i++) {
// Store the result so it appears in memory profiling
$result = $this->execute();
unset($result);
}
$this->profiler->stop();
$results = array(
'time' => $this->profiler->getTime(),
'memory' => $this->profiler->getMemoryUsage(),
'n' => $n,
);
$this->cleanup();
return $results;
}
protected function prepare()
{
}
abstract protected function execute();
protected function cleanup()
{
}
public function guessCount($max_seconds = 1)
{
$this->run(); // warmup
$once = $this->run();
if ($once['time'] >= $max_seconds) {
return 1;
} else {
return round($max_seconds / $once['time']);
}
}
}
class SimpleTest extends AbstractTest
{
/**
* @var \Closure
*/
private $prepare = null;
/**
* @var \Closure
*/
private $execute;
/**
* @var \Closure
*/
private $cleanup = null;
public function __construct($name, \Closure $execute)
{
parent::__construct($name);
$this->execute = $execute;
}
public function setPrepare(\Closure $prepare)
{
$this->prepare = $prepare;
return $this;
}
protected function prepare()
{
if ($prepare = $this->prepare) {
$prepare();
}
}
protected function execute()
{
return call_user_func($this->execute);
}
public function setCleanup(\Closure $cleanup)
{
$this->cleanup = $cleanup;
return $this;
}
protected function cleanup()
{
if ($cleanup = $this->cleanup) {
$cleanup();
}
}
}
class Benchmark
{
/**
* @var array [Test]
*/
private $tests = array();
private $n = null;
private $base_results;
public function addTest(AbstractTest $test)
{
$this->tests[$test->getName()] = $test;
}
/**
* Utility method to create tests on the fly
* You may chain the test:
*
* @param string $name
* @param \Closure $closure function to execute
* @return SimpleTest
*/
public function add($name, \Closure $closure)
{
$test = new SimpleTest($name, $closure);
$this->addTest($test);
return $test;
}
/**
* Runs an empty test to determine the benchmark overhead and run each test once
*/
private function warmup()
{
$warmup = new SimpleTest('warmup', function(){});
$warmup->run();
foreach ($this->tests as $test) {
$test->run();
}
$this->base_results = $warmup->run($this->n);
}
public function run($output = true)
{
$results = array();
if (null === $this->n) {
$this->guessCount(2); // aim for around 2 seconds per test
}
if ($output) {
echo "Running tests {$this->n} times.\n";
}
$this->warmup();
$i = 0;
foreach ($this->tests as $name => $test) {
if ($output) {
echo "Testing ".++$i."/".count($this->tests)." : $name\r";
}
$results[$name] = $test->run($this->n);
}
if ($output) {
echo "\n\n";
self::outputTable(self::formatResults($results));
}
return $results;
}
public function setCount($n)
{
$this->n = $n;
}
/**
* Average the guessCount of each test, determining the best n
*
* @param float $max_seconds
* @return int
*/
public function guessCount($max_seconds)
{
if (!$this->tests) {
throw new \RuntimeException('No test in Benchmark.');
}
$n = INF;
foreach ($this->tests as $test) {
$n = min($n, $test->guessCount($max_seconds));
}
return $this->n = Util::round($n);
}
/**
* Output results in columns, padding right if values are string, left if numeric
*
* @param array $lines array(array('Name' => 'Value'));
* @param integer $padding space between columns
*/
public static function outputTable(array $lines, $padding = 3)
{
if (!$lines) {
return;
}
$pad = function ($string, $width) use ($padding) {
if ($width > 0) {
return str_pad($string, $width, " ") . str_repeat(' ' , $padding);
} else {
return str_pad($string, -$width, " ", STR_PAD_LEFT) . str_repeat(' ' , $padding);
}
};
// init width with keys' length
$cols = array_combine(array_keys($lines[0]), array_map('strlen', array_keys($lines[0])));
foreach ($cols as $col => $width) {
foreach ($lines as $line) {
$width = max($width, strlen($line[$col]));
}
// pad left if numeric
if (preg_match('/^[0-9]/', $line[$col])) {
$width = -$width;
}
echo $pad($col, $width);
$cols[$col] = $width;
}
echo "\n";
foreach ($lines as $line) {
foreach ($cols as $col => $width) {
echo $pad($line[$col], $width);
}
echo "\n";
}
}
/**
* Format the results, rounding numbers, showing difference percentages
* and removing a flat time based on the benchmark overhead
*
* @param array $results array($name => array('time' => 1.0))
* @return array array(array('Test' => $name, 'Time' => '1000 ms', 'Perc' => '100 %'))
*/
public function formatResults(array $results)
{
uasort($results, function($a, $b) {
if ($a['time'] == $b['time'])
return 0;
else
return ($a['time'] < $b['time']) ? -1 : 1;
});
$min_time = INF;
$min_memory = INF;
foreach ($results as $name => $result) {
$time = $result['time'];
$time -= $this->base_results['time']; // Substract base_time
$time *= 1000; // Convert to ms
$time = round($time);
$time = max(1, $time); // min 1 ms
$min_time = min($min_time, $time);
$results[$name]['time'] = $time;
$min_memory = min($min_memory, $results[$name]['memory']);
}
$output = array();
foreach ($results as $name => $result) {
$output[] = array(
'Test' => $name,
'Time' => $result['time'] . ' ms',
'Time (%)' => Util::relativePerc($min_time, $result['time']),
'Memory' => Util::convertToSI($result['memory']),
'Memory (%)' => Util::relativePerc($min_memory, $result['memory']),
);
}
return $output;
}
}
class Util
{
public static function round($number, $significant = 0)
{
$order = floor(log($number) / log(10));
return round($number / pow(10, $order), $significant) * pow(10, $order);
}
/**
* Converts 1024 to 1K, etc.
*
* @param double $number i.e.: 1280
* @param integer $precision i.e.: 1.25 for precision = 2
* @param string $unit suffix of the unit, may be empty
* @param integer $factor change base to 1000 or 1024
* @return string i.e.: 1.25 kB
*/
public static function convertToSI($number, $precision = 2, $unit = 'B', $factor = 1024)
{
static $sizes = array(
'-3' => 'n',
'-2' => 'µ',
'-1' => 'm',
'0' => '',
'1' => 'k',
'2' => 'M',
'3' => 'G',
'4' => 'T'
);
$scale = $number == 0 ? 0 : floor(log($number, $factor));
return round($number / pow($factor, $scale), $precision) . ' ' . $sizes[$scale] . $unit = 'B';
}
public static function relativePerc($min, $value) {
if ($min == 0 || $min == $value) {
return '';
} else {
return round(($value - $min) / $min * 100) . ' %';
}
}
}
$benchmark = new Benchmark;
function multiexplode ($delimiters,$string) {
$ready = str_replace($delimiters, $delimiters[0], $string);
$launch = explode($delimiters[0], $ready);
return $launch;
}
function homemadeexplode($splitter, $str)
{
$return = [];
if (is_array($splitter) == true) {
foreach ($splitter as $sp) {
$str = homemadeexplode($sp, $str);
}
$return = $str;
} else {
if (is_array($str) == true) {
foreach ($str as $st) {
$tmp = explode($splitter, $st);
$return = array_merge($return, $tmp);
}
} else {
$return = explode($splitter, $str);
}
}
return $return;
}
$text = "あいうえ おか き くけこさしす: せそたち つてとな, にぬね のはひふ へほまみ むめ もやゆよらりるれ. ろわおん あいうえ | this one too :)";
$benchmark->add('multiexplode', function() use($text) { return multiexplode( [",",".","|",":"], $text); });
$benchmark->add('homemadeExplode', function() use($text) { return homemadeexplode([",",".","|",":"], $text); });
$benchmark->add('preg_split', function() use($text) { return preg_split( '/[,.|:]/', $text); });
$benchmark->add('mb_split', function() use($text) { return mb_split( '[,.|:]', $text); });
$benchmark->setCount(50000);
$benchmark->run();
Enable javascript to submit You have javascript disabled. You will not be able to edit any code.
Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).
Version System time (s) User time (s) Memory (MiB) 8.0.11 0.003 0.363 17.41 8.0.10 0.003 0.353 17.25 8.0.9 0.003 0.358 17.40 8.0.8 0.010 0.645 17.40 8.0.7 0.007 0.358 17.27 8.0.6 0.007 0.354 17.45 8.0.5 0.003 0.356 17.41 8.0.3 0.014 0.700 17.48 8.0.2 0.017 1.051 17.73 8.0.1 0.000 0.372 17.42 8.0.0 0.010 1.477 17.10 7.4.24 0.007 0.377 17.25 7.4.23 0.000 0.385 17.00 7.4.22 0.006 0.686 16.98 7.4.21 0.010 0.851 17.23 7.4.20 0.007 0.379 16.90 7.4.16 0.017 0.983 16.96 7.4.15 0.007 1.060 17.40 7.4.14 0.012 1.226 17.86 7.4.13 0.016 1.373 17.01 7.4.12 0.015 1.311 17.04 7.4.11 0.010 1.537 16.90 7.4.10 0.016 1.404 17.25 7.4.9 0.010 1.384 16.90 7.4.8 0.006 1.224 19.39 7.4.7 0.010 1.229 16.87 7.4.6 0.016 1.254 16.86 7.4.5 0.003 0.642 16.81 7.4.4 0.006 1.321 16.95 7.4.3 0.010 1.239 17.05 7.4.1 0.003 0.911 16.96 7.4.0 0.010 0.771 16.24 7.3.30 0.003 0.384 16.62 7.3.29 0.009 0.683 16.76 7.3.28 0.010 0.689 16.82 7.3.27 0.013 1.031 17.40 7.3.26 0.012 1.229 16.90 7.3.25 0.029 1.043 16.94 7.3.24 0.012 1.337 17.00 7.3.23 0.013 1.115 16.80 7.3.21 0.013 1.148 17.07 7.3.20 0.010 1.068 17.00 7.3.19 0.029 0.994 17.00 7.3.18 0.013 0.964 16.99 7.3.17 0.013 1.157 16.73 7.3.16 0.013 1.135 16.76 7.3.13 0.010 0.954 16.84 7.3.12 0.013 0.819 16.70 7.3.11 0.007 0.696 16.71 7.3.10 0.003 0.926 17.02 7.3.9 0.007 0.708 16.56 7.3.8 0.000 0.889 16.64 7.3.7 0.013 0.887 16.77 7.3.6 0.026 0.805 16.66 7.3.5 0.007 0.711 16.90 7.3.4 0.000 0.586 16.70 7.3.3 0.003 0.452 16.75 7.3.2 0.000 0.607 18.41 7.3.1 0.003 0.537 18.34 7.3.0 0.007 0.486 18.59 7.2.33 0.003 1.371 16.98 7.2.32 0.026 1.554 17.19 7.2.31 0.013 1.459 17.29 7.2.30 0.047 1.362 16.77 7.2.29 0.010 1.343 17.23 7.2.26 0.003 0.783 17.02 7.2.25 0.016 0.752 16.93 7.2.24 0.007 0.880 17.02 7.2.23 0.010 0.990 17.07 7.2.22 0.007 0.741 17.10 7.2.21 0.007 0.876 17.01 7.2.20 0.007 1.022 16.97 7.2.19 0.003 0.979 16.77 7.2.18 0.003 0.794 17.00 7.2.17 0.003 0.498 17.23 7.2.16 0.007 0.660 16.92 7.2.15 0.013 0.471 18.77 7.2.14 0.007 0.621 18.75 7.2.13 0.003 0.466 18.70 7.2.12 0.007 0.668 18.61 7.2.11 0.003 0.545 18.66 7.2.10 0.000 0.489 18.64 7.2.9 0.007 0.683 18.54 7.2.8 0.006 0.503 18.72 7.2.7 0.007 0.454 18.68 7.2.6 0.003 0.423 17.78 7.2.5 0.007 0.494 18.68 7.2.4 0.010 0.671 18.59 7.2.3 0.003 0.538 18.80 7.2.2 0.003 0.483 18.85 7.2.1 0.007 0.498 18.66 7.2.0 0.007 0.488 19.18 7.1.33 0.003 0.975 17.58 7.1.32 0.003 1.007 17.77 7.1.31 0.003 0.780 17.55 7.1.30 0.003 0.963 17.57 7.1.29 0.007 0.733 17.80 7.1.28 0.007 0.885 17.84 7.1.27 0.010 0.576 17.55 7.1.26 0.003 0.543 17.48 7.1.25 0.007 0.516 17.43 7.1.24 0.000 0.646 17.71 7.1.23 0.007 0.513 17.50 7.1.22 0.003 0.578 17.54 7.1.21 0.003 0.659 17.54 7.1.20 0.003 0.417 16.91 7.1.19 0.003 0.519 17.57 7.1.18 0.007 0.681 17.65 7.1.17 0.011 0.633 17.49 7.1.16 0.003 0.523 17.55 7.1.15 0.007 0.479 17.72 7.1.14 0.000 0.686 17.38 7.1.13 0.007 0.569 17.71 7.1.12 0.006 0.530 18.08 7.1.11 0.005 0.519 17.77 7.1.10 0.003 0.495 18.01 7.1.9 0.007 0.549 17.81 7.1.8 0.002 0.561 17.94 7.1.7 0.007 0.543 17.46 7.1.6 0.012 0.574 26.50 7.1.5 0.015 0.530 26.32 7.1.4 0.012 0.476 26.10 7.1.3 0.008 0.463 26.10 7.1.2 0.012 0.528 26.21 7.1.1 0.012 0.535 17.10 7.1.0 0.005 0.485 17.35 7.0.33 0.003 0.567 17.24 7.0.32 0.003 0.641 17.34 7.0.31 0.003 0.710 17.18 7.0.30 0.007 0.543 17.26 7.0.29 0.007 0.548 17.25 7.0.28 0.003 0.613 17.02 7.0.27 0.000 0.729 17.24 7.0.26 0.000 0.710 17.17 7.0.25 0.007 0.679 17.36 7.0.24 0.010 0.624 17.48 7.0.23 0.007 0.622 17.43 7.0.22 0.003 0.606 17.47 7.0.21 0.000 0.596 17.34 7.0.20 0.010 0.676 17.39 7.0.19 0.003 0.683 17.36 7.0.18 0.007 0.555 17.06 7.0.17 0.003 0.521 17.33 7.0.16 0.000 0.730 17.30 7.0.15 0.000 0.555 17.34 7.0.14 0.003 0.673 17.11 7.0.13 0.010 0.543 17.13 7.0.12 0.003 0.728 17.29 7.0.11 0.007 0.709 17.17 7.0.10 0.009 0.730 17.23 7.0.9 0.000 0.558 17.15 7.0.8 0.007 0.542 17.22 7.0.7 0.007 0.573 17.46 7.0.6 0.010 0.569 17.17 7.0.5 0.010 0.548 17.41 7.0.4 0.010 0.749 15.25 7.0.3 0.000 0.769 15.20 7.0.2 0.007 0.565 15.16 7.0.1 0.007 0.747 15.38 7.0.0 0.003 0.568 15.22 5.6.40 0.026 1.710 16.08 5.6.39 0.000 1.552 16.42 5.6.38 0.007 1.862 16.70 5.6.37 0.003 1.947 16.33 5.6.36 0.007 1.962 16.14 5.6.35 0.010 1.885 16.39 5.6.34 0.003 1.889 16.20 5.6.33 0.003 1.530 16.02 5.6.32 0.007 1.839 16.35 5.6.31 0.007 1.989 16.07 5.6.30 0.007 1.824 16.33 5.6.29 0.007 1.829 16.40 5.6.28 0.010 1.777 16.32 5.6.27 0.007 1.960 16.22 5.6.26 0.010 1.769 16.40 5.6.25 0.007 2.031 16.24 5.6.24 0.010 1.946 16.22 5.6.23 0.007 2.068 16.08 5.6.22 0.003 2.044 16.27 5.6.21 0.042 1.735 16.46 5.6.20 0.007 1.832 16.15 5.6.19 0.003 1.815 16.15 5.6.18 0.000 1.524 16.02 5.6.17 0.007 1.647 16.10 5.6.16 0.003 1.701 16.18 5.6.15 0.000 1.860 15.96 5.6.14 0.063 1.946 16.29 5.6.13 0.000 1.931 16.49 5.6.12 0.003 1.925 16.24 5.6.11 0.007 1.800 16.05 5.6.10 0.003 2.141 16.05 5.6.9 0.003 2.111 16.19 5.6.8 0.007 1.793 16.18 5.6.7 0.010 1.821 15.96 5.6.6 0.000 1.565 16.13 5.6.5 0.003 1.957 16.11 5.6.4 0.003 1.658 16.10 5.6.3 0.003 1.489 16.20 5.6.2 0.000 1.544 15.86 5.6.1 0.003 1.432 16.21 5.6.0 0.013 1.669 16.05
preferences:dark mode live preview ace vim emacs key bindings
51.99 ms | 403 KiB | 5 Q