Skip to content

[HttpKernel] Added support for timings in ArgumentValueResolvers #26833

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

Merged
merged 1 commit into from
Apr 20, 2018
Merged

[HttpKernel] Added support for timings in ArgumentValueResolvers #26833

merged 1 commit into from
Apr 20, 2018

Conversation

linaori
Copy link
Contributor

@linaori linaori commented Apr 6, 2018

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets ~
License MIT
Doc PR ~

This feature provides timings for the supports and resolve methods for each individual argument value resolver. It was already possible to see the controller.get_arguments timing, but it was impossible to track a possible performance issue any further without using different tools. I've explicitly added the supports method as well, as it might otherwise hide performance issues. The ServiceValueResolver for example, does a container::has, which in turn might trigger a factory method, which might trigger a query for example.

Due to the feature freeze I've already added this to 4.2. If for some reason it's okay to still merge it into 4.1, I can update the upgrade files. - Changed to 4.1

Without performance issue

image

With performance issue

image

*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
$method = \get_class($this->inner).'::'.__FUNCTION__;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also just do $method = \get_class($this->inner).'::supports'; and resolve for the other. Not sure what is preferred. Opinions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍for __FUNCTION__

@fabpot
Copy link
Member

fabpot commented Apr 6, 2018

4.1 is still open for small additions.

@linaori
Copy link
Contributor Author

linaori commented Apr 6, 2018

I've updated the changelogs to be for 4.1

@ogizanagi ogizanagi added this to the 4.1 milestone Apr 6, 2018
UPGRADE-4.1.md Outdated
HttpKernel
----------

* Added the `Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no upgrade path here 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I remove it in that case? It doesn't cause harm to add it, but it's not really of any value to developers as it's primarily internal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I meant actually. There is no BC break to document here, no upgrade path. We don't mention features in UPGRADE files 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done 😄

*/
public function supports(Request $request, ArgumentMetadata $argument): bool
{
$method = \get_class($this->inner).'::'.__FUNCTION__;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍for __FUNCTION__

$resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container);

if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class)) {
foreach ($container->findTaggedServiceIds('controller.argument_value_resolver') as $id => $tags) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'controller.argument_value_resolver' => $this->argumentValueResolverTag


if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class)) {
foreach ($container->findTaggedServiceIds('controller.argument_value_resolver') as $id => $tags) {
$container->register($id.'.traceable', TraceableValueResolver::class)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are used to debug.$id

foreach ($container->findTaggedServiceIds('controller.argument_value_resolver') as $id => $tags) {
$container->register($id.'.traceable', TraceableValueResolver::class)
->setDecoratedService($id)
->setArguments(array(new Reference($id.'.traceable.inner'), new Reference('debug.stopwatch')));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this binds the feature to FrameworkBundle as it's the one registering debug.stopwatch. I would make it null if invalid and instantiates StopWatch in the TraceableValueResolver constructor if not injected

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class is kinda useless if null is inserted though 😅 there's no way of fetching the stopwatch. The only thing that happens, is that it doesn't crash on NULL.

@@ -40,9 +43,19 @@ public function process(ContainerBuilder $container)
return;
}

$resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assignment does not seem necessary, leftover?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually being used for new IteratorArgument($resolvers). I initially wasn't able to use this as I needed the id, but casting the reference to a string gives me exactly that, saving a call to the container.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, missed the loop!

$id = (string) $resolverReference;
$container->register('debug.'.$id, TraceableValueResolver::class)
->setDecoratedService($id)
->setArguments(array(new Reference('debug.'.$id), new Reference('debug.stopwatch', ContainerInterface::NULL_ON_INVALID_REFERENCE)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be "debug.$id.inner"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, I think I've removed too much 😅

@linaori
Copy link
Contributor Author

linaori commented Apr 18, 2018

Service definitions should be fixed now, tests are passing 👍 My PC only froze for 10 minutes after which I rebooted via the on/off button, due to a minor recursion issue I created during the process.

Copy link
Member

@chalasr chalasr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Could have a line in the http-kernel changelog

@linaori
Copy link
Contributor Author

linaori commented Apr 18, 2018

@chalasr I removed the line where I mentioned adding it based on feedback earlier. I can put something back in there if desired. What were you thinking of?

@chalasr
Copy link
Member

chalasr commented Apr 18, 2018

@iltar I mean only the CHANGELOG file, not upgrade ones :)

@linaori
Copy link
Contributor Author

linaori commented Apr 18, 2018

Something in the form of: Added the ability to profile individual argument value resolvers via the Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver?

@chalasr
Copy link
Member

chalasr commented Apr 18, 2018

👌 for me

@fabpot
Copy link
Member

fabpot commented Apr 20, 2018

Thank you @iltar.

@fabpot fabpot merged commit 1c0d892 into symfony:master Apr 20, 2018
fabpot added a commit that referenced this pull request Apr 20, 2018
…eResolvers (iltar)

This PR was squashed before being merged into the 4.1-dev branch (closes #26833).

Discussion
----------

[HttpKernel] Added support for timings in ArgumentValueResolvers

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | ~
| License       | MIT
| Doc PR        | ~

This feature provides timings for the supports and resolve methods for each individual argument value resolver. It was already possible to see the `controller.get_arguments` timing, but it was impossible to track a possible performance issue any further without using different tools. I've explicitly added the `supports` method as well, as it might otherwise hide performance issues. The `ServiceValueResolver` for example, does a `container::has`, which in turn might trigger a factory method, which might trigger a query for example.

~~Due to the feature freeze I've already added this to 4.2. If for some reason it's okay to still merge it into 4.1, I can update the upgrade files.~~ - Changed to 4.1

##### *Without performance issue*
![image](https://user-images.githubusercontent.com/1754678/38416250-6cf45528-3994-11e8-91d4-2472c97c6c50.png)

##### *With performance issue*
![image](https://user-images.githubusercontent.com/1754678/38416266-7966eb7c-3994-11e8-9dc5-a99daa8f9a69.png)

Commits
-------

1c0d892 [HttpKernel] Added support for timings in ArgumentValueResolvers
@fabpot fabpot mentioned this pull request May 7, 2018
fabpot added a commit that referenced this pull request May 14, 2018
…atory (ogizanagi)

This PR was merged into the 4.1 branch.

Discussion
----------

[HttpKernel] Make TraceableValueResolver $stopwatch mandatory

| Q             | A
| ------------- | ---
| Branch?       | 4.1 <!-- see below -->
| Bug fix?      | no
| New feature?  | no <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #26833 (comment)   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A

I understand why this was suggested in #26833 (comment), but as stated by @iltar , I don't think it makes sense to register a traceable resolver instantiating a Stopwatch itself, as there is no way to fetch it and wouldn't be a shared instance, probably defeating the feature and registering a useless decorator.
Instead, let's make the stopwatch mandatory and make the service id to use in the pass configurable.

Commits
-------

585ae7c [HttpKernel] Make TraceableValueResolver $stopwatch mandatory
fabpot added a commit that referenced this pull request May 14, 2018
…voke controllers method (ogizanagi)

This PR was merged into the 4.1 branch.

Discussion
----------

[HttpKernel] Fix services are no longer injected into __invoke controllers method

| Q             | A
| ------------- | ---
| Branch?       | 4.1 <!-- see below -->
| Bug fix?      | yes
| New feature?  | no <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #27208   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A

_TL;DR:_ The `RemoveEmptyControllerArgumentLocatorsPass` is the one adding the `Controller::_invoke` => `Controller` shortcut missing from the service locator. It isn't properly executed on some cases. This fixes it.

Since #26833, the resolvers are decorated by a `TraceableValueResolver`, which usually isn't much an issue to deal within passes. But the `RemoveEmptyControllerArgumentLocatorsPass` happens late (`TYPE_BEFORE_REMOVING`), when decoration inheritance is already resolved, so accessing `$controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0));` isn't accessing the controller locator, but the decorated service instead.

Commits
-------

ee44903 [HttpKernel] Fix services are no longer injected into __invoke controllers method
symfony-splitter pushed a commit to symfony/http-kernel that referenced this pull request May 14, 2018
…voke controllers method (ogizanagi)

This PR was merged into the 4.1 branch.

Discussion
----------

[HttpKernel] Fix services are no longer injected into __invoke controllers method

| Q             | A
| ------------- | ---
| Branch?       | 4.1 <!-- see below -->
| Bug fix?      | yes
| New feature?  | no <!-- don't forget to update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- don't forget to update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | #27208   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A

_TL;DR:_ The `RemoveEmptyControllerArgumentLocatorsPass` is the one adding the `Controller::_invoke` => `Controller` shortcut missing from the service locator. It isn't properly executed on some cases. This fixes it.

Since symfony/symfony#26833, the resolvers are decorated by a `TraceableValueResolver`, which usually isn't much an issue to deal within passes. But the `RemoveEmptyControllerArgumentLocatorsPass` happens late (`TYPE_BEFORE_REMOVING`), when decoration inheritance is already resolved, so accessing `$controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0));` isn't accessing the controller locator, but the decorated service instead.

Commits
-------

ee44903 [HttpKernel] Fix services are no longer injected into __invoke controllers method
@linaori linaori deleted the feature/traceable-avr branch February 8, 2019 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants