[Profiler] Minimize the number of Profile writes

squash

squash
This commit is contained in:
Victor Berchet 2012-04-13 17:10:57 +02:00
parent 114bc14c21
commit 255127081a
2 changed files with 65 additions and 18 deletions

View File

@ -13,7 +13,9 @@ namespace Symfony\Component\HttpKernel\Debug;
use Symfony\Component\HttpKernel\Debug\Stopwatch; use Symfony\Component\HttpKernel\Debug\Stopwatch;
use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler; use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
@ -30,6 +32,7 @@ class ContainerAwareTraceableEventDispatcher extends ContainerAwareEventDispatch
private $called; private $called;
private $stopwatch; private $stopwatch;
private $priorities; private $priorities;
private $profiler;
/** /**
* Constructor. * Constructor.
@ -83,11 +86,18 @@ class ContainerAwareTraceableEventDispatcher extends ContainerAwareEventDispatch
case 'kernel.response': case 'kernel.response':
$token = $event->getResponse()->headers->get('X-Debug-Token'); $token = $event->getResponse()->headers->get('X-Debug-Token');
$this->stopwatch->stopSection($token); $this->stopwatch->stopSection($token);
$this->updateProfile($token); if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) {
// The profiles can only be updated once they have been created
// that is after the 'kernel.response' event of the main request
$this->updateProfiles($token, true);
}
break; break;
case 'kernel.terminate': case 'kernel.terminate':
$this->stopwatch->stopSection($token); $this->stopwatch->stopSection($token);
$this->updateProfile($token); // The children profiles have been updated by the previous 'kernel.response'
// event. Only the root profile need to be updated with the 'kernel.terminate'
// timing informations.
$this->updateProfiles($token, false);
break; break;
} }
@ -255,28 +265,41 @@ class ContainerAwareTraceableEventDispatcher extends ContainerAwareEventDispatch
} }
/** /**
* Updates the profile data. * Updates the stopwatch data in the profile hierarchy.
* *
* @param string $token Profile token * @param string $token Profile token
* @param Boolean $updateChildren Whether to update the children altogether
*/ */
private function updateProfile($token) private function updateProfiles($token, $updateChildren)
{ {
if (!$this->getContainer()->has('profiler')) { if (!$this->getContainer()->has('profiler')) {
return; return;
} }
$profiler = $this->getContainer()->get('profiler'); $this->profiler = $this->getContainer()->get('profiler');
if (!$profile = $profiler->loadProfile($token)) {
if (!$profile = $this->profiler->loadProfile($token)) {
return; return;
} }
$profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($token)); $this->saveStopwatchInfoInProfile($profile, $updateChildren);
$profiler->saveProfile($profile); }
// children /**
* Update the profiles with the timing info and saves them.
*
* @param Profile $profile The root profile
* @param Boolean $updateChildren Whether to update the children altogether
*/
private function saveStopwatchInfoInProfile(Profile $profile, $updateChildren)
{
$profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($profile->getToken()));
$this->profiler->saveProfile($profile);
if ($updateChildren) {
foreach ($profile->getChildren() as $child) { foreach ($profile->getChildren() as $child) {
$child->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($child->getToken())); $this->saveStopwatchInfoInProfile($child, true);
$profiler->saveProfile($child); }
} }
} }

View File

@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler; use Symfony\Component\HttpKernel\Profiler\Profiler;
use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\RequestMatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@ -34,6 +35,7 @@ class ProfilerListener implements EventSubscriberInterface
protected $exception; protected $exception;
protected $children; protected $children;
protected $requests; protected $requests;
protected $profiles;
/** /**
* Constructor. * Constructor.
@ -50,6 +52,7 @@ class ProfilerListener implements EventSubscriberInterface
$this->onlyException = (Boolean) $onlyException; $this->onlyException = (Boolean) $onlyException;
$this->onlyMasterRequests = (Boolean) $onlyMasterRequests; $this->onlyMasterRequests = (Boolean) $onlyMasterRequests;
$this->children = new \SplObjectStorage(); $this->children = new \SplObjectStorage();
$this->profiles = array();
} }
/** /**
@ -99,6 +102,16 @@ class ProfilerListener implements EventSubscriberInterface
return; return;
} }
$this->profiles[] = $profile;
if (null !== $exception) {
foreach ($this->profiles as $profile) {
$this->profiler->saveProfile($profile);
}
return;
}
// keep the profile as the child of its parent // keep the profile as the child of its parent
if (!$master) { if (!$master) {
array_pop($this->requests); array_pop($this->requests);
@ -109,17 +122,16 @@ class ProfilerListener implements EventSubscriberInterface
$this->children[$parent] = $profiles; $this->children[$parent] = $profiles;
} }
// store the profile and its children
if (isset($this->children[$request])) { if (isset($this->children[$request])) {
foreach ($this->children[$request] as $child) { foreach ($this->children[$request] as $child) {
$child->setParent($profile);
$profile->addChild($child); $profile->addChild($child);
$this->profiler->saveProfile($child);
} }
$this->children[$request] = array(); $this->children[$request] = array();
} }
$this->profiler->saveProfile($profile); if ($master) {
$this->saveProfiles($profile);
}
} }
static public function getSubscribedEvents() static public function getSubscribedEvents()
@ -128,9 +140,21 @@ class ProfilerListener implements EventSubscriberInterface
// kernel.request must be registered as early as possible to not break // kernel.request must be registered as early as possible to not break
// when an exception is thrown in any other kernel.request listener // when an exception is thrown in any other kernel.request listener
KernelEvents::REQUEST => array('onKernelRequest', 1024), KernelEvents::REQUEST => array('onKernelRequest', 1024),
KernelEvents::RESPONSE => array('onKernelResponse', -100), KernelEvents::RESPONSE => array('onKernelResponse', -100),
KernelEvents::EXCEPTION => 'onKernelException', KernelEvents::EXCEPTION => 'onKernelException',
); );
} }
/**
* Saves the profile hierarchy.
*
* @param Profile $profile The root profile
*/
private function saveProfiles(Profile $profile)
{
$this->profiler->saveProfile($profile);
foreach ($profile->getChildren() as $profile) {
$this->saveProfiles($profile);
}
}
} }