3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace Hoa\Bench { class Mark { /** * Mark ID. * * @var \Hoa\Bench\Mark string */ protected $_id = null; /** * Start time. * * @var \Hoa\Bench\Mark float */ protected $start = 0.0; /** * Stop time. * * @var \Hoa\Bench\Mark float */ protected $stop = 0.0; /** * Addition of pause time. * * @var \Hoa\Bench\Mark float */ protected $pause = 0.0; /** * Whether the mark is running. * * @var \Hoa\Bench\Mark bool */ protected $_running = false; /** * Whether the mark is in pause. * * @var \Hoa\Bench\Mark bool */ protected $_pause = false; /** * Built a mark (and set the ID). * * @access public * @param string $id The mark ID. * @return void */ public function __construct ( $id ) { $this->setId($id); return; } /** * Set the mark ID. * * @access protected * @param string $id The mark ID. * @return string */ protected function setId ( $id ) { $old = $this->_id; $this->_id = $id; return $old; } /** * Get the mark ID. * * @access public * @return string */ public function getId ( ) { return $this->_id; } /** * Start the mark. * A mark can be started if it is in pause, stopped, or if it is the first start. * Else, an exception will be thrown. * * @access public * @return \Hoa\Bench\Mark * @throw \Hoa\Bench\Exception */ public function start ( ) { if(true === $this->isRunning()) if(false === $this->isPause()) throw new Exception( 'Cannot start the %s mark, because it is running.', 0, $this->getId()); if(true === $this->isPause()) $this->pause += microtime(true) - $this->stop; else { $this->reset(); $this->start = microtime(true); } $this->_running = true; $this->_pause = false; return $this; } /** * Stop the mark. * A mark can be stopped if it is in pause, or started. Else, an exception * will be thrown (or not, according to the $silent argument). * * @access public * @param bool $silent If set to true and if the mark is not running, * no exception will be thrown. * @return \Hoa\Bench\Mark * @throw \Hoa\Bench\Exception */ public function stop ( $silent = false ) { if(false === $this->isRunning()) if(false === $silent) throw new Exception( 'Cannot stop the %s mark, because it is not running.', 1, $this->getId()); else return $this; $this->stop = microtime(true); $this->_running = false; $this->_pause = false; return $this; } /** * Reset the mark. * * @access public * @return \Hoa\Bench\Mark */ public function reset ( ) { $this->start = 0.0. $this->stop = 0.0; $this->pause = 0.0; $this->_running = false; $this->_pause = false; return $this; } /** * Pause the mark. * A mark can be in pause if it is started. Else, an exception will be * thrown (or not, according to the $silent argument). * * @access public * @param bool $silent If set to true and the mark is not running, * no exception will be throw. Idem if the mark * is in pause. * @return \Hoa\Bench\Mark * @throw \Hoa\Bench\Exception */ public function pause ( $silent = false ) { if(false === $this->isRunning()) if(false === $silent) throw new Exception( 'Cannot stop the %s mark, because it is not running.', 2, $this->getId()); else return $this; if(true === $this->isPause()) if(false === $silent) throw new Exception( 'The %s mark is still in pause. Cannot pause it again.', 3, $this->getId()); else return $this; $this->stop = microtime(true); $this->_pause = true; return $this; } /** * Get the difference between $stop and $start. * If the mark is still running (it contains the pause case), the current * microtime will be used in stay of $stop. * * @access public * @return float */ public function diff ( ) { if(false === $this->isRunning() || true === $this->isPause()) return $this->stop - $this->start - $this->pause; return microtime(true) - $this->start - $this->pause; } /** * Compare to mark. * $a op $b : return -1 if $a < $b, 0 if $a == $b, and 1 if $a > $b. We * compare the difference between $start and $stop, i.e. we call the diff() * method. * * @access public * @param \Hoa\Bench\Mark $mark The mark to compare to. * @return int */ public function compareTo ( Mark $mark ) { $a = $this->diff(); $b = $mark->diff(); if($a < $b) return -1; elseif($a == $b) return 0; else return 1; } /** * Check if the mark is running. * * @access public * @return bool */ public function isRunning ( ) { return $this->_running; } /** * Check if the mark is in pause. * * @access public * @return bool */ public function isPause ( ) { return $this->_pause; } /** * Alias of the diff() method, but return a string, not a float. * * @access public * @return string */ public function __toString ( ) { return (string) $this->diff(); } } class Bench implements \Iterator, \Countable { /** * Statistic : get the result. * * @const int */ const STAT_RESULT = 0; /** * Statistic : get the pourcent. * * @const int */ const STAT_POURCENT = 1; /** * Collection of marks. * * @var \Hoa\Bench array */ protected static $_mark = array(); /** * Collection of filters. * * @var \Hoa\Bench array */ protected $_filters = array(); /** * Get a mark. * If the mark does not exist, it will be automatically create. * * @access public * @param string $id The mark ID. * @return \Hoa\Bench\Mark * @throw \Hoa\Bench\Exception */ public function __get ( $id ) { if(true === $this->markExists($id)) return self::$_mark[$id]; $mark = new Mark($id); self::$_mark[$id] = $mark; return $mark; } /** * Check if a mark exists. * Alias of the protected markExist method. * * @access public * @param string $id The mark ID. * @return bool */ public function __isset ( $id ) { return $this->markExists($id); } /** * Destroy a mark. * * @access public * @param string $id The mark ID. * @return void */ public function __unset ( $id ) { unset(self::$_mark[$id]); return; } /** * Destroy all mark. * * @access public * @return void */ public function unsetAll ( ) { self::$_mark = array(); return; } /** * Check if a mark already exists. * * @access protected * @param string $id The mark ID. * @return bool */ protected function markExists ( $id ) { return isset(self::$_mark[$id]); } /** * Get the current mark for the iterator. * * @access public * @return \Hoa\Bench\Mark */ public function current ( ) { return current(self::$_mark); } /** * Get the current mark ID for the iterator. * * @access public * @return string */ public function key ( ) { return key(self::$_mark); } /** * Advance the internal mark collection pointer, and return the current * mark. * * @access public * @return \Hoa\Bench\Mark */ public function next ( ) { return next(self::$_mark); } /** * Rewind the internal mark collection pointer, and return the first mark. * * @access public * @return \Hoa\Bench\Mark */ public function rewind ( ) { return reset(self::$_mark); } /** * Check if there is a current element after calls the rewind or the next * methods. * * @access public * @return bool */ public function valid ( ) { if(empty(self::$_mark)) return false; $key = key(self::$_mark); $return = (next(self::$_mark) ? true : false); prev(self::$_mark); if(false === $return) { end(self::$_mark); if($key === key(self::$_mark)) $return = true; } return $return; } /** * Add a filter. * Used in the self::getStatistic() method, no in iterator. * A filter is a callable that will receive 3 values about a mark: ID, time * result, and time pourcent. The callable must return a boolean. * * @access public * @param mixed $callable Callable. * @return void */ public function filter ( $callable ) { $this->_filters[] = xcallable($callable); return $this; } /** * Return all filters. * * @access public * @return array */ public function getFilters ( ) { return $this->_filters; } /** * Get statistic. * Return an associative array : id => sub-array. The sub-array contains the * result time in second (given by the constant self::STAT_RESULT), and the * result pourcent (given by the constant self::START_POURCENT). * * @access public * @param bool $considerFilters Whether we should consider filters or * not. * @return array */ public function getStatistic ( $considerFilters = true ) { if(empty(self::$_mark)) return array(); $max = $this->getLongest()->diff(); $out = array(); foreach($this as $id => $mark) { $result = $mark->diff(); $pourcent = ($result * 100) / $max; if(true === $considerFilters) foreach($this->getFilters() as $filter) if(true !== $filter($id, $result, $pourcent)) continue 2; $out[$id] = array( self::STAT_RESULT => $result, self::STAT_POURCENT => $pourcent ); } return $out; } /** * Get the maximum, i.e. the longest mark in time. * * @access public * @return \Hoa\Bench\Mark */ public function getLongest ( ) { $max = 0; $outMark = null; foreach($this as $id => $mark) if($mark->diff() > $max) { $outMark = $mark; $max = $mark->diff(); } return $outMark; } /** * Draw statistic in text mode. * * @access public * @param int $width The graphic width. * @return string * @throw \Hoa\Bench\Exception */ public function drawStatistic ( $width = 80 ) { if(empty(self::$_mark)) return ''; if($width < 1) throw new Exception( 'The graphic width must be positive, given %d.', 0, $width); $out = null; $stats = $this->getStatistic(); $margin = 0; foreach($stats as $id => $foo) strlen($id) > $margin and $margin = strlen($id); $width = $width - $margin - 18; $format = '%-' . $margin . 's %-' . $width . 's %5dms, %5.1f%%' . "\n"; foreach($stats as $id => $stat) $out .= sprintf( $format, $id, str_repeat( '|', round(($stat[self::STAT_POURCENT] * $width) / 100) ), round(1000 * $stat[self::STAT_RESULT]), round($stat[self::STAT_POURCENT], 3) ); return $out; } /** * Count the number of mark. * * @access public * @return int */ public function count ( ) { return count(self::$_mark); } /** * Alias of drawStatistic() method. * * @access public * @return string */ public function __toString ( ) { return $this->drawStatistic(); } } } namespace { mb_internal_encoding('UTF-8'); mb_regex_encoding('UTF-8'); $bench = new Hoa\Bench\Bench(); $memory = array(); $string = str_repeat('foo', 10000); $_string = $string; $memory['substr'] = memory_get_usage(); $bench->substr->start(); while(0 < strlen($_string)) { preg_match('#^(?:foo)#u', $_string, $matches); $_string = mb_substr($_string, mb_strlen($matches[0])); } $bench->substr->stop(); $memory['substr'] = memory_get_usage() - $memory['substr']; unset($matches); unset($_string); $_string = $string; $offset = 0; $memory['offset'] = memory_get_usage(); $bench->offset->start(); while($offset < strlen($_string)) { preg_match('#(?:foo)#u', $_string, $matches, PREG_OFFSET_CAPTURE, $offset); $offset += mb_strlen($matches[0][0]); } $bench->offset->stop(); $memory['offset'] = memory_get_usage() - $memory['offset']; echo $bench; print_r($memory); }

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)
7.2.00.0101.20919.82
7.1.70.0071.17517.44
7.1.60.0101.18919.40
7.1.50.0100.84917.25
7.1.00.0030.91022.45
7.0.200.0031.25316.82
7.0.140.0100.95021.99
7.0.120.0000.91322.09
7.0.100.0100.90020.18
7.0.90.0100.88320.37
7.0.80.0030.87020.06
7.0.70.0100.77720.25
7.0.60.0100.91320.11
7.0.50.0070.79320.57
7.0.40.0100.94320.19
7.0.30.0130.90020.14
7.0.20.0100.93320.15
7.0.10.0100.90320.14
7.0.00.0070.94320.16
5.6.280.0000.95020.87
5.6.250.0030.90020.69
5.6.240.0070.89720.60
5.6.230.0000.78020.77
5.6.220.0100.76020.86
5.6.210.0100.89720.67
5.6.200.0070.91321.17
5.6.190.0070.87021.15
5.6.180.0100.77321.15
5.6.170.0130.93021.03
5.6.160.0130.90321.09
5.6.150.0100.93721.20
5.6.140.0000.94721.13
5.6.130.0000.91320.98
5.6.120.0030.92721.05
5.6.110.0070.90021.16
5.6.100.0130.92721.03
5.6.90.0070.91721.11
5.6.80.0100.87720.57
5.6.70.0130.86020.50
5.6.60.0070.92720.51
5.6.50.0030.78020.44
5.6.40.0030.87720.42
5.6.30.0070.87020.55
5.6.20.0070.82320.53
5.6.10.0100.92720.46
5.6.00.0100.93720.48
5.5.380.0070.90020.54
5.5.370.0070.91720.46
5.5.360.0070.78720.46
5.5.350.0000.92720.57
5.5.340.0300.87721.00
5.5.330.0070.94321.00
5.5.320.0100.90021.02
5.5.310.0100.93320.85
5.5.300.0030.91020.94
5.5.290.0070.98721.01
5.5.280.0070.92721.01
5.5.270.0170.89320.95
5.5.260.0030.93020.89
5.5.250.0100.86720.77
5.5.240.0100.91320.36
5.5.230.0100.90020.11
5.5.220.0030.86720.35
5.5.210.0100.94020.34
5.5.200.0030.94720.31
5.5.190.0000.71720.24
5.5.180.0030.70720.26
5.5.160.0100.91020.25
5.5.150.0130.93320.36
5.5.140.0130.91320.08
5.5.130.0000.80320.07
5.5.120.0070.90720.34
5.5.110.0030.86020.21
5.5.100.0130.90720.07
5.5.90.0000.89020.22
5.5.80.0030.83020.16
5.5.70.0030.84720.06
5.5.60.0100.91720.16
5.5.50.0030.93320.17
5.5.40.0070.91720.12
5.5.30.0100.93320.18
5.5.20.0100.89720.06
5.5.10.0070.90720.21
5.5.00.0100.93720.19
5.4.450.0070.92719.54
5.4.440.0070.92719.29
5.4.430.0030.77319.32
5.4.420.0130.96019.45
5.4.410.0170.88319.42
5.4.400.0070.91718.94
5.4.390.0130.96719.31
5.4.380.0070.92319.24
5.4.370.0100.98019.29
5.4.360.0000.85719.30
5.4.350.0000.85019.05
5.4.340.0070.70719.12
5.4.320.0070.94319.19
5.4.310.0270.91718.91
5.4.300.0170.92319.13
5.4.290.0100.92319.13
5.4.280.0100.91019.23
5.4.270.0030.90719.04
5.4.260.0130.91019.18
5.4.250.0100.80019.20
5.4.240.0170.93019.05
5.4.230.0000.94319.13
5.4.220.0030.90318.91
5.4.210.0070.89719.13
5.4.200.0130.84318.91
5.4.190.0130.88019.21
5.4.180.0070.98019.13
5.4.170.0130.92719.23
5.4.160.0100.88718.86
5.4.150.0100.90719.16
5.4.140.0070.91316.50
5.4.130.0131.07716.52
5.4.120.0071.05016.52
5.4.110.0071.04016.65
5.4.100.0001.11016.55
5.4.90.0000.87016.35
5.4.80.0000.98716.45
5.4.70.0000.83016.45
5.4.60.0000.85716.37
5.4.50.0070.97316.53
5.4.40.0070.96016.59
5.4.30.0030.88316.45
5.4.20.0070.86316.43
5.4.10.0170.98716.57
5.4.00.0070.96315.79
5.3.290.0100.93014.90
5.3.280.0030.93714.84
5.3.270.0030.93014.89
5.3.260.0100.93714.95
5.3.250.0070.94014.97
5.3.240.0030.95014.95
5.3.230.0101.01714.86
5.3.220.0030.84014.91
5.3.210.0001.02714.79
5.3.200.0070.91314.82
5.3.190.0000.77314.93
5.3.180.0000.75714.92
5.3.170.0000.75014.78
5.3.160.0100.97014.84
5.3.150.0000.95314.92
5.3.140.0030.86714.88
5.3.130.0070.97314.91
5.3.120.0070.95314.79
5.3.110.0030.94314.79
5.3.100.0030.89014.26
5.3.90.0031.03314.27
5.3.80.0030.98014.27
5.3.70.0070.98714.39
5.3.60.0000.85014.33
5.3.50.0070.98314.24
5.3.40.0000.96714.23
5.3.30.0071.00714.16
5.3.20.0031.01713.81
5.3.10.0100.95714.02
5.3.00.0070.83013.79

preferences:
37.24 ms | 400 KiB | 5 Q