internal/impl: inline coderInfoFields for better cache locality
Microbenchmarks are inconclusive/noisy, but shows a small but noticeable
improvement on internal benchmarks.
Change-Id: Ic46c6aac8a42c4dc749c4f3583d8c8c95e9548b7
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/229277
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/codec_message.go b/internal/impl/codec_message.go
index 370ec65..03b096e 100644
--- a/internal/impl/codec_message.go
+++ b/internal/impl/codec_message.go
@@ -31,6 +31,11 @@
needsInitCheck bool
isMessageSet bool
numRequiredFields uint8
+
+ // Include space for a number of coderFieldInfos to improve cache locality.
+ // The number of entries is chosen through a combination of guesswork and
+ // empirical testing.
+ coderFieldBuf [32]coderFieldInfo
}
type coderFieldInfo struct {
@@ -53,6 +58,7 @@
mi.coderFields = make(map[protowire.Number]*coderFieldInfo)
fields := mi.Desc.Fields()
+ preallocFields := mi.coderFieldBuf[:]
for i := 0; i < fields.Len(); i++ {
fd := fields.Get(i)
@@ -80,7 +86,14 @@
fieldOffset = offsetOf(fs, mi.Exporter)
childMessage, funcs = fieldCoder(fd, ft)
}
- cf := &coderFieldInfo{
+ var cf *coderFieldInfo
+ if len(preallocFields) > 0 {
+ cf = &preallocFields[0]
+ preallocFields = preallocFields[1:]
+ } else {
+ cf = new(coderFieldInfo)
+ }
+ *cf = coderFieldInfo{
num: fd.Number(),
offset: fieldOffset,
wiretag: wiretag,