internal/impl: add fast-path unmarshal
Benchmarks run with:
go test ./benchmarks/ -bench=Wire -benchtime=500ms -benchmem -count=8
Fast-path vs. parent commit:
name old time/op new time/op delta
Wire/Unmarshal/google_message1_proto2-12 1.35µs ± 2% 0.45µs ± 4% -67.01% (p=0.000 n=8+8)
Wire/Unmarshal/google_message1_proto3-12 1.07µs ± 1% 0.31µs ± 1% -71.04% (p=0.000 n=8+8)
Wire/Unmarshal/google_message2-12 691µs ± 2% 188µs ± 2% -72.78% (p=0.000 n=7+8)
name old allocs/op new allocs/op delta
Wire/Unmarshal/google_message1_proto2-12 60.0 ± 0% 25.0 ± 0% -58.33% (p=0.000 n=8+8)
Wire/Unmarshal/google_message1_proto3-12 42.0 ± 0% 7.0 ± 0% -83.33% (p=0.000 n=8+8)
Wire/Unmarshal/google_message2-12 28.6k ± 0% 8.5k ± 0% -70.34% (p=0.000 n=8+8)
Fast-path vs. -v1:
name old time/op new time/op delta
Wire/Unmarshal/google_message1_proto2-12 702ns ± 1% 445ns ± 4% -36.58% (p=0.000 n=8+8)
Wire/Unmarshal/google_message1_proto3-12 604ns ± 1% 311ns ± 1% -48.54% (p=0.000 n=8+8)
Wire/Unmarshal/google_message2-12 179µs ± 3% 188µs ± 2% +5.30% (p=0.000 n=7+8)
name old allocs/op new allocs/op delta
Wire/Unmarshal/google_message1_proto2-12 26.0 ± 0% 25.0 ± 0% -3.85% (p=0.000 n=8+8)
Wire/Unmarshal/google_message1_proto3-12 8.00 ± 0% 7.00 ± 0% -12.50% (p=0.000 n=8+8)
Wire/Unmarshal/google_message2-12 8.49k ± 0% 8.49k ± 0% -0.01% (p=0.000 n=8+8)
Change-Id: I6247ac3fd66a63d9acb902cbd192094ee3d151c3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185147
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/codec_reflect.go b/internal/impl/codec_reflect.go
index 05ceb33..d307efe 100644
--- a/internal/impl/codec_reflect.go
+++ b/internal/impl/codec_reflect.go
@@ -7,6 +7,8 @@
package impl
import (
+ "reflect"
+
"google.golang.org/protobuf/internal/encoding/wire"
)
@@ -22,9 +24,22 @@
return b, nil
}
+func consumeEnum(b []byte, p pointer, wtyp wire.Type, _ unmarshalOptions) (n int, err error) {
+ if wtyp != wire.VarintType {
+ return 0, errUnknown
+ }
+ v, n := wire.ConsumeVarint(b)
+ if n < 0 {
+ return 0, wire.ParseError(n)
+ }
+ p.v.Elem().SetInt(int64(v))
+ return n, nil
+}
+
var coderEnum = pointerCoderFuncs{
- size: sizeEnum,
- marshal: appendEnum,
+ size: sizeEnum,
+ marshal: appendEnum,
+ unmarshal: consumeEnum,
}
func sizeEnumNoZero(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -42,8 +57,9 @@
}
var coderEnumNoZero = pointerCoderFuncs{
- size: sizeEnumNoZero,
- marshal: appendEnumNoZero,
+ size: sizeEnumNoZero,
+ marshal: appendEnumNoZero,
+ unmarshal: consumeEnum,
}
func sizeEnumPtr(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -54,9 +70,20 @@
return appendEnum(b, pointer{p.v.Elem()}, wiretag, opts)
}
+func consumeEnumPtr(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
+ if wtyp != wire.VarintType {
+ return 0, errUnknown
+ }
+ if p.v.Elem().IsNil() {
+ p.v.Elem().Set(reflect.New(p.v.Elem().Type().Elem()))
+ }
+ return consumeEnum(b, pointer{p.v.Elem()}, wtyp, opts)
+}
+
var coderEnumPtr = pointerCoderFuncs{
- size: sizeEnumPtr,
- marshal: appendEnumPtr,
+ size: sizeEnumPtr,
+ marshal: appendEnumPtr,
+ unmarshal: consumeEnumPtr,
}
func sizeEnumSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -67,9 +94,14 @@
return appendEnumSliceReflect(b, p.v.Elem(), wiretag, opts)
}
+func consumeEnumSlice(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
+ return consumeEnumSliceReflect(b, p.v, wtyp, opts)
+}
+
var coderEnumSlice = pointerCoderFuncs{
- size: sizeEnumSlice,
- marshal: appendEnumSlice,
+ size: sizeEnumSlice,
+ marshal: appendEnumSlice,
+ unmarshal: consumeEnumSlice,
}
func sizeEnumPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
@@ -104,6 +136,7 @@
}
var coderEnumPackedSlice = pointerCoderFuncs{
- size: sizeEnumPackedSlice,
- marshal: appendEnumPackedSlice,
+ size: sizeEnumPackedSlice,
+ marshal: appendEnumPackedSlice,
+ unmarshal: consumeEnumSlice,
}