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

Expect same message types in mergeFromMessage #661

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

osa1
Copy link
Member

@osa1 osa1 commented May 24, 2022

This PR refactors GeneratedMessage.mergeFromMessage to check that messages
being merged have the same type. mergeFromMessage now throws an
ArgumentError if the messages have different types.

Type check is implemented by comparing message BuilderInfos for pointer
equality.

This allows simplifying the merge logic and avoiding some checks. The new
version is ~7% faster:

(Using deepCopy benchmark as deepCopy is implemented as merging empty message
with the message being copied)

Before:

protobuf_deep_copy(RunTimeRaw): 610.7286585365854 us.
protobuf_deep_copy(RunTimeRaw): 610.3725609756098 us.
protobuf_deep_copy(RunTimeRaw): 605.0148036253777 us.

After:

protobuf_deep_copy(RunTimeRaw): 561.1190476190476 us.
protobuf_deep_copy(RunTimeRaw): 552.5508287292818 us.
protobuf_deep_copy(RunTimeRaw): 547.2497267759562 us.

_validateField at the end of _mergeField removed: we already have a valid
message so the field value must be valid for the message type. _validateField
also checks that the message is writable, which is also unnecessary as we check
it in _mergeFromMessage.

Fixes #60

@rakudrama
Copy link
Contributor

Fixes #60

@rakudrama do you have any benchmarks for this?

There are a few different ways to implement this. We could move the sameMessage check to the outside of the loop, or add a fast path check in _mergeField. Not sure which one will perform the best without benchmarks.

I'm also not sure which approach would be best.
I don't now of any benchmarks other than the Golem ones.
I think it would be worth auditing the existing benchmarks and perhaps adding some benchmarks that you know are representative of real app scenarios.

@osa1
Copy link
Member Author

osa1 commented Jun 29, 2022

I think we should be able to benchmark this by using deepCopy, which uses mergeFromMessage:

T deepCopy() => info_.createEmptyInstance!() as T..mergeFromMessage(this);

Currently we have 2 somewhat large messages in benchmarks:

  • The message in query_benchmark is 246K. This message has lots of strings.
  • google_message2 in protobuf_benchmarks is 83K. I don't know about the structure of this message.

We can add a benchmark that measures deepCopy of these messages.

Note: these benchmarks will be merged to benchmarks/ soon: #698

@osa1
Copy link
Member Author

osa1 commented Aug 5, 2022

I added a new benchmark to measure deepCopy time and this seems to significantly improve it.

AOT, master:

protobuf_deep_copy(RunTimeRaw): 625.190625 us.
protobuf_deep_copy(RunTimeRaw): 627.7799373040752 us.
protobuf_deep_copy(RunTimeRaw): 625.09375 us.

AOT, this PR:

protobuf_deep_copy(RunTimeRaw): 475.6320665083135 us.
protobuf_deep_copy(RunTimeRaw): 476.2588095238095 us.
protobuf_deep_copy(RunTimeRaw): 475.4239904988123 us.

Diff: -24%

JS, master:

protobuf_deep_copy(RunTimeRaw): 738.3763837638377 us.
protobuf_deep_copy(RunTimeRaw): 680 us.
protobuf_deep_copy(RunTimeRaw): 729.9270072992701 us.

JS, this PR:

protobuf_deep_copy(RunTimeRaw): 639.297124600639 us.
protobuf_deep_copy(RunTimeRaw): 669.2307692307693 us.
protobuf_deep_copy(RunTimeRaw): 659.2105263157895 us.

Diff: -8%

This should improve clone as the code generated for clone is identical to deepCopy implementation.

@osa1 osa1 marked this pull request as ready for review August 5, 2022 08:35
@osa1
Copy link
Member Author

osa1 commented Aug 6, 2022

We should also try implementing a deepCopy that is actually implemented as cloning, instead of merging the message to an empty message.

@osa1
Copy link
Member Author

osa1 commented Aug 25, 2022

We should also try implementing a deepCopy that is actually implemented as cloning, instead of merging the message to an empty message.

This is done in #742 which halves AOT deepCopy benchmark runtime.

@osa1
Copy link
Member Author

osa1 commented Sep 12, 2022

Sigurd asked about whether it makes sense to allow merging messages with different types. I think it doesn't, and I tried adding this to the merge method and tested the code internally:

if (!identical(_meta, other._meta)) {
  throw 'Merging messages with different builder infos';
}

To my surprise, this doesn't break anything.

So I will simplify the merge implementation in this PR and assume that we're always merging messages of same types. The code will be simpler, and with the same performance wins.

@osa1 osa1 changed the title Implement fast path when merging fields of same message Expect same message types in _mergeFromMessage Sep 12, 2022
@osa1 osa1 changed the title Expect same message types in _mergeFromMessage Expect same message types in mergeFromMessage Sep 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cloning should avoid validation checks
2 participants