Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Add new ReactPerf #6046
This is a work in progress on implementing new ReactPerf as discussed in #6015.
Per @sebmarkbage’s request, I decided to focus on removing dependencies on internal method names. Data will be explicitly passed to the perf tool from React methods, and we will attempt to not rely on the execution order.
Rather than refactor the existing code, I chose to create a new tool side by side so I can compare their output until I’m confident about correctness. I will later add
referenced this pull request
Feb 16, 2016
Say we’ve got three components.
Regular Recursive Batch
Components mount (or updated) recursively like they normally do. Numbers correspond to the current time, phrases to events the Perf tool receives. The columns show whether the time period is counted towards
We need to make sure that it is easy to introduce out-of-stack updates later. For example, we want a top-level update of
As an extra safety measure, we will absurdly include an update of
Note how the
Do these calculations look right? Is this the desired output for these scenarios?
Yea, this looks right. I can't see how steps 13-14 could possibly happen but if it could, then yea, that would be the right call.
The point of decoupling this is so that in theory, someone else could've implemented this perf tool without changing the core. Since you're effectively mapping the names of methods 1:1, it doesn't create much decoupling. If we change the algorithm, you would still have to go change the ReactNewPerf implementation.
A good guideline is to put things that are likely to change together into the same file. So, if we can't decouple, we might as well put all of ReactNewPerf into ReactCompositeComponent etc. to make it easy to refactor.
I understand that this is your later step "It should not rely on the rendering and mounting stack matching parent hierarchy".
One suggestion that I have is that you could, have start and stop timer associated with component time in ReactNewPerf. E.g.
That way we can restructure the order completely without changing ReactNewPerf.
We could pass something like
Is this what you’re getting at?
Can do that. But it’s not exposed yet, is it? Meaning I’d need to add these events to the devtool code myself.
Currently I don’t have enough context about what kind of information DevTools want. I can start by firing notifications on the devtool for every lifecycle hook with the internal instance. Would that be sufficient? ReactNewPerf would tune in to "mounted" and "unmounted" events and use this as a chance to track the owners.
If I do this, we’ll need to gate devtool API by something like
Currently these events are exposed through the devtools (search for
(Note that the terminology is a bit confusing there. The
The "backend" part of the devtools is an event protocol designed by @jaredly to be sufficient to track the tree. A good start might be to mirror that API.
I think you mean the parents. We use the term "owner" for the thing that created the element which is not the same as the thing mounting it - which is the parent. To track inclusive time you need the parent.
It is unfortunate that tracking the tree might add a lot of overhead but it is probably nice to be able to visualize this in terms of a full tree.
The idea is that we can check for
Currently the devtools work in production mode because it just uses monkey patching. That sucks for optimizations and package size. Maybe a
Thank you, this is very helpful.
Thanks for correcting me. I thought owners should be used for the inclusive calculation but I trust you that parents make more sense here. I don’t really understand the problem well enough yet to see why.
Since this is all very confusing I’ll finish the implementation first, and then we’ll decide how to proceed with the feature flags both for Perf and tree tracking.
Sure. If you want, you can also just add a temporary constant flag (always
GH Review: review-needed
GH Review: needs-revision
Feb 18, 2016
So far I haven’t been able to do this if
I’m not sure whether this is the approach you had in mind but it seems like a lot of changes so I want to double-check. Maybe we can use context for passing
Alternatively we can change the logic so that even DOM components get their own exclusive time measurements with
The mental model I have is that DOM components are just another composite component. Their time shouldn't count to the exclusive time of the composite above them. If it does in the old perf tools, that seems like an artifact/bug rather than desired behavior.
If a composite passes a bunch of children to another composite. Then it would be misleading to include those in the exclusive time of the parent when the owner really created it.
It seems fine to put these calls into the native components.
However, note that I also want to unify the way native components are rendered so that a lot of that wouldn't vary by renderer eventually. The recursion will move into shared code. That way we could put these measurements in a generic way. That would preclude renderer specific tags like
This might be why I thought we should use the owner tree for calculating inclusive time.
Interesting. I definitely think that it does in the old perf tools. In the old perf tools, anything until the next composite is on the mounting stack counts towards the previous top composite on the stack.
What would be the point of exclusive metrics than don’t count DOM components towards the composites? Would information about DOM components be included in the metrics at all?
Currently, ReactPerf groups all information by composites only. Aside from the log of all DOM changes (which goes separately from the inclusive/exclusive tables), ReactPerf currently does not provide you specific information about the DOM components. If we include DOM components in the measurements, would we not have a useless table dominated by
Also, if we only measure composites’ own time, what will we be measuring exactly? Time spent in constructor and
(Now I decided to do my own homework and read the docs. Apparently what you’re saying is exactly what we’ve been promising all along:)
So I guess this is what I’ll do then.
In the current table view you're right that we probably don't want to show DOM components as their own rows. But if we showed it in a tree view it could make a lot more sense. Maybe the ideal is that the visualization lets you enable and disable seeing DOM components when you're actually looking at the data.
We should really include all of those lifecycle methods in the measurements. I consider it a bug that we currently don't. componentDidMount is an example of one that runs later so that could give you an opportunity to make it work for out-of-order reconciliation. Ideally we can also split out the time for each lifecycle method so you can look if you notice a slow component and want to know what piece to optimize.
Don't forget that the
The DOM operation isn't necessarily the slowest part. Once diffed, the work that is actually touching the DOM, more often than not, is something that you have to do. So it is not very actionable.