Skip to content
This repository has been archived by the owner on Jul 30, 2018. It is now read-only.

Benchmark tweaks #619

Merged
merged 14 commits into from
Aug 2, 2017
Merged

Benchmark tweaks #619

merged 14 commits into from
Aug 2, 2017

Conversation

agubler
Copy link
Member

@agubler agubler commented Jul 25, 2017

Type: feature

The following has been addressed in the PR:

  • There is a related issue
  • All code matches the style guide
  • Unit or Functional tests are included in the PR

Description:

Some performance tweaks based on the js-framework-benchmark results.

Before and after (tweak) results running on my mac with 20 iterations.

interactive_results

Copy link
Member

@kitsonk kitsonk left a comment

Choose a reason for hiding this comment

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

Couple comments

if (diffFunctions.length === 0) {
diffFunctions.push(auto);
const newProperty = this._bindFunctionProperty(properties[propertyName], bind);
if (registeredDiffPropertyNames.indexOf(propertyName) !== -1) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't know if it is any more performant, but you could use @dojo/shim/array.includes() here which offloads to native...

Copy link
Member Author

@agubler agubler Jul 26, 2017

Choose a reason for hiding this comment

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

I "think" that indexOf performs better generally across our supported platforms, although native includes is slightly better on chrome and firefox according to this benchmark: https://jsperf.com/array-indexof-vs-includes

Copy link
Member

Choose a reason for hiding this comment

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

👍

const diffFunctions = this.getDecorator(`diffProperty:${propertyName}`);
for (let i = 0; i < diffFunctions.length; i++) {
const result = diffFunctions[i](previousProperty, newProperty);
if (result.changed && changedPropertyKeys.indexOf(propertyName) === -1) {
Copy link
Member

Choose a reason for hiding this comment

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

@dojo/shim/array.includes()?


this._properties = diffPropertyResults;

if (changedPropertyKeys.length) {
if (changedPropertyKeys.length > 0) {
Copy link
Member

Choose a reason for hiding this comment

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

💯

}

if (runReactions) {
this._mapDiffPropertyReactions(properties, changedPropertyKeys).forEach((args, reaction) => {
Copy link
Member

Choose a reason for hiding this comment

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

speculating, but with us targeting the down emit and access this in the arrow function, it might be an opportunity to create a bound callback that we cache if this gets called a lot?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not exactly a hot path as only gets called if there is a registered diffProperty.

Copy link
Member

Choose a reason for hiding this comment

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

👍

}

if (dNode.properties.bind === undefined) {
(<any> dNode).properties.bind = this;
Copy link
Member

Choose a reason for hiding this comment

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

why if dNode.properties.bind didn't require a cast on dNode, it does now?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it is readonly...

Copy link
Member

Choose a reason for hiding this comment

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

👍

@agubler
Copy link
Member Author

agubler commented Jul 28, 2017

@kitsonk any more feedback / comments on this one?

this._bindFunctionPropertyMap = new WeakMap<(...args: any[]) => any, { boundFunc: (...args: any[]) => any, scope: any }>();
this._registries = new RegistryHandler();
this._registries.add(registry);
this.own(this._registries);
this._boundRenderFunc = this.render.bind(this);
Copy link
Member

Choose a reason for hiding this comment

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

More of general observation of why we don't use initializers generally... like:

class WidgetBase {
    private _properties = {} as P;
    private _registries = new RegistryHandler();
}

It would cut out a fair amount of typing and is even more readable IMO.

Copy link
Member Author

Choose a reason for hiding this comment

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

I prefer initialising inline also, seemed unrelated to these changes though.

Copy link
Member

Choose a reason for hiding this comment

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

True... 🤷‍♂️

if (diffFunctions.length === 0) {
diffFunctions.push(auto);
const newProperty = this._bindFunctionProperty(properties[propertyName], bind);
if (registeredDiffPropertyNames.indexOf(propertyName) !== -1) {
Copy link
Member

Choose a reason for hiding this comment

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

👍

@@ -198,13 +191,14 @@ export class WidgetBase<P = WidgetProperties, C extends DNode = DNode> extends E
this._properties = <P> {};
Copy link
Member

Choose a reason for hiding this comment

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

Would Object.create(null) perform better? I don't if this gets overwritten or not, but if it doesn't, I suspect it will be a minor performance improvement in property lookups.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think generally it does, I don't think it'll reflect in the benchmarks but I'll update it regardless.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually hasOwnProperty is used by Maquette on properties so we need it to be an object.

Copy link
Member

Choose a reason for hiding this comment

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

DOH! Sorry, I think I remember that now. 😢 Is it worth it to PR maquette to use Object.hasOwnProperty.call(props, key) so that Object.create(null) can be used, or is it just a minimal improvement thing that it wouldn't matter?

Copy link
Member Author

Choose a reason for hiding this comment

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

The honest answer is I don't know how significant it would be, I do suspect minimal.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, other fruit to squeeze... 🍋

@dylans dylans added this to the 2017.08 milestone Jul 29, 2017
@agubler agubler force-pushed the benchmark-tweaks branch 2 times, most recently from 83fd64e to 4a8426d Compare August 2, 2017 09:10
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants