-
Notifications
You must be signed in to change notification settings - Fork 27.4k
perf($compile): wrap try/catch of collect comment directives into a function to avoid V8 deopt #14848
Conversation
Great PR, thanks for this. Could you add a comment to the function that indicates that this is for perf reasons?
Funnily enough, the try-catch was introduced because there was a not reproducible error in IE9 ... |
Thanks! Ok! I'll add the comment now. |
d3fd76e
to
d5351e5
Compare
…unction to avoid V8 deopt
d5351e5
to
3a40bd4
Compare
break; | ||
} | ||
|
||
directives.sort(byPriority); | ||
return directives; | ||
|
||
function collectCommentDirectives() { |
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.
Rather than extracting the entire case to a function, you may want to consider extracting just the bit that might throw (accessing nodeValue
) and putting that function as a sibling to the collectDirectives
function.
Reason being is that since collectDirectives
is invoked once for every node which is often in the thousands (1558 on a quick sample I took from one app that I work on), we can avoid creating thousands of additional functions that need to be GCed.
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.
Isn't this something that an interpreter can optimize as it knows that this function is always used the same, only with a different context?
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 interpreter still has to create a new closure and function instance for each and every one though (must ensure two of these !=
each other etc.).
I'd definitely vote to avoid recreating the same function per node...
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.
Ok,
I have some reasonable doubts about what @dcherman and @jbedard exposes, I believe that current compilers are smart enough, and I would prefer this kind of comments with links to jsperf.
Unfortunately jsperf is offline :/ and in my benchmark with code from real apps shows no conclusive performance difference from one implementation to the other.
So, to let you to test each version I put each version in a separated commit so you can do your own benchmarking.
And about optimisation has this great rule: "don’t optimize before you need to optimize"
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.
So I'll retract my statement, and you can revert the commit if you'd like.
All browsers at least back to IE9 seem to defer parsing of functions until necessary, and memory allocations did not seem to occur in the tests that I've done in Chrome, FF, or IE11.
About pre-mature optimization; the compile and linking phases are some of the hottest areas in Angular, so I think it's more important to consider the implications of any given change here versus tinkering with something like $http
where optimization is way less likely to bear measurable fruit. Worst case scenario is you learn something about how browsers work internally as we did here, and that's never a bad thing. In this case, I suggested the change initially because it's semantically identical to the original PR without any additional complexity or significant restructuring, but is more obviously correct to someone that was not aware of engine optimizations (guilty as charged here).
If you want to look into something similar, I've been meaning to make a similar change in $digest
to eliminate the deopts there and profile to see if it speeds up the digest cycle at all. I suspect that
…ctives because a possible performance concern
LGTM |
So, it is ready for merge then. |
Yep - will do on Monday if no one gets to it before me |
Too low hanging a fruit - sorry, @petebacondarwin 😛 |
…unction to avoid V8 deopt Closes #14848
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...) its a performance optimization. It turns out that try/catch statements prevents the optimization of the function collectDirectives, which has a great weight in the initial document parse.
What is the current behavior? (You can also link to an open issue here)
It should be around a 5% faster in the angular initial document parse, and also in directives compilation.
What is the new behavior (if this is a feature change)?
There is no change in the functionality.
Does this PR introduce a breaking change?
No
Please check if the PR fulfills these requirements
Other information:
See: GoogleChrome/devtools-docs#53
I did all performance checking over existing code from my customers, in their code this optimization makes it go a 5% faster in the initial parse time and compile time in average (I just performed 200 evaluation comparison with execution times around 50 - 100ms of each evaluation). I did the performance test over chrome, safari and firefox, all of them with similar speedup results.
I am not sure which environment do you use to check performance (I think that it is probably related to benchpress). ¿Do you have a guide about how to set up and do testing?
I found the problem while doing performance optimization in a customer code. Just clicking around I found this message lots of times:

It should solve it, because in production environments usually there are no comments, so, this function is likely to be never executed.
I did no new documentation neither new tests because nothing changes but performance.