-
-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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
[Serializer] Add methods getSupportedTypes
to allow better performance
#49291
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice improvement!
I would go as far as suggesting to add getSupportedTypes
to both NormalizerInterface
and DenormalizerInterface
(with a BC layer of course)? That'd make a lot of sense to me.
src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/CacheableSupportsMethodInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/MimeMessageNormalizer.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/SupportedTypesMethodInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/SupportedTypesMethodInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php
Outdated
Show resolved
Hide resolved
the new interface needs to be implemented in the TraceableNormalizer, so that the benefits of this caching are not lost (and hidden from devs) in dev environments when the profiler is enabled. |
This looks very promising! +1 on my side for the general approach as well as for making |
e11f040
to
25b94bc
Compare
d103aa6
to
84b2667
Compare
db028b5
to
2e9daf0
Compare
@nicolas-grekas PR has been updated to move |
Thank you @tucksaun. |
25cf787
to
e5af24a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @nicolas-grekas for taking over the last edits regarding your comment 👍
Also I like the idea or the wildcard: stating that a normalizer supports any type and is cacheable was indeed something my PR was lacking!
* For each supported formats (if applicable), the supported types should be | ||
* returned as keys, and each type should be mapped to a boolean indicating | ||
* if the result of supportsDenormalization() can be cached or not | ||
* (a result cannot be cached when it depends on the context or on the data.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"(a result cannot be cached when it depends on the context or on the data)." (dot after the parenthesis) ?
* For each supported formats (if applicable), the supported types should be | ||
* returned as keys, and each type should be mapped to a boolean indicating | ||
* if the result of supportsNormalization() can be cached or not | ||
* (a result cannot be cached when it depends on the context or on the data.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"(a result cannot be cached when it depends on the context or on the data)." (dot after the parenthesis) ?
…portedTypes()" (nicolas-grekas) This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] Allow filtering "object" when using "getSupportedTypes()" | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Follows #49291 This allows telling when only objects are accepted, to skip calling `supportsNormalization()` when native types are considered. /cc `@tucksaun` Commits ------- 6984dce [Serializer] Allow filtering "object" when using "getSupportedTypes()"
| Q | A | ------------- | --- | Branch? | 6.3 for features | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | symfony#49291 (review) | License | MIT | Doc PR | n/a As mentioned in symfony#49291 (review).
| Q | A | ------------- | --- | Branch? | 6.3 for features | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | symfony#49291 (review) | License | MIT | Doc PR | n/a As mentioned in symfony#49291 (review).
This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] Add missing upgrade note | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | none | License | MIT | Doc PR | none Forgot during #49291 /cc `@nicolas`-grekas Commits ------- a28ff01 [Serializer] Add missing upgrade note
| Q | A | ------------- | --- | Branch? | 6.3 for features | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | symfony#49291 (review) | License | MIT | Doc PR | n/a As mentioned in symfony#49291 (review).
…(tucksaun) This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] Mark `ObjectNormalizer` as final for 7.0 | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | #49291 (review) | License | MIT | Doc PR | none Extracted from #49950 and related to #49291 (review) Commits ------- b2828e9 [Serializer] Mark ObjectNormalizer as final for 7.0
| Q | A | ------------- | --- | Branch? | 6.3 for features | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | symfony#49291 (review) | License | MIT | Doc PR | n/a As mentioned in symfony#49291 (review).
…(tucksaun) This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] Marking some Normalizer classes as final | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | #49291 (review) | License | MIT | Doc PR | n/a As mentioned in #49291 (review). Making those classes final will allow to get rid of all the `__CLASS__ === static::class` for cacheability checks in 7.0 Commits ------- d976fc5 [Serializer] Marking some Normalizer classes as final
| Q | A | ------------- | --- | Branch? | 6.3 for features | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | symfony/symfony#49291 (review) | License | MIT | Doc PR | n/a As mentioned in symfony/symfony#49291 (review).
…rmalizableInterface (spideyfusion) This PR was merged into the 6.3 branch. Discussion ---------- [Serializer] Fix ignoring objects that only implement DenormalizableInterface | Q | A | ------------- | --- | Branch? | 6.3 <!-- see below --> | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | N/A <!-- prefix each issue number with "Fix #", no need to create an issue if none exists, explain below instead --> | License | MIT | Doc PR | N/A <!-- required for new features --> When the #49291 optimization got introduced, the `DenormalizableInterface` type was left out of the `CustomNormalizer` normalizer's `getSupportedTypes` implementation. This prevents us for example, implementing custom deserialization logic for API objects where we can't describe all deserialization rules via attributes. <!-- Replace this notice by a short README for your feature/bugfix. This will help reviewers and should be a good start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the latest branch. - For new features, provide some code snippets to help understand usage. - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry - Never break backward compatibility (see https://symfony.com/bc). --> Commits ------- a0a3ce1 [Serializer] Fix ignoring objects that only implement DenormalizableInterface
The PRs allows normalizers or denormalizers to expose their supported types and the associated cacheability to the Serializer.
With this info, even if the
supports*
call is not cacheable, the Serializer can skip a ton of method calls tosupports*
improving performance substaintially in some cases:I found this design while working on a customer project performance (a big app built around API Platform): we reached the point where the slowest part of main application endpoint was `Symfony\Component\Serializer\Serializer::getNormalizer`.
After some digging, we found out we were experiencing the conjunction of two phenomenons:
Because most of the normalizers are not cacheable, the Serializer has to call every normalizer over and over again leading
getNormalizer
to account for 20% of the total wall time:We first tried to improve cacheability based on context without much success, then an approach similar to #45779 with some success but still feeling this could be faster.
We then thought that even if the
supportsNormalization
could not be cached (because of the context), maybe we could avoid the calls at the origin by letting theNormalizers
expose the types they support and came to this PR with pretty good results.The perfornance improvement was only measured by adapting Symfony's normalizers as well as the project ones, proper third party normalizers updates should improve performance even more.
This should effectively replaces the
CacheableSupportsMethodInterface
as the cacheability can now be returned bygetSupportedTypes
.