-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
Added cache data collector and profiler page #21065
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
Conversation
$loaders = array_map(function ($loader) { return new Reference($loader); }, $config['loaders']); | ||
$loaders = array_map(function ($loader) { | ||
return new Reference($loader); | ||
}, $config['loaders']); |
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.
This change was from fabbot.io
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.
you should revert them, fabbot is broken these days
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.
Okey, thank you
@@ -674,7 +677,9 @@ private function registerTemplatingConfiguration(array $config, ContainerBuilder | |||
)); | |||
|
|||
$container->setParameter('templating.engines', $config['engines']); | |||
$engines = array_map(function ($engine) { return new Reference('templating.engine.'.$engine); }, $config['engines']); | |||
$engines = array_map(function ($engine) { |
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.
This change was from fabbot.io
@Nyholm thanks for this PR. Don't worry about the logo because the SensioLabs designer will take care of that. And same thing about the design, don't worry because we can iterate it later. Let's focus on the contents and the information provided. Thanks! |
That is great. Then Im done with this PR =) ("Done" = "Waiting for community feedback") |
It would be very useful collect this information also from production env and analyze it later. Can anybody idea how to make it possible without enabling whole profiler? |
With the current implementation you should only load |
* | ||
* @return string | ||
*/ | ||
private function getValueRepresentation($value) |
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.
@Nyholm I'm not sure, but can't we use the VarDumper component here to print the value ? (BTW thanks a lot for this first collector, it's really nice!)
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.
Oh. That is a good idea. I'll see what I can do. Thanks.
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.
the representation should be handled by the data collector, using the cloneVar method of the base DataCollector
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.
I cannot use the DataCollector::cloneVar
in this context. The RecordingAdapter
is not a data collector. However, I use the cloneVar
once the data is moved to the CacheDataCollector
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.
@Renrhaf I've updated the PR using your suggestion. Thank you!
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.
@Nyholm seems good to me ;) thank you !
* | ||
* @return object | ||
*/ | ||
private function timeCall($name, array $arguments = array()) |
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.
what about using a stopwatch instead?
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.
Sure!
* | ||
* @param $call | ||
*/ | ||
private function addCall($call) |
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.
this function wrapper for a oneliner could be removed
/** | ||
* @author Tobias Nyholm <tobias.nyholm@gmail.com> | ||
*/ | ||
interface RecordingAdapterInterface |
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.
I'd remove this interface entirely: we don't want a contract here, we need only a behavior (an implem)
foreach ($calls as $call) { | ||
$statistics[$name]['calls'] += 1; | ||
$statistics[$name]['time'] += $call->time; | ||
if ($call->name === 'getItem') { |
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.
what about getItems?
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.
Thank you. If one do getItems(['a', 'b', 'c']). I will count that as 1 call and 3 reads.
$result = $call->result; | ||
$hits = 0; | ||
$items = array(); | ||
foreach ($result as $item) { |
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.
In the case of a generator, I see two issues here:
- this is consuming the generator. Since these are not rewindable,
return $result;
returns a non usable generator. - this is couting hits, but maybe the app didn't consume the generator on its side.
This means I think we should have two code paths here: one for array (doing the same as the current code),
and one for Traversable, which should wrap this in a generator-closure, and do things lazily.
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.
I've wrapped the result in a generator closure as you suggested. I fail to understand we need a code path for arrays. I know that getItems will return something that you can do foreach with. Why can't I just always wrap it in a generator-closure?
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.
no strong reason, good also via a generator
* @author Aaron Scherer <aequasi@gmail.com> | ||
* @author Tobias Nyholm <tobias.nyholm@gmail.com> | ||
*/ | ||
final class RecordingAdapter implements AdapterInterface |
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.
Oh, I guess this should be named TraceableAdapter for consistency with the code base (eg TraceableUrlMatcher, etc.)
* | ||
* @return string | ||
*/ | ||
private function getValueRepresentation($value) |
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.
I think we don't need this logic, let's just use $value
directly.
The clone may fail (implem can throw in __clone
), and is fragile (not recursive).
and for other types of data, we don't care (resources cannot come up from a cache pool)
removing also will make the layer slimmer, which is also a nice target
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.
Will do. Thank you.
namespace Symfony\Component\Cache\Adapter; | ||
|
||
use Psr\Cache\CacheItemInterface; | ||
use Psr\Cache\CacheItemPoolInterface; |
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.
not used anymore (mybad)
<?php | ||
|
||
/* | ||
* This file is part of php-cache\cache-bundle package. |
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.
this is wrong
/* | ||
* This file is part of php-cache\cache-bundle package. | ||
* | ||
* (c) 2015-2015 Aaron Scherer <aequasi@gmail.com>, Tobias Nyholm <tobias.nyholm@gmail.com> |
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.
Symfony code must use the Symfony copyright
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.
Sorry, Copy/paste issue.. An my IDE does not show file headers. I will fix these
{% block head %} | ||
{{ parent() }} | ||
<style> | ||
.color-red { |
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.
would be better to include necessary styles in the CSS, to be usable for all collectors
{{ include('@WebProfiler/Icon/cache.svg') }} | ||
</span> | ||
<strong>Cache</strong> | ||
<span class="count"> |
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.
I don't think we should have the time here anymore, for consistency with other panels
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.
Do you want me to remove it?
|
||
{% block panel %} | ||
<h2>Cache</h2> | ||
{% for name, calls in collector.calls %} |
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.
It would be great to have the aggregated stats first as big numbers (as done in other panels), before having the detail for each pool
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.
Done!
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.
no it is not done
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.
$container->register($id.'.recorder', TraceableAdapter::class) | ||
->setDecoratedService($id) | ||
->addArgument(new Reference($id.'.recorder.inner')) | ||
->addArgument(new Reference('debug.stopwatch')) |
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.
The implementation does not use Stopwatch
Just by looking at the screenshot I was not able to easily recognise what "ratio" refers to. Does it mean hits/reads? |
Sorry about that. Yes, the ratio is the hits/reads ratio. See new screenshot: FYI: I created a separate PR with the adapters. I added some tests and fixed some bugs in it. I will rebase this PR when/if #21082 gets merged. |
I think I would change the label from "ratio" to "hits/reads" then. |
And what about providing aggregated data across all pools? |
I will.
That is only in the toolbar atm. |
Nice :) What about a tab per pool? That should organize things right? The table with calls looks rather technical, so maybe we can improve that UX-wise.
👍 |
This PR was squashed before being merged into the 3.3-dev branch (closes #21082). Discussion ---------- [Cache] TraceableAdapter | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | Related to #21065 | License | MIT | Doc PR | n/a I moved the TraceableAdapter to a separate PR and added some tests. I found a small bug which was fixed. Commits ------- 5cc4baf [Cache] TraceableAdapter
3e5b858
to
7341375
Compare
Thank you @ro0NL. I agree with your comments that this could be improved and I really like your suggestions. I think this is "good enough" and I will let other PRs improve this. Does it sound reasonable? I've rebased this PR on master. |
$statistics[$name]['misses'] += $count - $call->misses; | ||
} elseif ($call->name === 'hasItem') { | ||
$statistics[$name]['reads'] += 1; | ||
if ($call->result->getRawData()[0][0] === false) { |
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.
This looks a bit ugly.
$call->result
is a Symfony\Component\VarDumper\Cloner\Data
. I know that hasItem
will always return a boolean thanks to PSR-6. So I believe this is safe.
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.
No better way for now, I may work on something better soon but this is the way to go for now.
That's unfortunate, as it means that the main info displayed in the toolbar is not available anymore when looking at details. |
Ping @stof |
@Nyholm Any reason not to aggregate missed and deletes? I would also change the order to be consistent with how it is for the cache pools. |
We chain a From DX perspective it also would be great to have some kind of (javascript?) filtering in the panel, as that would allow you to instantly see the behavior path of a specific cache item. |
Is there anything else I can do to help getting this PR merged? |
@Nyholm If you can rebase on current master, I can merge it :) |
👍 from me |
b9114b8
to
d09bcf3
Compare
Thank you. The PR is rebased and tests are all green. |
Thank you @Nyholm. |
This PR was squashed before being merged into the 3.3-dev branch (closes #21065). Discussion ---------- Added cache data collector and profiler page | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #19297 | License | MIT | Doc PR | n/a Adding a first version of cache profiler page. Most things are taken from PHP-cache. FYI: @aequasi ### What is included? A collector, recording adapter and a profiler page.   ### What is not included? * A good logo * Nice design on the profiler page This PR aims to pass as the minimum requirement for a cache page. Im happy to do fancy extra features but those should be a different PR. Commits ------- 7497f1c Added cache data collector and profiler page
Thank you for merging |
Many thanks @Nyholm :) |
Adding a first version of cache profiler page. Most things are taken from PHP-cache.
FYI: @aequasi
What is included?
A collector, recording adapter and a profiler page.
What is not included?
This PR aims to pass as the minimum requirement for a cache page. Im happy to do fancy extra features but those should be a different PR.