Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Profiler Extension #19

Merged
merged 9 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ services:

Neusta\Pimcore\FixtureBundle\ReferenceRepository\:
resource: '../src/ReferenceRepository/*'

Neusta\Pimcore\FixtureBundle\Profiler\:
resource: '../src/Profiler/*'
2 changes: 0 additions & 2 deletions src/EventListener/PimcoreLoadOptimization.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ public function beforeCommand(): void

$this->originalSqlLogger = Db::getConnection()->getConfiguration()->getSQLLogger();
Db::getConnection()->getConfiguration()->setSQLLogger(null);

$this->profilerDisabler->disable();
}

public function afterCommand(): void
Expand Down
50 changes: 50 additions & 0 deletions src/Profiler/DataCollector/FixtureLoaderCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\DataCollector;

use Neusta\Pimcore\FixtureBundle\Profiler\FixtureReference\FixtureReference;
use Neusta\Pimcore\FixtureBundle\Profiler\FixtureReference\FixtureReferenceResolver;
use Neusta\Pimcore\FixtureBundle\Profiler\PerformanceInfo\PerformanceInfo;
use Neusta\Pimcore\FixtureBundle\Profiler\Timing\TimingCollector;
use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class FixtureLoaderCollector extends AbstractDataCollector
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
public function __construct(
private readonly FixtureReferenceResolver $fixtureReferenceResolver,
private readonly TimingCollector $timingCollector,
) {
}

public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
$this->data['timings'] = $this->timingCollector->getAll();

$this->data['references'] = $this->fixtureReferenceResolver->getRootReferences();
}

public static function getTemplate(): ?string
{
return '@NeustaPimcoreFixture/data_collector/template.html.twig';
}

public function getDependencyFreeFixtures(): array
{
return $this->data['references'];
}

public function getTiming(FixtureReference $fixtureReference): PerformanceInfo
{
return $this->data['timings'][$fixtureReference->getName()];
}

/**
* @return array<class-string, PerformanceInfo>
*/
public function getTimings(): array
{
return $this->data['timings'];
}
}
36 changes: 36 additions & 0 deletions src/Profiler/EventListener/FixtureDependencyGraphSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\EventListener;

use Neusta\Pimcore\FixtureBundle\Event\AfterLoadFixtures;
use Neusta\Pimcore\FixtureBundle\Event\BeforeExecuteFixture;
use Neusta\Pimcore\FixtureBundle\Profiler\FixtureReference\FixtureReferenceResolver;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class FixtureDependencyGraphSubscriber implements EventSubscriberInterface
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
private array $loadedFixtures = [];

public function __construct(
private readonly FixtureReferenceResolver $fixtureReferenceResolver,
) {
}

public static function getSubscribedEvents(): array
{
return [
BeforeExecuteFixture::class => ['beforeExecuteFixture', 10],
AfterLoadFixtures::class => 'afterLoadFixtures',
];
}

public function beforeExecuteFixture(BeforeExecuteFixture $event): void
{
$this->loadedFixtures[] = $event->fixture;
}

public function afterLoadFixtures(): void
{
$this->fixtureReferenceResolver->setFixtures($this->loadedFixtures);
}
}
38 changes: 38 additions & 0 deletions src/Profiler/EventListener/TimingSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\EventListener;

use Neusta\Pimcore\FixtureBundle\Event\AfterExecuteFixture;
use Neusta\Pimcore\FixtureBundle\Event\BeforeExecuteFixture;
use Neusta\Pimcore\FixtureBundle\Profiler\Timing\Timing;
use Neusta\Pimcore\FixtureBundle\Profiler\Timing\TimingCollector;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class TimingSubscriber implements EventSubscriberInterface
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
public function __construct(
private readonly Timing $timing,
private readonly TimingCollector $timingCollector,
) {
}

public static function getSubscribedEvents(): array
{
return [
BeforeExecuteFixture::class => 'beforeExecuteFixture',
AfterExecuteFixture::class => 'afterExecuteFixture',
];
}

public function beforeExecuteFixture(BeforeExecuteFixture $event): void
{
$this->timing->beforeExecuteFixture($event->fixture);
}

public function afterExecuteFixture(AfterExecuteFixture $event): void
{
$this->timing->afterExecuteFixture($event->fixture);

$this->timingCollector->add($event->fixture, $this->timing->getPerformanceInfo($event->fixture));
}
}
58 changes: 58 additions & 0 deletions src/Profiler/FixtureReference/FixtureReference.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\FixtureReference;

use Neusta\Pimcore\FixtureBundle\Fixture\Fixture;

class FixtureReference
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var class-string */
private string $fixtureFqcn;
/** @var list<FixtureReference> */
private array $dependencies = [];
/** @var list<FixtureReference> */
private array $dependants = [];

public function __construct(Fixture $fixture)
{
$this->fixtureFqcn = get_class($fixture);
}

/**
* @return class-string
*/
public function getName(): string
{
return $this->fixtureFqcn;
}

public function addDependencyReference(FixtureReference $dependency): void
{
$this->dependencies[] = $dependency;
}

public function addDependantReference(FixtureReference $fixtureReference): void
{
$this->dependants[] = $fixtureReference;
}

public function getDependencies(): array
{
return $this->dependencies;
}

public function hasDependencies(): bool
{
return !empty($this->dependencies);
}

public function getDependants(): array
{
return $this->dependants;
}

public function hasDependants(): bool
{
return !empty($this->dependants);
}
}
101 changes: 101 additions & 0 deletions src/Profiler/FixtureReference/FixtureReferenceResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\FixtureReference;

use Neusta\Pimcore\FixtureBundle\Fixture\Fixture;
use Neusta\Pimcore\FixtureBundle\Fixture\HasDependencies;

class FixtureReferenceResolver
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var array<class-string, FixtureReference> */
private array $allReferences;
/** @var list<FixtureReference> */
private array $rootReferences;

/**
* @param array<Fixture> $loadedFixtures
* @return void
*/
public function setFixtures(array $loadedFixtures): void
{
$this->initAllReferences($loadedFixtures);
$this->resolveDependencies($this->createIndexedListOfFixtures($loadedFixtures));
$this->collectRootReferences();
}

private function initAllReferences(array $loadedFixtures): void
{
$this->allReferences = [];

foreach ($loadedFixtures as $fixture) {
$fixtureReference = new FixtureReference($fixture);
$this->allReferences[$fixtureReference->getName()] = $fixtureReference;
}
}

/**
* @param array<Fixture> $loadedFixtures
* @return array<class-string, Fixture>
*/
private function createIndexedListOfFixtures(array $loadedFixtures): array
{
$indexedList = [];

foreach ($loadedFixtures as $fixture) {
$indexedList[get_class($fixture)] = $fixture;
}

return $indexedList;
}

/**
* @param array<class-string, Fixture> $indexedListOfFixtures
* @return void
*/
private function resolveDependencies(array $indexedListOfFixtures): void
{
foreach ($this->allReferences as $name => $reference) {
$this->collect($reference, $indexedListOfFixtures[$name]);
}
}

private function collect(FixtureReference $fixtureReference, Fixture $fixture): void
{
if (!$fixture instanceof HasDependencies) {
return;
}

foreach ($fixture->getDependencies() as $dependencyFixtureFqcn) {
$dependencyReference = $this->allReferences[$dependencyFixtureFqcn];
$fixtureReference->addDependencyReference($dependencyReference);
$dependencyReference->addDependantReference($fixtureReference);
}
}

private function collectRootReferences(): void
{
$this->rootReferences = [];

foreach ($this->allReferences as $reference) {
if (!$reference->hasDependants()) {
$this->rootReferences[] = $reference;
}
}
}

/**
* @return array<class-string, FixtureReference>
*/
public function getAllReferences(): array
{
return $this->allReferences;
}

/**
* @return list<FixtureReference>
*/
public function getRootReferences(): array
{
return $this->rootReferences;
}
}
12 changes: 12 additions & 0 deletions src/Profiler/PerformanceInfo/PerformanceInfo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\PerformanceInfo;

class PerformanceInfo
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
public function __construct(
public readonly float $duration,
public readonly int $memory,
) {
}
}
54 changes: 54 additions & 0 deletions src/Profiler/Timing/Timing.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\Timing;

use Neusta\Pimcore\FixtureBundle\Fixture\Fixture;
use Neusta\Pimcore\FixtureBundle\Profiler\PerformanceInfo\PerformanceInfo;
use Symfony\Component\Stopwatch\Stopwatch;

class Timing
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
private const STOPWATCH_NAME_PREFIX = 'fixture:';
private const STOPWATCH_CATEGORY = 'execute';

public function __construct(
private readonly Stopwatch $stopwatch,
) {
}

public function beforeExecuteFixture(Fixture $fixture): void
{
$this->stopwatch->start($this->stopWatchName($fixture), self::STOPWATCH_CATEGORY);
}

public function afterExecuteFixture(Fixture $fixture): void
{
$this->stopwatch->stop($this->stopWatchName($fixture));
}

private function stopWatchName(Fixture $fixture): string
{
$fixtureName = (new \ReflectionClass($fixture))->getShortName();

return sprintf(
'%s%s',
self::STOPWATCH_NAME_PREFIX,
$fixtureName
);
}

public function getPerformanceInfo(Fixture $fixture): PerformanceInfo
{
try {
$event = $this->stopwatch->getEvent($this->stopWatchName($fixture));
} catch (\LogicException) {
return new PerformanceInfo(-1, -1);
}

return new PerformanceInfo(
$event->getDuration(),
$event->getMemory(),
);
}

}
25 changes: 25 additions & 0 deletions src/Profiler/Timing/TimingCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Neusta\Pimcore\FixtureBundle\Profiler\Timing;

use Neusta\Pimcore\FixtureBundle\Fixture\Fixture;
use Neusta\Pimcore\FixtureBundle\Profiler\PerformanceInfo\PerformanceInfo;

class TimingCollector
nehlsen marked this conversation as resolved.
Show resolved Hide resolved
{
/** @var array<class-string, PerformanceInfo> */
private array $timings = [];

public function add(Fixture $fixture, PerformanceInfo $performanceInfo): void
{
$this->timings[get_class($fixture)] = $performanceInfo;
}

/**
* @return array<class-string, PerformanceInfo>
*/
public function getAll(): array
{
return $this->timings;
}
}
Loading
Loading