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

Optimize performance by optionally collectiong only EA directives #14850

Merged
merged 2 commits into from
Aug 8, 2016

Conversation

drpicox
Copy link
Contributor

@drpicox drpicox commented Jun 30, 2016

What kind of change does this PR introduce? (Bug fix, feature, docs update, ...) Performance optimization that introduces a new feature as $compileProvider configuration.

What is the current behavior? (You can also link to an open issue here): $compile collect directives from entities, attributes, classes and comments. It parses all four kind of directives, although usually only E (components) and A ("directives") are used in most of the projects.

What is the new behavior (if this is a feature change)?: It introduces a new configuration in the $compileProvider that disables the compilation of C and M directives:

$compileProvider.commentDirectivesEnabled(false);
$compileProvider.cssClassDirectivesEnabled(false);

Does this PR introduce a breaking change?
No. By default is configured true, thus it is compatible with all existing code.

Please check if the PR fulfills these requirements

Other information:
It is closely related to #14848
I have reused the same benchmarks to measure the improved performance of this PR, and it is around 10-15% of performance improvement by setting restrictDirectivesTo to 'EA'.

@drpicox drpicox force-pushed the perf-collectDirectives-EA branch 4 times, most recently from ab35cc9 to 18ef9f1 Compare June 30, 2016 10:03
@Narretz Narretz changed the title Optimize performance by collectiong only EA directives Optimize performance by optionally collectiong only EA directives Jun 30, 2016
@petebacondarwin
Copy link
Contributor

This seems like a pretty good idea since just about every Angular app I have ever written doesn't actually use comment or CSS class based directives. We could even make this opt-out in a future version...

The API naming seems a bit clunky though... Perhaps something more like restrictDirectivesTo('EA') or similar? Open to discussion on that...

@Narretz
Copy link
Contributor

Narretz commented Jun 30, 2016

I also like it. One of these things that are really obvious in hindsight.
I also think that we could expand the API to allow any combination of restricts (although EA is needed by probably 99.999% of apps).

@drpicox
Copy link
Contributor Author

drpicox commented Jun 30, 2016

Good!
I'll try to update it later today :)
(I also like more the naming)

@drpicox drpicox force-pushed the perf-collectDirectives-EA branch from 18ef9f1 to e40345e Compare June 30, 2016 21:36
@drpicox
Copy link
Contributor Author

drpicox commented Jun 30, 2016

I have updated it.

The function name is restrictDirectivesTo, default value is 'EACM', and the implementation is almost the same.

Because:

  • restrictDirectivesTo may accept any combination of EACM,
  • I do not want to add more conditionals than previously existing (deactivate E or A is a little bit more complex),
  • and it makes no sense to do not include EA

I force to have at least EA in the expression (throws an error if not).

@petebacondarwin
Copy link
Contributor

Great and rapid work - thanks @drpicox
Sorry to be a pain but now that I realise that disabling E and A is not really viable, my suggested API naming doesn't make that much sense.

Can we have a quick chat about what might work best before you make any more changes...

Perhaps we could make it explicit, following the getter/setter style of debugInfoEnabled:

commentDirectivesEnabled(false);
cssClassDirectivesEnabled(false);

or perhaps we could disable them together...

commentAndCssClassDirectivesEnabled(false);

or some better thing??

@drpicox
Copy link
Contributor Author

drpicox commented Jul 1, 2016

I have seen some people using class directives, mainly because some people work like times of backbone or jquey and they use templates from designers which do thinks like <button class="save-user-button">Save<button> . There is also a popular library to draw charts by using canvas that has class directives (it break when restrict was defaulted to EA but they corrected it to support C).

So it make sense to have separated class and comments. I have never seen a comment directive. I know why it is supposed to be useful because of the angular documentation.

I have difficult to do a chat by now, now I'm at AngularCamp listening to @toddmotto talking about .component :)

@drpicox
Copy link
Contributor Author

drpicox commented Jul 1, 2016

Btw I'm follows you at Twitter, so if you follow me you can send me pms and have the chat.

@@ -3128,17 +3128,129 @@ describe('$compile', function() {
});
});

it('should observe interpolated attrs', inject(function($rootScope, $compile) {
Copy link
Member

Choose a reason for hiding this comment

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

Why was this test removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ops! It shouldn't!

@Narretz
Copy link
Contributor

Narretz commented Jul 1, 2016

I think the explicit version is the way to go. It's verbose, but you are not gonna use this more than once per app, and it also doesn't give the impression that you can disable EA

commentDirectivesEnabled(false);
cssClassDirectivesEnabled(false);

$rootScope = _$rootScope_;
}));

it('should not compile class directives', function() {
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be cleaner to use test-collect for all testcases. It makes the comparison easier.

@gkalpak
Copy link
Member

gkalpak commented Jul 1, 2016

Yeah, 👍 for the explicit versions from me too.

BTW, I would feel more confident about the tests, if we used the they helper to run each of them against all possible combinations and verfiy that the behavior is correct. Something like this:

they('should handle comment directives appropriately ($prop)', [
  {restrict: 'EA', collect: false},
  {restrict: 'EAC', collect: false},
  {restrict: 'EAM', collect: true},
  {restrict: 'EACM', collect: true}
], function(config) {
  module(function($compileProvider) {
    $compileProvider.restrictDirectivesTo(config.restrict);
  });

  inject(function() {
    var html = '<!-- directive: test-collect -->';
    element = $compile('<div>' + html + '</div>')($rootScope);
    expect(collected).toBe(config.collect);
  });
});

@petebacondarwin
Copy link
Contributor

OK, so lets go with

commentDirectivesEnabled(false);
cssClassDirectivesEnabled(false);

@drpicox can you take a look at @gkalpak's comments about the testing?

Thanks

expect(collected).toBe(true);
}));

angular.forEach([
Copy link
Member

Choose a reason for hiding this comment

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

You don't need angular..

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ops, true! Thanks!

@gkalpak
Copy link
Member

gkalpak commented Jul 27, 2016

Do we have any (verifiable) numbers on how performance is affected by this?
That would be nice 😄

I also think it is a good idea to mention this in the Running in Production section of the Developer Guide.

@drpicox
Copy link
Contributor Author

drpicox commented Jul 27, 2016

I did my performance benchmarks using code from my customers (just right click and get source).
I also have used benchpress and numbers looked similar (although I am not sure because I am not familiar with benchpress yet).
I'll try to modify benchpress to enable/disable directives conditionally so we can verify it.
And btw, the gain of comment directives is very low, there are usually no commens, but from element classes is high.

@drpicox drpicox force-pushed the perf-collectDirectives-EA branch 3 times, most recently from 699ab98 to af12104 Compare July 27, 2016 14:10
@drpicox
Copy link
Contributor Author

drpicox commented Jul 27, 2016

I have added a benchpress benchmark.

  • I follow more or less the same structure of the other benchmarks
  • I have added query params (they can be set by just clicking links), in order to configure $compileProvider in config time.
  • I have added a repeater in order to make more benchmark repeats easily (I think that it might be possible to be configured from benchpress, but I didn't found it in a quick glance)
  • I have added a chooser for templates: the idea is the compile time varies in function the of compiled template. Now I just have added two templates from http://getbootstrap.com/getting-started/#examples , I consider that they are realistic.

How to run?

  • $ grunt bp_build
  • $ grunt webserver
  • go to incognito mode
  • open http://localhost:8000/build/benchmarks/bootstrap-compile-bp
  • select the kind of directives that you want to enable
  • change if you wish repeat count
  • select the template
  • and click "Loop 25x"
    (better if for each test you create a new window)

The numbers that I have obtained are:

  • Carousel template: ~12% of speedup
    • Compile everything: mean: 206.71ms ± 24% (stddev 49.45) (min 177.41 / max 332.15)
    • Compile only EA: mean: 183.14ms ± 25% (stddev 45.87) (min 154.76 / max 303.56)
  • Theme template: ~10% of speedup
    • Compile Everything: mean: 615.42ms ± 21% (stddev 126.72) (min 531.03 / max 923.89)
    • Compile only EA: mean: mean: 555.74ms ± 21% (stddev 117.11) (min 474.25 / max 793.57)

@drpicox drpicox force-pushed the perf-collectDirectives-EA branch from af12104 to dd07d9c Compare July 27, 2016 17:27
@drpicox drpicox force-pushed the perf-collectDirectives-EA branch from dd07d9c to 4bde767 Compare July 27, 2016 18:08
* $compileProvider.commentDirectivesEnabled(false);
* ```
*
* @param {boolean} false if the compiler may ignore directives on comments
Copy link
Member

Choose a reason for hiding this comment

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

You should have the argument name right after the type. Now false is interpreted as the argument type and the rest as the description.

@drpicox
Copy link
Contributor Author

drpicox commented Jul 28, 2016

Thanks @gkalpak for comments, I have updated it.

@drpicox drpicox force-pushed the perf-collectDirectives-EA branch 5 times, most recently from 2fa432f to af05406 Compare July 29, 2016 07:40
@drpicox drpicox force-pushed the perf-collectDirectives-EA branch from af05406 to 66f2eaa Compare July 29, 2016 11:49
@petebacondarwin
Copy link
Contributor

LGTM

@Narretz Narretz modified the milestones: 1.5.9, 1.5.x Aug 3, 2016
@Narretz Narretz merged commit 4c2964d into angular:master Aug 8, 2016
gkalpak pushed a commit that referenced this pull request Aug 8, 2016
…ass and comment directives

When the functions `cssClassDirectivesEnabled()` / `commentDirectivesEnabled()` on the `$compileProvider` are called with `false`, then the compiler won't look for directives on css classes / comment elements.

This can result in a compilation speed-up of around 10%.

PR (#14850)
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.

5 participants