@ 2017-12-07T02:40:30Z <?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 = "here is a sample: this text, and this will be exploded. this also | 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.000 0.304 17.43 8.0.10 0.000 0.297 17.36 8.0.9 0.007 0.335 17.47 8.0.8 0.006 0.465 17.39 8.0.7 0.003 0.300 17.39 8.0.6 0.007 0.295 17.50 8.0.5 0.003 0.298 17.29 8.0.3 0.010 0.582 17.38 8.0.2 0.020 1.075 17.53 8.0.1 0.007 0.293 17.47 8.0.0 0.013 0.972 17.14 7.4.24 0.003 0.314 17.14 7.4.23 0.003 0.322 16.86 7.4.22 0.022 0.588 17.16 7.4.21 0.008 0.536 17.07 7.4.20 0.000 0.324 17.13 7.4.16 0.016 0.837 17.06 7.4.15 0.016 1.129 17.40 7.4.14 0.011 1.145 17.86 7.4.13 0.010 1.023 16.97 7.4.12 0.015 1.172 16.99 7.4.11 0.016 1.091 17.04 7.4.10 0.003 1.353 16.82 7.4.9 0.019 0.931 17.11 7.4.8 0.010 1.110 19.39 7.4.7 0.018 1.528 16.86 7.4.6 0.013 0.943 16.85 7.4.5 0.003 0.495 16.90 7.4.4 0.016 1.353 16.96 7.4.3 0.020 1.297 16.98 7.4.1 0.003 0.691 15.35 7.4.0 0.007 0.654 15.23 7.3.30 0.006 0.324 16.78 7.3.29 0.003 0.335 16.68 7.3.28 0.014 0.646 16.80 7.3.27 0.010 0.952 17.40 7.3.26 0.012 1.017 16.95 7.3.25 0.017 1.051 16.85 7.3.24 0.012 1.079 16.91 7.3.23 0.019 0.957 16.77 7.3.21 0.007 1.022 16.81 7.3.20 0.016 1.197 17.00 7.3.19 0.013 0.808 17.04 7.3.18 0.010 0.861 16.95 7.3.17 0.010 1.022 17.06 7.3.16 0.010 0.848 17.01 7.3.13 0.007 0.684 15.08 7.3.12 0.004 0.788 15.10 7.3.11 0.009 0.635 15.29 7.3.10 0.002 0.647 15.11 7.3.9 0.002 0.598 15.34 7.3.8 0.007 0.699 15.11 7.3.7 0.007 0.673 15.11 7.3.6 0.003 0.651 15.13 7.3.5 0.004 0.732 15.26 7.3.4 0.004 0.509 15.20 7.3.3 0.004 0.470 15.17 7.3.2 0.004 0.465 16.77 7.3.1 0.001 0.575 16.78 7.3.0 0.007 0.498 16.87 7.2.33 0.020 1.064 16.98 7.2.32 0.017 1.210 17.20 7.2.31 0.017 1.165 17.04 7.2.30 0.300 1.097 16.92 7.2.29 0.020 0.974 17.11 7.2.26 0.008 0.847 15.38 7.2.25 0.008 0.863 15.41 7.2.24 0.007 0.678 15.52 7.2.23 0.006 0.738 15.41 7.2.22 0.003 0.790 15.52 7.2.21 0.003 0.807 15.34 7.2.20 0.003 0.680 15.46 7.2.19 0.006 0.688 15.35 7.2.18 0.006 0.749 15.31 7.2.17 0.001 0.552 15.29 7.2.16 0.005 0.560 15.41 7.2.15 0.003 0.541 17.12 7.2.14 0.003 0.645 17.25 7.2.13 0.007 0.522 17.17 7.2.12 0.007 0.554 17.17 7.2.11 0.003 0.610 17.23 7.2.10 0.007 0.592 17.20 7.2.9 0.003 0.501 17.08 7.2.8 0.007 0.566 17.04 7.2.7 0.001 0.564 17.05 7.2.6 0.007 0.500 17.12 7.2.5 0.009 0.611 17.14 7.2.4 0.003 0.494 17.22 7.2.3 0.006 0.554 17.10 7.2.2 0.003 0.542 17.15 7.2.1 0.004 0.590 16.96 7.2.0 0.011 0.529 17.38 7.1.33 0.002 0.715 16.15 7.1.32 0.006 0.756 16.08 7.1.31 0.003 0.723 15.94 7.1.30 0.007 0.752 16.09 7.1.29 0.003 0.731 16.08 7.1.28 0.000 0.719 16.08 7.1.27 0.006 0.547 16.03 7.1.26 0.008 0.491 16.14 7.1.25 0.004 0.585 15.89 7.1.24 0.002 0.555 16.11 7.1.23 0.004 0.562 15.99 7.1.22 0.001 0.567 15.98 7.1.21 0.007 0.544 16.15 7.1.20 0.003 0.531 15.95 7.1.19 0.007 0.522 16.11 7.1.18 0.006 0.536 15.86 7.1.17 0.004 0.602 16.04 7.1.16 0.003 0.550 15.90 7.1.15 0.007 0.518 16.10 7.1.14 0.009 0.617 15.99 7.1.13 0.004 0.559 15.93 7.1.12 0.008 0.518 16.47 7.1.11 0.003 0.526 16.28 7.1.10 0.010 0.534 16.40 7.1.9 0.009 0.539 16.17 7.1.8 0.015 0.542 16.31 7.1.7 0.008 0.504 15.88 7.1.6 0.018 0.508 23.05 7.1.5 0.018 0.530 22.86 7.1.4 0.012 0.506 22.69 7.1.3 0.015 0.532 22.77 7.1.2 0.013 0.525 22.84 7.1.1 0.013 0.519 15.65 7.1.0 0.007 0.510 15.63 7.0.33 0.007 0.555 15.67 7.0.32 0.007 0.539 15.63 7.0.31 0.008 0.696 15.63 7.0.30 0.003 0.574 15.61 7.0.29 0.005 0.606 15.63 7.0.28 0.003 0.685 15.68 7.0.27 0.041 0.639 15.67 7.0.26 0.005 0.601 15.59 7.0.25 0.007 0.653 15.54 7.0.24 0.003 0.728 15.57 7.0.23 0.006 0.677 15.76 7.0.22 0.005 0.606 15.67 7.0.21 0.005 0.696 15.50 7.0.20 0.005 0.629 15.64 7.0.19 0.003 0.653 15.76 7.0.18 0.003 0.616 15.65 7.0.17 0.003 0.719 15.78 7.0.16 0.007 0.626 15.70 7.0.15 0.005 0.690 15.63 7.0.14 0.002 0.661 15.55 7.0.13 0.005 0.695 15.71 7.0.12 0.005 0.715 15.66 7.0.11 0.002 0.744 15.64 7.0.10 0.005 0.714 15.71 7.0.9 0.003 0.699 15.64 7.0.8 0.005 0.720 15.49 7.0.7 0.007 0.730 15.56 7.0.6 0.007 0.661 15.54 7.0.5 0.005 0.732 15.57 7.0.4 0.003 0.732 13.78 7.0.3 0.002 0.637 13.76 7.0.2 0.007 0.624 13.54 7.0.1 0.007 0.685 13.62 7.0.0 0.005 0.751 13.75 5.6.40 0.002 1.376 14.47 5.6.39 0.003 1.645 14.63 5.6.38 0.007 1.493 14.54 5.6.37 0.000 1.649 14.81 5.6.36 0.005 1.508 14.92 5.6.35 0.002 1.800 14.72 5.6.34 0.008 1.748 14.85 5.6.33 0.002 1.554 14.74 5.6.32 0.003 1.539 14.84 5.6.31 0.007 1.583 14.78 5.6.30 0.012 1.588 14.70 5.6.29 0.008 1.610 14.53 5.6.28 0.003 1.759 14.78 5.6.27 0.003 1.741 14.72 5.6.26 0.019 1.762 14.89 5.6.25 0.003 1.632 14.69 5.6.24 0.013 1.785 14.81 5.6.23 0.003 1.572 14.79 5.6.22 0.006 1.404 14.91 5.6.21 0.005 1.710 14.60 5.6.20 0.003 1.743 14.65 5.6.19 0.005 1.664 14.76 5.6.18 0.007 1.691 14.63 5.6.17 0.008 1.506 14.71 5.6.16 0.003 1.796 14.85 5.6.15 0.005 1.803 14.67 5.6.14 0.007 1.751 14.58 5.6.13 0.005 1.630 14.81 5.6.12 0.008 1.609 14.62 5.6.11 0.020 1.581 14.64 5.6.10 0.008 1.640 14.89 5.6.9 0.072 1.579 14.76 5.6.8 0.005 1.723 14.46 5.6.7 0.003 1.513 14.65 5.6.6 0.005 1.618 14.41 5.6.5 0.007 1.465 14.61 5.6.4 0.005 1.485 14.55 5.6.3 0.002 1.446 14.50 5.6.2 0.005 1.416 14.64 5.6.1 0.003 1.422 14.61 5.6.0 0.008 1.411 14.53
preferences:dark mode live preview
41.48 ms | 401 KiB | 5 Q