Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove fold() closures from FieldSet._hashCode. #554

Merged
merged 1 commit into from
Apr 23, 2022

Conversation

LorenVS
Copy link
Contributor

@LorenVS LorenVS commented Nov 12, 2021

The fold() calls come with significant runtime cost, and make it more
difficult to hoist accesses to commonly used variables. Just rewriting
this pattern shows a significant performance improvement for both JS and
VM benchmarks.

Baseline

JS
HashCode(RunTime): 9833.333333333334 us.
HashCode(RunTime): 9891.625615763547 us.
HashCode(RunTime): 9607.655502392345 us.
HashCode(RunTime): 9661.835748792271 us.
HashCode(RunTime): 9765.853658536585 us.
VM
HashCode(RunTime): 4527.384615384615 us.
HashCode(RunTime): 4534.151583710407 us.
HashCode(RunTime): 4546.556818181818 us.
HashCode(RunTime): 4490.65470852017

Results

JS
HashCode(RunTime): 8004 us.
HashCode(RunTime): 7980.0796812749 us.
HashCode(RunTime): 7976.095617529881 us.
HashCode(RunTime): 7824.21875 us.
HashCode(RunTime): 7847.058823529412 us.
VM
HashCode(RunTime): 2474.5451174289246 us.
HashCode(RunTime): 2533.7037974683544 us.
HashCode(RunTime): 2532.4556962025317 us.
HashCode(RunTime): 2420.072551390568 us.
HashCode(RunTime): 2521.3198992443326

@google-cla google-cla bot added the cla: yes label Nov 12, 2021
The fold() calls come with significant runtime cost, and make it more
difficult to hoist accesses to commonly used variables. Just rewriting
this pattern shows a significant performance improvement for both JS and
VM benchmarks.

Baseline

```
JS
HashCode(RunTime): 9833.333333333334 us.
HashCode(RunTime): 9891.625615763547 us.
HashCode(RunTime): 9607.655502392345 us.
HashCode(RunTime): 9661.835748792271 us.
HashCode(RunTime): 9765.853658536585 us.
VM
HashCode(RunTime): 4527.384615384615 us.
HashCode(RunTime): 4534.151583710407 us.
HashCode(RunTime): 4546.556818181818 us.
HashCode(RunTime): 4490.65470852017
```

Results

```
JS
HashCode(RunTime): 8004 us.
HashCode(RunTime): 7980.0796812749 us.
HashCode(RunTime): 7976.095617529881 us.
HashCode(RunTime): 7824.21875 us.
HashCode(RunTime): 7847.058823529412 us.
VM
HashCode(RunTime): 2474.5451174289246 us.
HashCode(RunTime): 2533.7037974683544 us.
HashCode(RunTime): 2532.4556962025317 us.
HashCode(RunTime): 2420.072551390568 us.
HashCode(RunTime): 2521.3198992443326
```
Copy link
Contributor

@rakudrama rakudrama left a comment

Choose a reason for hiding this comment

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

Looks good.
Do you think the existing tests are adequate to pick up a bug if you had introduced one?
(I don't think you did, but that is always a concern.)

});
// Hash with non-extension fields.
final values = _values;
for (final fi in _infosSortedByTag) {
Copy link
Contributor

Choose a reason for hiding this comment

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

_hashObjects, called at line 671, also uses fold

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is a big difference between these two patterns. The function passed to fold() in _hashObjects doesn't capture any local variables. I tested modifying that one as well and it was a regression in both JS and VM cases.

@sigurdm
Copy link
Collaborator

sigurdm commented Nov 15, 2021

I wonder, now that we're looking into the hashing, if _HashUtils could be replaced by Object.hash() and Object.hashAll, and if it would give any performance benefit...

@rakudrama
Copy link
Contributor

I wonder, now that we're looking into the hashing, if _HashUtils could be replaced by Object.hash() and Object.hashAll, and if it would give any performance benefit...

I suspect performance would be worse. There is no way way Object.hash and Object.hashAll to code a loop other than passing some Iterable to Object.hashAll. I think Loren's code would have the performance benefit since it combines the hash the tag and the values for each field. These would end up being in a temporary list if one had to use Object.hashAll.

I recommend this change goes ahead as-is. It is a nice performance boost for real apps.

Sigurd, are you an 'owner' that can approve this change?

@sigurdm
Copy link
Collaborator

sigurdm commented Nov 16, 2021

I think protobuf is a bit "between owners". My main worry is the syncing to our internal repo. But besides that I approve - feel free to merge.

Copy link
Member

@osa1 osa1 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 also run the benchmarks locally again and got similar improvements.

One of the CI checks was cancelled but for some reason I can't restart it now. Merging.

@osa1 osa1 merged commit 767ce81 into google:master Apr 23, 2022
osa1 added a commit to osa1/protobuf.dart that referenced this pull request Apr 23, 2022
@osa1
Copy link
Member

osa1 commented May 19, 2022

Ported to internal in cl/449694660.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants