Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con
$loader->load('debug_prod.xml');

if (class_exists(Stopwatch::class)) {
$container->register('debug.stopwatch', Stopwatch::class);
$container->register('debug.stopwatch', Stopwatch::class)->addArgument(true);
$container->setAlias(Stopwatch::class, 'debug.stopwatch');
}

Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Stopwatch/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ CHANGELOG
-----

* added the `Stopwatch::reset()` method
* allowed to measure sub-millisecond times by introducing an argument to the
constructor of `Stopwatch`
15 changes: 11 additions & 4 deletions src/Symfony/Component/Stopwatch/Section.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ class Section
*/
private $origin;

/**
* @var bool
*/
private $morePrecision;

/**
* @var string
*/
Expand All @@ -41,11 +46,13 @@ class Section
/**
* Constructor.
*
* @param float|null $origin Set the origin of the events in this section, use null to set their origin to their start time
* @param float|null $origin Set the origin of the events in this section, use null to set their origin to their start time
* @param bool $morePrecision If true, time is stored as float to keep the original microsecond precision
*/
public function __construct($origin = null)
public function __construct($origin = null, $morePrecision = false)
{
$this->origin = is_numeric($origin) ? $origin : null;
$this->morePrecision = $morePrecision;
}

/**
Expand Down Expand Up @@ -74,7 +81,7 @@ public function get($id)
public function open($id)
{
if (null === $session = $this->get($id)) {
$session = $this->children[] = new self(microtime(true) * 1000);
$session = $this->children[] = new self(microtime(true) * 1000, $this->morePrecision);
}

return $session;
Expand Down Expand Up @@ -113,7 +120,7 @@ public function setId($id)
public function startEvent($name, $category)
{
if (!isset($this->events[$name])) {
$this->events[$name] = new StopwatchEvent($this->origin ?: microtime(true) * 1000, $category);
$this->events[$name] = new StopwatchEvent($this->origin ?: microtime(true) * 1000, $category, $this->morePrecision);
}

return $this->events[$name]->start();
Expand Down
13 changes: 11 additions & 2 deletions src/Symfony/Component/Stopwatch/Stopwatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
*/
class Stopwatch
{
/**
* @var bool
*/
private $morePrecision;

/**
* @var Section[]
*/
Expand All @@ -28,9 +33,13 @@ class Stopwatch
*/
private $activeSections;

public function __construct()
/**
* @param bool $morePrecision If true, time is stored as float to keep the original microsecond precision
*/
public function __construct($morePrecision = false)
{
$this->reset();
$this->morePrecision = $morePrecision;
}

/**
Expand Down Expand Up @@ -162,6 +171,6 @@ public function getSectionEvents($id)
*/
public function reset()
{
$this->sections = $this->activeSections = array('__root__' => new Section('__root__'));
$this->sections = $this->activeSections = array('__root__' => new Section('__root__', $this->morePrecision));
}
}
17 changes: 12 additions & 5 deletions src/Symfony/Component/Stopwatch/StopwatchEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ class StopwatchEvent
*/
private $category;

/**
* @var bool
*/
private $morePrecision;

/**
* @var float[]
*/
Expand All @@ -41,15 +46,17 @@ class StopwatchEvent
/**
* Constructor.
*
* @param float $origin The origin time in milliseconds
* @param string|null $category The event category or null to use the default
* @param float $origin The origin time in milliseconds
* @param string|null $category The event category or null to use the default
* @param bool $morePrecision If true, time is stored as float to keep the original microsecond precision
*
* @throws \InvalidArgumentException When the raw time is not valid
*/
public function __construct($origin, $category = null)
public function __construct($origin, $category = null, $morePrecision = false)
{
$this->origin = $this->formatTime($origin);
$this->category = is_string($category) ? $category : 'default';
$this->morePrecision = $morePrecision;
}

/**
Expand Down Expand Up @@ -97,7 +104,7 @@ public function stop()
throw new \LogicException('stop() called but start() has not been called before.');
}

$this->periods[] = new StopwatchPeriod(array_pop($this->started), $this->getNow());
$this->periods[] = new StopwatchPeriod(array_pop($this->started), $this->getNow(), $this->morePrecision);

return $this;
}
Expand Down Expand Up @@ -177,7 +184,7 @@ public function getDuration()

for ($i = 0; $i < $left; ++$i) {
$index = $stopped + $i;
$periods[] = new StopwatchPeriod($this->started[$index], $this->getNow());
$periods[] = new StopwatchPeriod($this->started[$index], $this->getNow(), $this->morePrecision);
}

$total = 0;
Expand Down
17 changes: 9 additions & 8 deletions src/Symfony/Component/Stopwatch/StopwatchPeriod.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@ class StopwatchPeriod
/**
* Constructor.
*
* @param int $start The relative time of the start of the period (in milliseconds)
* @param int $end The relative time of the end of the period (in milliseconds)
* @param int|float $start The relative time of the start of the period (in milliseconds)
* @param int|float $end The relative time of the end of the period (in milliseconds)
* @param bool $morePrecision If true, time is stored as float to keep the original microsecond precision
*/
public function __construct($start, $end)
public function __construct($start, $end, $morePrecision = false)
{
$this->start = (int) $start;
$this->end = (int) $end;
$this->start = $morePrecision ? (float) $start : (int) $start;
$this->end = $morePrecision ? (float) $end : (int) $end;
$this->memory = memory_get_usage(true);
}

/**
* Gets the relative time of the start of the period.
*
* @return int The time (in milliseconds)
* @return int|float The time (in milliseconds)
*/
public function getStartTime()
{
Expand All @@ -48,7 +49,7 @@ public function getStartTime()
/**
* Gets the relative time of the end of the period.
*
* @return int The time (in milliseconds)
* @return int|float The time (in milliseconds)
*/
public function getEndTime()
{
Expand All @@ -58,7 +59,7 @@ public function getEndTime()
/**
* Gets the time spent in this period.
*
* @return int The period duration (in milliseconds)
* @return int|float The period duration (in milliseconds)
*/
public function getDuration()
{
Expand Down
67 changes: 67 additions & 0 deletions src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Stopwatch\Tests;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Stopwatch\StopwatchPeriod;

class StopwatchPeriodTest extends TestCase
{
/**
* @dataProvider provideTimeValues
*/
public function testGetStartTime($start, $useMorePrecision, $expected)
{
$period = new StopwatchPeriod($start, $start, $useMorePrecision);
$this->assertSame($expected, $period->getStartTime());
}

/**
* @dataProvider provideTimeValues
*/
public function testGetEndTime($end, $useMorePrecision, $expected)
{
$period = new StopwatchPeriod($end, $end, $useMorePrecision);
$this->assertSame($expected, $period->getEndTime());
}

/**
* @dataProvider provideDurationValues
*/
public function testGetDuration($start, $end, $useMorePrecision, $duration)
{
$period = new StopwatchPeriod($start, $end, $useMorePrecision);
$this->assertSame($duration, $period->getDuration());
}

public function provideTimeValues()
{
yield array(0, false, 0);
yield array(0, true, 0.0);
yield array(0.0, false, 0);
yield array(0.0, true, 0.0);
yield array(2.71, false, 2);
yield array(2.71, true, 2.71);
}

public function provideDurationValues()
{
yield array(0, 0, false, 0);
yield array(0, 0, true, 0.0);
yield array(0.0, 0.0, false, 0);
yield array(0.0, 0.0, true, 0.0);
yield array(2, 3.14, false, 1);
yield array(2, 3.14, true, 1.14);
yield array(2.71, 3.14, false, 1);
yield array(2.71, 3.14, true, 0.43);
}
}