3v4l.org

run code in 300+ PHP versions simultaneously
<?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();

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).

VersionSystem time (s)User time (s)Memory (MiB)
8.0.110.0000.30417.43
8.0.100.0000.29717.36
8.0.90.0070.33517.47
8.0.80.0060.46517.39
8.0.70.0030.30017.39
8.0.60.0070.29517.50
8.0.50.0030.29817.29
8.0.30.0100.58217.38
8.0.20.0201.07517.53
8.0.10.0070.29317.47
8.0.00.0130.97217.14
7.4.240.0030.31417.14
7.4.230.0030.32216.86
7.4.220.0220.58817.16
7.4.210.0080.53617.07
7.4.200.0000.32417.13
7.4.160.0160.83717.06
7.4.150.0161.12917.40
7.4.140.0111.14517.86
7.4.130.0101.02316.97
7.4.120.0151.17216.99
7.4.110.0161.09117.04
7.4.100.0031.35316.82
7.4.90.0190.93117.11
7.4.80.0101.11019.39
7.4.70.0181.52816.86
7.4.60.0130.94316.85
7.4.50.0030.49516.90
7.4.40.0161.35316.96
7.4.30.0201.29716.98
7.4.10.0030.69115.35
7.4.00.0070.65415.23
7.3.300.0060.32416.78
7.3.290.0030.33516.68
7.3.280.0140.64616.80
7.3.270.0100.95217.40
7.3.260.0121.01716.95
7.3.250.0171.05116.85
7.3.240.0121.07916.91
7.3.230.0190.95716.77
7.3.210.0071.02216.81
7.3.200.0161.19717.00
7.3.190.0130.80817.04
7.3.180.0100.86116.95
7.3.170.0101.02217.06
7.3.160.0100.84817.01
7.3.130.0070.68415.08
7.3.120.0040.78815.10
7.3.110.0090.63515.29
7.3.100.0020.64715.11
7.3.90.0020.59815.34
7.3.80.0070.69915.11
7.3.70.0070.67315.11
7.3.60.0030.65115.13
7.3.50.0040.73215.26
7.3.40.0040.50915.20
7.3.30.0040.47015.17
7.3.20.0040.46516.77
7.3.10.0010.57516.78
7.3.00.0070.49816.87
7.2.330.0201.06416.98
7.2.320.0171.21017.20
7.2.310.0171.16517.04
7.2.300.3001.09716.92
7.2.290.0200.97417.11
7.2.260.0080.84715.38
7.2.250.0080.86315.41
7.2.240.0070.67815.52
7.2.230.0060.73815.41
7.2.220.0030.79015.52
7.2.210.0030.80715.34
7.2.200.0030.68015.46
7.2.190.0060.68815.35
7.2.180.0060.74915.31
7.2.170.0010.55215.29
7.2.160.0050.56015.41
7.2.150.0030.54117.12
7.2.140.0030.64517.25
7.2.130.0070.52217.17
7.2.120.0070.55417.17
7.2.110.0030.61017.23
7.2.100.0070.59217.20
7.2.90.0030.50117.08
7.2.80.0070.56617.04
7.2.70.0010.56417.05
7.2.60.0070.50017.12
7.2.50.0090.61117.14
7.2.40.0030.49417.22
7.2.30.0060.55417.10
7.2.20.0030.54217.15
7.2.10.0040.59016.96
7.2.00.0110.52917.38
7.1.330.0020.71516.15
7.1.320.0060.75616.08
7.1.310.0030.72315.94
7.1.300.0070.75216.09
7.1.290.0030.73116.08
7.1.280.0000.71916.08
7.1.270.0060.54716.03
7.1.260.0080.49116.14
7.1.250.0040.58515.89
7.1.240.0020.55516.11
7.1.230.0040.56215.99
7.1.220.0010.56715.98
7.1.210.0070.54416.15
7.1.200.0030.53115.95
7.1.190.0070.52216.11
7.1.180.0060.53615.86
7.1.170.0040.60216.04
7.1.160.0030.55015.90
7.1.150.0070.51816.10
7.1.140.0090.61715.99
7.1.130.0040.55915.93
7.1.120.0080.51816.47
7.1.110.0030.52616.28
7.1.100.0100.53416.40
7.1.90.0090.53916.17
7.1.80.0150.54216.31
7.1.70.0080.50415.88
7.1.60.0180.50823.05
7.1.50.0180.53022.86
7.1.40.0120.50622.69
7.1.30.0150.53222.77
7.1.20.0130.52522.84
7.1.10.0130.51915.65
7.1.00.0070.51015.63
7.0.330.0070.55515.67
7.0.320.0070.53915.63
7.0.310.0080.69615.63
7.0.300.0030.57415.61
7.0.290.0050.60615.63
7.0.280.0030.68515.68
7.0.270.0410.63915.67
7.0.260.0050.60115.59
7.0.250.0070.65315.54
7.0.240.0030.72815.57
7.0.230.0060.67715.76
7.0.220.0050.60615.67
7.0.210.0050.69615.50
7.0.200.0050.62915.64
7.0.190.0030.65315.76
7.0.180.0030.61615.65
7.0.170.0030.71915.78
7.0.160.0070.62615.70
7.0.150.0050.69015.63
7.0.140.0020.66115.55
7.0.130.0050.69515.71
7.0.120.0050.71515.66
7.0.110.0020.74415.64
7.0.100.0050.71415.71
7.0.90.0030.69915.64
7.0.80.0050.72015.49
7.0.70.0070.73015.56
7.0.60.0070.66115.54
7.0.50.0050.73215.57
7.0.40.0030.73213.78
7.0.30.0020.63713.76
7.0.20.0070.62413.54
7.0.10.0070.68513.62
7.0.00.0050.75113.75
5.6.400.0021.37614.47
5.6.390.0031.64514.63
5.6.380.0071.49314.54
5.6.370.0001.64914.81
5.6.360.0051.50814.92
5.6.350.0021.80014.72
5.6.340.0081.74814.85
5.6.330.0021.55414.74
5.6.320.0031.53914.84
5.6.310.0071.58314.78
5.6.300.0121.58814.70
5.6.290.0081.61014.53
5.6.280.0031.75914.78
5.6.270.0031.74114.72
5.6.260.0191.76214.89
5.6.250.0031.63214.69
5.6.240.0131.78514.81
5.6.230.0031.57214.79
5.6.220.0061.40414.91
5.6.210.0051.71014.60
5.6.200.0031.74314.65
5.6.190.0051.66414.76
5.6.180.0071.69114.63
5.6.170.0081.50614.71
5.6.160.0031.79614.85
5.6.150.0051.80314.67
5.6.140.0071.75114.58
5.6.130.0051.63014.81
5.6.120.0081.60914.62
5.6.110.0201.58114.64
5.6.100.0081.64014.89
5.6.90.0721.57914.76
5.6.80.0051.72314.46
5.6.70.0031.51314.65
5.6.60.0051.61814.41
5.6.50.0071.46514.61
5.6.40.0051.48514.55
5.6.30.0021.44614.50
5.6.20.0051.41614.64
5.6.10.0031.42214.61
5.6.00.0081.41114.53

preferences:
41.48 ms | 401 KiB | 5 Q