-
Notifications
You must be signed in to change notification settings - Fork 4.6k
encoding/proto: enable use cached size option #8569
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
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #8569 +/- ##
==========================================
- Coverage 81.64% 80.56% -1.09%
==========================================
Files 413 413
Lines 40621 40843 +222
==========================================
- Hits 33167 32906 -261
- Misses 5991 6260 +269
- Partials 1463 1677 +214
🚀 New features to boost your workflow:
|
The code seems okay but I am not sure if we want to do that especially since the description for
On the other side it also says that it asserts that nothing has changed in between :
So I would like other maintainers opinion on this. cc @dfawley @easwars @arjan-bal |
return nil, fmt.Errorf("proto: failed to marshal, message is %T, want proto.Message", v) | ||
} | ||
|
||
size := proto.Size(vv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this seems to rely on a runtime behaviour of calling proto.Size(vv)
before using the cached size (please correct me if I'm wrong), we should call this out in a code comment just above this to serve as a warning for future code authors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we don't call proto.Size(vv)
here, we could end up using a stale cached size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would this be cleaner? rs-unity@188bece rs-unity@ec0c47e
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring of UseCachedSize
does say the following:
// UseCachedSize indicates that the result of a previous Size call
// may be reused.****
And that if that condition is not met, bad things might happen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just want to flag an edge case that normally shouldn’t happen: if another part of the stack keeps a reference to the proto message and it’s shared across multiple Go routines, one routine might modify the message while another is marshaling it through this codec. In that situation, enabling UseCachedSize
becomes risky.
That said, the issue I’m describing would still cause (other) problems even if UseCachedSize
isn’t enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the comment: rs-unity@ec0c47e
…ying the use of UseCachedSize
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you also be able to run the benchmarks here: https://github.com/grpc/grpc-go/tree/master/benchmark and report the results? Thanks.
return nil, fmt.Errorf("proto: failed to marshal, message is %T, want proto.Message", v) | ||
} | ||
|
||
size := proto.Size(vv) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring of UseCachedSize
does say the following:
// UseCachedSize indicates that the result of a previous Size call
// may be reused.****
And that if that condition is not met, bad things might happen.
Here are the commands to run them: # get the baseline performance
git checkout master
RUN_NAME="unary-before"
go run benchmark/benchmain/main.go -benchtime=60s -workloads=unary \
-compression=off -maxConcurrentCalls=120 -trace=off \
-reqSizeBytes=1024 -respSizeBytes=1024 -networkMode=Local -resultFile="${RUN_NAME}" -recvBufferPool=simple
# get the performance with the improvements
git checkout use-cached-size
RUN_NAME="unary-after"
go run benchmark/benchmain/main.go -benchtime=60s -workloads=unary \
-compression=off -maxConcurrentCalls=120 -trace=off \
-reqSizeBytes=1024 -respSizeBytes=1024 -networkMode=Local -resultFile="${RUN_NAME}" -recvBufferPool=simple
# generate a report
go run benchmark/benchresult/main.go unary-before unary-after I suspect the benchmarks may not show a significant improvement since they use a very simple proto with a shallow schema. |
In our workload, the improvements had a big impact, we were able to cut node count by 10–20%. That said, our use case is pretty unique since we’re serving over 200M payloads per second. Here's the results of the benchmarks based on @arjan-bal command:
Here's the results of the benchmarks based on a test closer to our workload:
|
8a1ee43
to
ec0c47e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the improvement! We'll wait for a second approval before merging.
Enable UseCachedSize in proto marshal to eliminate redundant size computation
Fixes: #8570
The proto message size was previously being computed twice: once before marshalling and again during the marshalling call itself. In high-throughput workloads, this duplicated computation is expensive.
By enabling
UseCachedSize
onMarshalOptions
, we reuse the size calculated immediately before marshalling, avoiding the second call toproto.Size
.In our application, the redundant size call accounted for ~12% of total CPU time. With this change, we eliminate that overhead while preserving correctness.
RELEASE NOTES: