Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

perf($rootScope): do not mark $watchCollectionInterceptor as $stateful #16009

Merged
merged 1 commit into from
Sep 18, 2017

Conversation

jbedard
Copy link
Collaborator

@jbedard jbedard commented May 25, 2017

I think this was a mistake from the start. This interceptor doesn't actually store any state, it just reads the inner/complex state of its input. EDIT: actually it had a purpose originally, although may no longer be as significant, see #16009 (comment)

Removing the $stateful flag will allow some expressions (those with inputs such as array/object literals) to avoid invoking $watchCollectionInterceptor and avoid creating the literals etc. on each digest.

Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

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

LGTM (I think)

@Narretz
Copy link
Contributor

Narretz commented May 31, 2017

Can you please add the info from the first post to the commit message? Otherwise LGTM.

@Narretz Narretz added this to the Backlog milestone May 31, 2017
@Narretz
Copy link
Contributor

Narretz commented May 31, 2017

I think this should be fix instead of perf, since it is a prerequisite for #16015 and as you said, probably a mistake from the start

@jbedard jbedard force-pushed the scope-watchcollection-stateful branch from ba5120a to 7a1bdbc Compare June 2, 2017 04:38
@jbedard jbedard modified the milestones: 1.7.0, Backlog Jun 2, 2017
@jbedard jbedard changed the title perf($rootScope): do not mark $watchCollectionInterceptor as $stateful fix($rootScope): do not mark $watchCollectionInterceptor as $stateful Jun 2, 2017
@jbedard
Copy link
Collaborator Author

jbedard commented Jun 2, 2017

Updated. This one could probably also go to 1.6.x if there's no objections...

@gkalpak
Copy link
Member

gkalpak commented Jun 2, 2017

I don't have any objections.
(I see this more as a perf than fix though, because (hopefully) other that saving some unnecessary work, this change should not in any way affect the behavior of $watchCollection.)

@jbedard
Copy link
Collaborator Author

jbedard commented Jun 9, 2017

I agree it is more of a perf then fix. Even though #16015 depends on it I think that's more of a bug that #16015 fixes, not this. @Narretz any objection to labelling it as perf?

@Narretz
Copy link
Contributor

Narretz commented Jun 9, 2017

Fine with me

@jbedard jbedard force-pushed the scope-watchcollection-stateful branch from 7a1bdbc to 6fbe208 Compare June 10, 2017 04:11
@jbedard jbedard changed the title fix($rootScope): do not mark $watchCollectionInterceptor as $stateful perf($rootScope): do not mark $watchCollectionInterceptor as $stateful Jun 10, 2017
@jbedard
Copy link
Collaborator Author

jbedard commented Jun 28, 2017

FYI I want to look into this more and actually measure it using #16063.

I think I may recall why we originally did this (or why I did it, and didn't leave a comment explaining why...). Essentially because inputs to an expression being used in $watchCollection will often contain non-simple inputs (like collections!). In which case the quick input-watching must fallback to the full expression watching, and might even be a bit slower.

But for literal expressions it sure would be nice if this flag was off since shallow-watching the inputs is all we need to do, and we can avoid constructing the literal and analyzing the collection with this interceptor etc.

@jbedard jbedard force-pushed the scope-watchcollection-stateful branch 2 times, most recently from 0b4cd09 to 805cc43 Compare August 3, 2017 08:07
@jbedard
Copy link
Collaborator Author

jbedard commented Aug 3, 2017

After a bit more investigation, just removing $stateful to allow input watching will...

  • add a minor overhead to everything (due to the inputsWatchDelegate)
  • may remove the overhead of $watchCollectionInterceptor when all inputs are simple values
  • may remove the major overhead of reconstructing literals when all inputs are simple values

I've updated the first commit to only remove $stateful for literals since non-literals will never get the benefits but always get that extra minor overhead.

I've also added a second commit which adds the (internal) concept of $pure interceptors in addition to the existing $stateful concept. If an interceptor is $pure then it will only get invoked if it's inputs have changed, where normally it is invoked if inputs changed or those inputs are non-primitive values. This does not add it to filters or any public interface but that is a possibility for the future (and is like the Angular pure flag).

Locally the parsed-expressions-bp $watchCollection literal tests are 2x as fast and GC went from very-high to 0 when the literal reconstructing is avoided.

I think adding $pure is worth it since it allows this perf gain for all literals (not only those with only simple inputs). WDYT?

@jbedard jbedard force-pushed the scope-watchcollection-stateful branch from 805cc43 to 190241b Compare August 3, 2017 08:29
// Mark literals as $pure to watch literal inputs of any type.
// Mark non literals as $stateful to avoid input-watching and always invoke the interceptor
// since the inputs will most likely be non-simple (like collections!).
$watchCollectionInterceptor.$stateful = !($watchCollectionInterceptor.$pure = $parse(obj).literal);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Split into 2 lines

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Change to $$pure until documented

@jbedard jbedard force-pushed the scope-watchcollection-stateful branch from 190241b to 04485ef Compare September 12, 2017 03:37
…hing

By adding a $$pure flag to the $watchCollectionInterceptor to shallow
watch all inputs regardless of type when watching an object/array
literal.
@jbedard jbedard force-pushed the scope-watchcollection-stateful branch 2 times, most recently from 04485ef to 3fb7173 Compare September 12, 2017 08:11
@jbedard
Copy link
Collaborator Author

jbedard commented Sep 17, 2017

Some benchmarks... when running the parsed-expressions-bp $watchCollection Literals test (basically $watchCollection on those expressions 10000x):

Old: ~5.2s, >375000kb GCed
New: ~2.1s, <10kb GCed

@jbedard
Copy link
Collaborator Author

jbedard commented Sep 17, 2017

I think travis passed now, but github hasn't picked up the new status?

@Narretz
Copy link
Contributor

Narretz commented Sep 18, 2017

The problem with Travis is that the deploy job isn't automatically started after one of the test jobs fails and then passes. I've restarted it manually

@jbedard jbedard merged commit 97b00ca into angular:master Sep 18, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants