internal/impl: improve extension fast path performance
Stash fast-path information for extensions on the ExtensionInfo. In
the usual case where an ExtensionType's underlying implementation is
an *ExtensionInfo, fetching the fast-path information becomes a type
assertion rather than a mutex-guarded map access.
Maintain a global sync.Map for the case where an ExtensionType isn't an
*ExtensionInfo.
Substantially improves performance for fast-path operations on
extensions:
Encode/MessageSet_type_id_before_message_content-12 267ns ± 1% 185ns ± 1% -30.44% (p=0.001 n=7+7)
Encode/basic_scalar_types_(*test.TestAllExtensions)-12 1.94µs ± 1% 0.40µs ± 1% -79.32% (p=0.000 n=8+7)
Change-Id: If048b521deb3665a090ea3d0a178c61691d4201e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/210540
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/encode.go b/internal/impl/encode.go
index cd57998..4ce3b1d 100644
--- a/internal/impl/encode.go
+++ b/internal/impl/encode.go
@@ -155,7 +155,7 @@
return 0
}
for _, x := range *ext {
- xi := mi.extensionFieldInfo(x.Type())
+ xi := getExtensionFieldInfo(x.Type())
if xi.funcs.size == nil {
continue
}
@@ -176,7 +176,7 @@
// Fast-path for one extension: Don't bother sorting the keys.
var err error
for _, x := range *ext {
- xi := mi.extensionFieldInfo(x.Type())
+ xi := getExtensionFieldInfo(x.Type())
b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
}
return b, err
@@ -191,7 +191,7 @@
var err error
for _, k := range keys {
x := (*ext)[int32(k)]
- xi := mi.extensionFieldInfo(x.Type())
+ xi := getExtensionFieldInfo(x.Type())
b, err = xi.funcs.marshal(b, x.Value(), xi.wiretag, opts)
if err != nil {
return b, err