From 959bee839225ae8dc72ff6855718599e2e5da174 Mon Sep 17 00:00:00 2001 From: Sebastian Helzle Date: Thu, 20 Aug 2020 19:04:09 +0200 Subject: [PATCH] FEATURE: Show render metrics for cached elements This change will add the rendertime and sql querycount to the details when inspecting fusion object with a caching configuration. --- .../Aspect/CollectDebugInformationAspect.php | 4 +- Classes/Aspect/ContentCacheSegmentAspect.php | 13 ++- Classes/Aspect/RuntimeTracingAspect.php | 57 +++++++++++++ Classes/Service/RenderTimer.php | 80 +++++++++++++++++++ 4 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 Classes/Aspect/RuntimeTracingAspect.php create mode 100644 Classes/Service/RenderTimer.php diff --git a/Classes/Aspect/CollectDebugInformationAspect.php b/Classes/Aspect/CollectDebugInformationAspect.php index 74b9697..120acdd 100644 --- a/Classes/Aspect/CollectDebugInformationAspect.php +++ b/Classes/Aspect/CollectDebugInformationAspect.php @@ -137,8 +137,8 @@ public function addDebugValues(JoinPointInterface $joinPoint): string */ public function startSqlLogging(\Neos\Flow\AOP\JoinPointInterface $joinPoint): void { - $this->sqlLoggingStack = new DebugStack(); - $this->entityManager->getConfiguration()->setSQLLogger($this->sqlLoggingStack); + $this->sqlLoggingStack = new DebugStack(); + $this->entityManager->getConfiguration()->setSQLLogger($this->sqlLoggingStack); } /** diff --git a/Classes/Aspect/ContentCacheSegmentAspect.php b/Classes/Aspect/ContentCacheSegmentAspect.php index 23a99f7..8bc40a1 100644 --- a/Classes/Aspect/ContentCacheSegmentAspect.php +++ b/Classes/Aspect/ContentCacheSegmentAspect.php @@ -20,6 +20,7 @@ use Neos\Fusion\Core\Cache\ContentCache; use Neos\Fusion\FusionObjects\AbstractFusionObject; use Neos\Utility\ObjectAccess; +use t3n\Neos\Debug\Service\RenderTimer; /** * @Flow\Scope("singleton") @@ -46,6 +47,13 @@ class ContentCacheSegmentAspect */ protected $interceptedFusionObject; + /** + * @Flow\Inject + * + * @var RenderTimer + */ + protected $renderTimer; + public function injectContentCache(ContentCache $contentCache): void { $randomCacheMarker = ObjectAccess::getProperty($contentCache, 'randomCacheMarker', true); @@ -65,10 +73,13 @@ public function debuggingActive(): void public function wrapCachedSegment(JoinPointInterface $joinPoint): string { $segment = $joinPoint->getAdviceChain()->proceed($joinPoint); + $fusionPath = $joinPoint->getMethodArgument('fusionPath'); + $renderTime = $this->renderTimer->stop($fusionPath); return $this->renderCacheInfoIntoSegment($segment, [ 'mode' => static::MODE_CACHED, - 'fusionPath' => $joinPoint->getMethodArgument('fusionPath'), + 'fusionPath' => $fusionPath, + 'renderMetrics' => $renderTime, 'entryIdentifier' => $this->interceptedCacheEntryValues, 'entryTags' => $joinPoint->getMethodArgument('tags'), 'lifetime' => $joinPoint->getMethodArgument('lifetime') diff --git a/Classes/Aspect/RuntimeTracingAspect.php b/Classes/Aspect/RuntimeTracingAspect.php new file mode 100644 index 0000000..732a5ec --- /dev/null +++ b/Classes/Aspect/RuntimeTracingAspect.php @@ -0,0 +1,57 @@ +enter()) && t3n\Neos\Debug\Aspect\RuntimeTracingAspect->debuggingActive") + */ + public function onEnter(JoinPointInterface $joinPoint): void + { + $configuration = $joinPoint->getMethodArgument('configuration'); + $fusionPath = $joinPoint->getMethodArgument('fusionPath'); + + $cacheMode = $configuration['mode'] ?? null; + + if (! $cacheMode) { + return; + } + + $this->renderTimer->start($fusionPath); + } +} diff --git a/Classes/Service/RenderTimer.php b/Classes/Service/RenderTimer.php new file mode 100644 index 0000000..bf2187b --- /dev/null +++ b/Classes/Service/RenderTimer.php @@ -0,0 +1,80 @@ +entityManager->getConfiguration()->getSQLLogger(); + $queryCount = $sqlLoggingStack instanceof DebugStack ? $sqlLoggingStack->queryCount : 0; + + $this->renderMetrics[$fusionPath] = [ + 'startRenderAt' => $this->ts(), + 'sqlQueryCount' => $queryCount, + ]; + } + + /** + * Return current microtime in ms + */ + private function ts(): float + { + return microtime(true) * 1000; + } + + /** + * Stops the timer and returns the computed values + * + * @return null|mixed[] + */ + public function stop(string $fusionPath): ?array + { + if (! array_key_exists($fusionPath, $this->renderMetrics)) { + return null; + } + + $metrics = $this->renderMetrics[$fusionPath]; + $sqlLoggingStack = $this->entityManager->getConfiguration()->getSQLLogger(); + $queryCount = $sqlLoggingStack instanceof DebugStack ? $sqlLoggingStack->queryCount : 0; + + return [ + 'renderTime' => round($this->ts() - $metrics['startRenderAt'], 2) . ' ms', + 'sqlQueryCount' => $queryCount - $metrics['sqlQueryCount'], + ]; + } +}