Skip to content

Commit 0f45079

Browse files
authored
encoding/proto: enable use cached size option (#8569)
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` on `MarshalOptions`, we reuse the size calculated immediately before marshalling, avoiding the second call to `proto.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: - encoding/proto: Avoid redundant message size calculation when marshalling.
1 parent 8420f3f commit 0f45079

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

encoding/proto/proto.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,33 @@ func (c *codecV2) Marshal(v any) (data mem.BufferSlice, err error) {
4646
return nil, fmt.Errorf("proto: failed to marshal, message is %T, want proto.Message", v)
4747
}
4848

49+
// Important: if we remove this Size call then we cannot use
50+
// UseCachedSize in MarshalOptions below.
4951
size := proto.Size(vv)
52+
53+
// MarshalOptions with UseCachedSize allows reusing the result from the
54+
// previous Size call. This is safe here because:
55+
//
56+
// 1. We just computed the size.
57+
// 2. We assume the message is not being mutated concurrently.
58+
//
59+
// Important: If the proto.Size call above is removed, using UseCachedSize
60+
// becomes unsafe and may lead to incorrect marshaling.
61+
//
62+
// For more details, see the doc of UseCachedSize:
63+
// https://pkg.go.dev/google.golang.org/protobuf/proto#MarshalOptions
64+
marshalOptions := proto.MarshalOptions{UseCachedSize: true}
65+
5066
if mem.IsBelowBufferPoolingThreshold(size) {
51-
buf, err := proto.Marshal(vv)
67+
buf, err := marshalOptions.Marshal(vv)
5268
if err != nil {
5369
return nil, err
5470
}
5571
data = append(data, mem.SliceBuffer(buf))
5672
} else {
5773
pool := mem.DefaultBufferPool()
5874
buf := pool.Get(size)
59-
if _, err := (proto.MarshalOptions{}).MarshalAppend((*buf)[:0], vv); err != nil {
75+
if _, err := marshalOptions.MarshalAppend((*buf)[:0], vv); err != nil {
6076
pool.Put(buf)
6177
return nil, err
6278
}

0 commit comments

Comments
 (0)