Download project

This commit is contained in:
Roman Pyrih
2024-11-20 09:09:44 +01:00
parent 547a138d6a
commit 5ff041757f
40737 changed files with 7766183 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
CHANGELOG
=========
5.2
---
* Add `name` argument to the `StopWatchEvent` constructor, accessible via a new `StopwatchEvent::getName()`
5.0.0
-----
* Removed support for passing `null` as 1st (`$id`) argument of `Section::get()` method, pass a valid child section identifier instead.
4.4.0
-----
* Deprecated passing `null` as 1st (`$id`) argument of `Section::get()` method, pass a valid child section identifier instead.
3.4.0
-----
* added the `Stopwatch::reset()` method
* allowed to measure sub-millisecond times by introducing an argument to the
constructor of `Stopwatch`

View File

@@ -0,0 +1,19 @@
Copyright (c) 2004-present Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,42 @@
Stopwatch Component
===================
The Stopwatch component provides a way to profile code.
Getting Started
---------------
```
$ composer require symfony/stopwatch
```
```php
use Symfony\Component\Stopwatch\Stopwatch;
$stopwatch = new Stopwatch();
// optionally group events into sections (e.g. phases of the execution)
$stopwatch->openSection();
// starts event named 'eventName'
$stopwatch->start('eventName');
// ... run your code here
// optionally, start a new "lap" time
$stopwatch->lap('foo');
// ... run your code here
$event = $stopwatch->stop('eventName');
$stopwatch->stopSection('phase_1');
```
Resources
---------
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -0,0 +1,163 @@
<?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;
/**
* Stopwatch section.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Section
{
/**
* @var StopwatchEvent[]
*/
private $events = [];
/**
* @var float|null
*/
private $origin;
/**
* @var bool
*/
private $morePrecision;
/**
* @var string
*/
private $id;
/**
* @var Section[]
*/
private $children = [];
/**
* @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(?float $origin = null, bool $morePrecision = \false)
{
$this->origin = $origin;
$this->morePrecision = $morePrecision;
}
/**
* Returns the child section.
*
* @return self|null
*/
public function get(string $id)
{
foreach ($this->children as $child) {
if ($id === $child->getId()) {
return $child;
}
}
return null;
}
/**
* Creates or re-opens a child section.
*
* @param string|null $id Null to create a new section, the identifier to re-open an existing one
*
* @return self
*/
public function open(?string $id)
{
if (null === $id || null === ($session = $this->get($id))) {
$session = $this->children[] = new self(\microtime(\true) * 1000, $this->morePrecision);
}
return $session;
}
/**
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* Sets the session identifier.
*
* @return $this
*/
public function setId(string $id)
{
$this->id = $id;
return $this;
}
/**
* Starts an event.
*
* @return StopwatchEvent
*/
public function startEvent(string $name, ?string $category)
{
if (!isset($this->events[$name])) {
$this->events[$name] = new \Symfony\Component\Stopwatch\StopwatchEvent($this->origin ?: \microtime(\true) * 1000, $category, $this->morePrecision, $name);
}
return $this->events[$name]->start();
}
/**
* Checks if the event was started.
*
* @return bool
*/
public function isEventStarted(string $name)
{
return isset($this->events[$name]) && $this->events[$name]->isStarted();
}
/**
* Stops an event.
*
* @return StopwatchEvent
*
* @throws \LogicException When the event has not been started
*/
public function stopEvent(string $name)
{
if (!isset($this->events[$name])) {
throw new \LogicException(\sprintf('Event "%s" is not started.', $name));
}
return $this->events[$name]->stop();
}
/**
* Stops then restarts an event.
*
* @return StopwatchEvent
*
* @throws \LogicException When the event has not been started
*/
public function lap(string $name)
{
return $this->stopEvent($name)->start();
}
/**
* Returns a specific event by name.
*
* @return StopwatchEvent
*
* @throws \LogicException When the event is not known
*/
public function getEvent(string $name)
{
if (!isset($this->events[$name])) {
throw new \LogicException(\sprintf('Event "%s" is not known.', $name));
}
return $this->events[$name];
}
/**
* Returns the events from this section.
*
* @return StopwatchEvent[]
*/
public function getEvents()
{
return $this->events;
}
}

View File

@@ -0,0 +1,146 @@
<?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;
use Symfony\Contracts\Service\ResetInterface;
// Help opcache.preload discover always-needed symbols
\class_exists(\Symfony\Component\Stopwatch\Section::class);
/**
* Stopwatch provides a way to profile code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Stopwatch implements ResetInterface
{
/**
* @var bool
*/
private $morePrecision;
/**
* @var Section[]
*/
private $sections;
/**
* @var Section[]
*/
private $activeSections;
/**
* @param bool $morePrecision If true, time is stored as float to keep the original microsecond precision
*/
public function __construct(bool $morePrecision = \false)
{
$this->morePrecision = $morePrecision;
$this->reset();
}
/**
* @return Section[]
*/
public function getSections()
{
return $this->sections;
}
/**
* Creates a new section or re-opens an existing section.
*
* @param string|null $id The id of the session to re-open, null to create a new one
*
* @throws \LogicException When the section to re-open is not reachable
*/
public function openSection(?string $id = null)
{
$current = \end($this->activeSections);
if (null !== $id && null === $current->get($id)) {
throw new \LogicException(\sprintf('The section "%s" has been started at an other level and cannot be opened.', $id));
}
$this->start('__section__.child', 'section');
$this->activeSections[] = $current->open($id);
$this->start('__section__');
}
/**
* Stops the last started section.
*
* The id parameter is used to retrieve the events from this section.
*
* @see getSectionEvents()
*
* @throws \LogicException When there's no started section to be stopped
*/
public function stopSection(string $id)
{
$this->stop('__section__');
if (1 == \count($this->activeSections)) {
throw new \LogicException('There is no started section to stop.');
}
$this->sections[$id] = \array_pop($this->activeSections)->setId($id);
$this->stop('__section__.child');
}
/**
* Starts an event.
*
* @return StopwatchEvent
*/
public function start(string $name, ?string $category = null)
{
return \end($this->activeSections)->startEvent($name, $category);
}
/**
* Checks if the event was started.
*
* @return bool
*/
public function isStarted(string $name)
{
return \end($this->activeSections)->isEventStarted($name);
}
/**
* Stops an event.
*
* @return StopwatchEvent
*/
public function stop(string $name)
{
return \end($this->activeSections)->stopEvent($name);
}
/**
* Stops then restarts an event.
*
* @return StopwatchEvent
*/
public function lap(string $name)
{
return \end($this->activeSections)->stopEvent($name)->start();
}
/**
* Returns a specific event by name.
*
* @return StopwatchEvent
*/
public function getEvent(string $name)
{
return \end($this->activeSections)->getEvent($name);
}
/**
* Gets all events for a given section.
*
* @return StopwatchEvent[]
*/
public function getSectionEvents(string $id)
{
return isset($this->sections[$id]) ? $this->sections[$id]->getEvents() : [];
}
/**
* Resets the stopwatch to its original state.
*/
public function reset()
{
$this->sections = $this->activeSections = ['__root__' => new \Symfony\Component\Stopwatch\Section(null, $this->morePrecision)];
}
}

View File

@@ -0,0 +1,225 @@
<?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;
/**
* Represents an Event managed by Stopwatch.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class StopwatchEvent
{
/**
* @var StopwatchPeriod[]
*/
private $periods = [];
/**
* @var float
*/
private $origin;
/**
* @var string
*/
private $category;
/**
* @var bool
*/
private $morePrecision;
/**
* @var float[]
*/
private $started = [];
/**
* @var string
*/
private $name;
/**
* @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
* @param string|null $name The event name or null to define the name as default
*
* @throws \InvalidArgumentException When the raw time is not valid
*/
public function __construct(float $origin, ?string $category = null, bool $morePrecision = \false, ?string $name = null)
{
$this->origin = $this->formatTime($origin);
$this->category = \is_string($category) ? $category : 'default';
$this->morePrecision = $morePrecision;
$this->name = $name ?? 'default';
}
/**
* Gets the category.
*
* @return string
*/
public function getCategory()
{
return $this->category;
}
/**
* Gets the origin in milliseconds.
*
* @return float
*/
public function getOrigin()
{
return $this->origin;
}
/**
* Starts a new event period.
*
* @return $this
*/
public function start()
{
$this->started[] = $this->getNow();
return $this;
}
/**
* Stops the last started event period.
*
* @return $this
*
* @throws \LogicException When stop() is called without a matching call to start()
*/
public function stop()
{
if (!\count($this->started)) {
throw new \LogicException('stop() called but start() has not been called before.');
}
$this->periods[] = new \Symfony\Component\Stopwatch\StopwatchPeriod(\array_pop($this->started), $this->getNow(), $this->morePrecision);
return $this;
}
/**
* Checks if the event was started.
*
* @return bool
*/
public function isStarted()
{
return !empty($this->started);
}
/**
* Stops the current period and then starts a new one.
*
* @return $this
*/
public function lap()
{
return $this->stop()->start();
}
/**
* Stops all non already stopped periods.
*/
public function ensureStopped()
{
while (\count($this->started)) {
$this->stop();
}
}
/**
* Gets all event periods.
*
* @return StopwatchPeriod[]
*/
public function getPeriods()
{
return $this->periods;
}
/**
* Gets the relative time of the start of the first period in milliseconds.
*
* @return int|float
*/
public function getStartTime()
{
if (isset($this->periods[0])) {
return $this->periods[0]->getStartTime();
}
if ($this->started) {
return $this->started[0];
}
return 0;
}
/**
* Gets the relative time of the end of the last period in milliseconds.
*
* @return int|float
*/
public function getEndTime()
{
$count = \count($this->periods);
return $count ? $this->periods[$count - 1]->getEndTime() : 0;
}
/**
* Gets the duration of the events in milliseconds (including all periods).
*
* @return int|float
*/
public function getDuration()
{
$periods = $this->periods;
$left = \count($this->started);
for ($i = $left - 1; $i >= 0; --$i) {
$periods[] = new \Symfony\Component\Stopwatch\StopwatchPeriod($this->started[$i], $this->getNow(), $this->morePrecision);
}
$total = 0;
foreach ($periods as $period) {
$total += $period->getDuration();
}
return $total;
}
/**
* Gets the max memory usage of all periods in bytes.
*
* @return int
*/
public function getMemory()
{
$memory = 0;
foreach ($this->periods as $period) {
if ($period->getMemory() > $memory) {
$memory = $period->getMemory();
}
}
return $memory;
}
/**
* Return the current time relative to origin in milliseconds.
*
* @return float
*/
protected function getNow()
{
return $this->formatTime(\microtime(\true) * 1000 - $this->origin);
}
/**
* Formats a time.
*
* @throws \InvalidArgumentException When the raw time is not valid
*/
private function formatTime(float $time) : float
{
return \round($time, 1);
}
/**
* Gets the event name.
*/
public function getName() : string
{
return $this->name;
}
public function __toString() : string
{
return \sprintf('%s/%s: %.2F MiB - %d ms', $this->getCategory(), $this->getName(), $this->getMemory() / 1024 / 1024, $this->getDuration());
}
}

View File

@@ -0,0 +1,74 @@
<?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;
/**
* Represents an Period for an Event.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class StopwatchPeriod
{
private $start;
private $end;
private $memory;
/**
* @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, bool $morePrecision = \false)
{
$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 in milliseconds.
*
* @return int|float
*/
public function getStartTime()
{
return $this->start;
}
/**
* Gets the relative time of the end of the period in milliseconds.
*
* @return int|float
*/
public function getEndTime()
{
return $this->end;
}
/**
* Gets the time spent in this period in milliseconds.
*
* @return int|float
*/
public function getDuration()
{
return $this->end - $this->start;
}
/**
* Gets the memory usage in bytes.
*
* @return int
*/
public function getMemory()
{
return $this->memory;
}
public function __toString() : string
{
return \sprintf('%.2F MiB - %d ms', $this->getMemory() / 1024 / 1024, $this->getDuration());
}
}

View File

@@ -0,0 +1,31 @@
{
"name": "symfony\/stopwatch",
"type": "library",
"description": "Provides a way to profile code",
"keywords": [],
"homepage": "https:\/\/symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https:\/\/symfony.com\/contributors"
}
],
"require": {
"php": ">=7.2.5",
"symfony\/service-contracts": "^1|^2|^3"
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
},
"exclude-from-classmap": [
"\/Tests\/"
]
},
"minimum-stability": "dev"
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;