diff --git a/_build/redirection_map b/_build/redirection_map index 75b0c28da2b..66fc6db1b47 100644 --- a/_build/redirection_map +++ b/_build/redirection_map @@ -507,3 +507,4 @@ /components/http_client /http_client /components/mailer /mailer /messenger/message-recorder messenger/dispatch_after_current_bus +/components/stopwatch https://github.com/symfony/stopwatch diff --git a/components/phpunit_bridge.rst b/components/phpunit_bridge.rst index 095a4840d64..31d5de1759b 100644 --- a/components/phpunit_bridge.rst +++ b/components/phpunit_bridge.rst @@ -477,8 +477,8 @@ If you have this kind of time-related tests:: } } -You used the :doc:`Symfony Stopwatch Component ` to -calculate the duration time of your process, here 10 seconds. However, depending +You calculated the duration time of your process using the Stopwatch utilities to +:ref:`profile Symfony applications `. However, depending on the load of the server or the processes running on your local machine, the ``$duration`` could for example be ``10.000023s`` instead of ``10s``. diff --git a/components/stopwatch.rst b/components/stopwatch.rst deleted file mode 100644 index e6e11d9c53e..00000000000 --- a/components/stopwatch.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. index:: - single: Stopwatch - single: Components; Stopwatch - -The Stopwatch Component -======================= - - The Stopwatch component provides a way to profile code. - -Installation ------------- - -.. code-block:: terminal - - $ composer require symfony/stopwatch - -.. include:: /components/require_autoload.rst.inc - -Usage ------ - -The Stopwatch component provides a consistent way to measure execution -time of certain parts of code so that you don't constantly have to parse -:phpfunction:`microtime` by yourself. Instead, use the -:class:`Symfony\\Component\\Stopwatch\\Stopwatch` class:: - - use Symfony\Component\Stopwatch\Stopwatch; - - $stopwatch = new Stopwatch(); - - // starts event named 'eventName' - $stopwatch->start('eventName'); - - // ... run your code here - - $event = $stopwatch->stop('eventName'); - // you can convert $event into a string for a quick summary - // e.g. (string) $event = '4.50 MiB - 26 ms' - -The :class:`Symfony\\Component\\Stopwatch\\StopwatchEvent` object can be retrieved -from the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::start`, -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::stop`, -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::lap` and -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::getEvent` methods. -The latter should be used when you need to retrieve the duration of an event -while it is still running. - -.. tip:: - - By default, the stopwatch truncates any sub-millisecond time measure to ``0``, - so you can't measure microseconds or nanoseconds. If you need more precision, - pass ``true`` to the ``Stopwatch`` class constructor to enable full precision:: - - $stopwatch = new Stopwatch(true); - -The stopwatch can be reset to its original state at any given time with the -:method:`Symfony\\Component\\Stopwatch\\Stopwatch::reset` method, which deletes -all the data measured so far. - -You can also provide a category name to an event:: - - $stopwatch->start('eventName', 'categoryName'); - -You can consider categories as a way of tagging events. For example, the -Symfony Profiler tool uses categories to nicely color-code different events. - -.. tip:: - - Read :ref:`this article ` to learn more about - integrating the Stopwatch component into the Symfony profiler. - -Periods -------- - -As you know from the real world, all stopwatches come with two buttons: -one to start and stop the stopwatch, and another to measure the lap time. -This is exactly what the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::lap` -method does:: - - $stopwatch = new Stopwatch(); - // starts event named 'foo' - $stopwatch->start('foo'); - // ... some code goes here - $stopwatch->lap('foo'); - // ... some code goes here - $stopwatch->lap('foo'); - // ... some other code goes here - $event = $stopwatch->stop('foo'); - -Lap information is stored as "periods" within the event. To get lap information -call:: - - $event->getPeriods(); - -In addition to periods, you can get other useful information from the event object. -For example:: - - $event->getCategory(); // returns the category the event was started in - $event->getOrigin(); // returns the event start time in milliseconds - $event->ensureStopped(); // stops all periods not already stopped - $event->getStartTime(); // returns the start time of the very first period - $event->getEndTime(); // returns the end time of the very last period - $event->getDuration(); // returns the event duration, including all periods - $event->getMemory(); // returns the max memory usage of all periods - -Sections --------- - -Sections are a way to logically split the timeline into groups. You can see -how Symfony uses sections to nicely visualize the framework lifecycle in the -Symfony Profiler tool. Here is a basic usage example using sections:: - - $stopwatch = new Stopwatch(); - - $stopwatch->openSection(); - $stopwatch->start('parsing_config_file', 'filesystem_operations'); - $stopwatch->stopSection('routing'); - - $events = $stopwatch->getSectionEvents('routing'); - -You can reopen a closed section by calling the :method:`Symfony\\Component\\Stopwatch\\Stopwatch::openSection` -method and specifying the id of the section to be reopened:: - - $stopwatch->openSection('routing'); - $stopwatch->start('building_config_tree'); - $stopwatch->stopSection('routing'); diff --git a/page_creation.rst b/page_creation.rst index 0e82596dfac..1835308804e 100644 --- a/page_creation.rst +++ b/page_creation.rst @@ -176,6 +176,8 @@ the debugging routes in the next section. You'll learn about many more commands as you continue! +.. _web-debug-toolbar: + The Web Debug Toolbar: Debugging Dream -------------------------------------- diff --git a/performance.rst b/performance.rst index 2356bd18911..ec9d44e5610 100644 --- a/performance.rst +++ b/performance.rst @@ -8,14 +8,24 @@ Symfony is fast, right out of the box. However, you can make it faster if you optimize your servers and your applications as explained in the following performance checklists. -Symfony Application Checklist ------------------------------ +Performance Checklists +---------------------- -These are the code and configuration changes that you can make in your Symfony -application to improve its performance: +Use these checklists to verify that your application and server are configured +for maximum performance: -#. :ref:`Install APCu Polyfill if your server uses APC ` -#. :ref:`Dump the service container into a single file ` +* **Symfony Application Checklist**: + + #. :ref:`Install APCu Polyfill if your server uses APC ` + +* **Production Server Checklist**: + + #. :ref:`Dump the service container into a single file ` + #. :ref:`Use the OPcache byte code cache ` + #. :ref:`Configure OPcache for maximum performance ` + #. :ref:`Don't check PHP files timestamps ` + #. :ref:`Configure the PHP realpath Cache ` + #. :ref:`Optimize Composer Autoloader ` .. _performance-install-apcu-polyfill: @@ -72,19 +82,6 @@ container into a single file, which could improve performance when using // ... $container->setParameter('container.dumper.inline_factories', true); -Production Server Checklist ---------------------------- - -These are the changes that you can make in your production server to improve -performance when running Symfony applications: - -#. :ref:`Use the OPcache byte code cache ` -#. :ref:`Use the OPcache class preloading ` -#. :ref:`Configure OPcache for maximum performance ` -#. :ref:`Don't check PHP files timestamps ` -#. :ref:`Configure the PHP realpath Cache ` -#. :ref:`Optimize Composer Autoloader ` - .. _performance-use-opcache: Use the OPcache Byte Code Cache @@ -212,6 +209,120 @@ deployment process too): used in your application and prevents Composer from scanning the file system for classes that are not found in the class map. (see: `Composer's autoloader optimization`_). +.. _profiling-applications: + +Profiling Applications +---------------------- + +`Blackfire`_ is the best tool to profile and optimize performance of Symfony +applications during development, test and production. It's a commercial service, +but provides free features that you can use to find bottlenecks in your projects. + +Symfony provides a basic performance profiler in the development +:ref:`config environment `. Click on the "time panel" +of the :ref:`web debug toolbar ` to see how much time Symfony +spent on tasks such as making database queries and rendering templates. + +Custom Profiling +~~~~~~~~~~~~~~~~ + +You can measure the execution time and memory consumption of your own code and +display the result in the Symfony profiler thanks to the `Stopwatch component`_. + +When using :ref:`autowiring `, type-hint any controller or +service argument with the :class:`Symfony\\Component\\Stopwatch\\Stopwatch` class +and Symfony will inject the ``debug.stopwatch`` service:: + + use Symfony\Component\Stopwatch\Stopwatch; + + class DataExporter + { + private $stopwatch; + + public function __construct(Stopwatch $stopwatch) + { + $this->stopwatch = $stopwatch; + } + + public function export() + { + // the argument is the name of the "profiling event" + $this->stopwatch->start('export-data'); + + // ...do things to export data... + + // reset the stopwatch to delete all the data measured so far + // $this->stopwatch->reset(); + + $this->stopwatch->stop('export-data'); + } + } + +If the request calls this service during its execution, you'll see a new +event called ``export-data`` in the Symfony profiler. + +The ``start()``, ``stop()`` and ``getEvent()`` methods return a +:class:`Symfony\\Component\\Stopwatch\\StopwatchEvent` object that provides +information about the current event, even while it's still running. This +object can be converted to a string for a quick summary:: + + // ... + dump((string) $this->stopwatch->getEvent()); // dumps e.g. '4.50 MiB - 26 ms' + +You can also profile your template code with the :ref:`stopwatch Twig tag `: + +.. code-block:: twig + + {% stopwatch 'render-blog-posts' %} + {% for post in blog_posts%} + {# ... #} + {% endfor %} + {% endstopwatch %} + +Profiling Categories +.................... + +Use the second optional argument of the ``start()`` method to define the +category or tag of the event. This helps keep events organized by type:: + + $this->stopwatch->start('export-data', 'export'); + +Profiling Periods +................. + +A `real-world stopwatch`_ not only includes the start/stop button but also a +"lap button" to measure each partial lap. This is exactly what the ``lap()`` +method does, which stops an event and then restarts it immediately:: + + $this->stopwatch->start('process-data-records', 'export'); + + foreach ($records as $record) { + // ... some code goes here + $this->stopwatch->lap('process-data-records'); + } + + $event = $this->stopwatch->stop('process-data-records'); + // $event->getDuration(), $event->getMemory(), etc. + + // Lap information is stored as "periods" within the event: + // $event->getPeriods(); + +Profiling Sections +.................. + +Sections are a way to split the profile timeline into groups. Example:: + + $this->stopwatch->openSection(); + $this->stopwatch->start('validating-file', 'validation'); + $this->stopwatch->stopSection('parsing'); + + $events = $this->stopwatch->getSectionEvents('parsing'); + + // later you can reopen a section passing its name to the openSection() method + $this->stopwatch->openSection('parsing'); + $this->stopwatch->start('processing-file'); + $this->stopwatch->stopSection('parsing'); + Learn more ---------- @@ -225,3 +336,6 @@ Learn more .. _`APCu PHP functions`: https://www.php.net/manual/en/ref.apcu.php .. _`cachetool`: https://github.com/gordalina/cachetool .. _`open_basedir`: https://www.php.net/manual/ini.core.php#ini.open-basedir +.. _`Blackfire`: https://blackfire.io/docs/introduction?utm_source=symfony&utm_medium=symfonycom_docs&utm_campaign=performance +.. _`Stopwatch component`: https://symfony.com/components/Stopwatch +.. _`real-world stopwatch`: https://en.wikipedia.org/wiki/Stopwatch diff --git a/profiler.rst b/profiler.rst index cb8ae679d99..4946ad4ac8a 100644 --- a/profiler.rst +++ b/profiler.rst @@ -98,23 +98,8 @@ Timing the Execution of the Application --------------------------------------- If you want to measure the time some tasks take in your application, there's no -need to create a custom data collector. Instead, use the `Stopwatch component`_ -which provides utilities to profile code and displays the results on the -"Performance" panel of the Profiler web interface. - -When using :ref:`autowiring `, type-hint any argument with -the :class:`Symfony\\Component\\Stopwatch\\Stopwatch` class and Symfony will -inject the Stopwatch service. Then, use the ``start()``, ``lap()`` and -``stop()`` methods to measure time:: - - // a user signs up and the timer starts... - $stopwatch->start('user-sign-up'); - - // ...do things to sign up the user... - $stopwatch->lap('user-sign-up'); - - // ...the sign up process is finished - $stopwatch->stop('user-sign-up'); +need to create a custom data collector. Instead, use the built-in utilities to +:ref:`profile Symfony applications `. .. tip:: @@ -229,5 +214,4 @@ event:: profiler/data_collector .. _`Single-page applications`: https://en.wikipedia.org/wiki/Single-page_application -.. _`Stopwatch component`: https://symfony.com/components/Stopwatch .. _`Blackfire`: https://blackfire.io/docs/introduction?utm_source=symfony&utm_medium=symfonycom_docs&utm_campaign=profiler diff --git a/reference/twig_reference.rst b/reference/twig_reference.rst index 84e52b0cd35..f44f5043d92 100644 --- a/reference/twig_reference.rst +++ b/reference/twig_reference.rst @@ -601,15 +601,17 @@ trans_default_domain This will set the default domain in the current template. +.. _reference-twig-tag-stopwatch: + stopwatch ~~~~~~~~~ .. code-block:: twig - {% stopwatch 'name' %}...{% endstopwatch %} + {% stopwatch 'event_name' %}...{% endstopwatch %} -This will time the run time of the code inside it and put that on the timeline -of the WebProfilerBundle. +This measures the time and memory used to execute some code in the template and +displays it in the Symfony profiler. See :ref:`how to profile Symfony applications `. .. _reference-twig-tests: