]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/gob: avoid a pointer to wireType in typeInfo
authorDaniel Martí <mvdan@mvdan.cc>
Sat, 25 Mar 2023 11:48:41 +0000 (11:48 +0000)
committerDaniel Martí <mvdan@mvdan.cc>
Wed, 29 Mar 2023 22:57:25 +0000 (22:57 +0000)
wireType itself is just a struct with seven pointer fields,
so an indirection doesn't feel necessary to noticeably reduce the amount
of memory that typeInfo takes for each Go type registered in gob.

The indirection does add a small amount of overhead though,
particularly one extra allocation when registering a type,
which is done a number of times as part of init.

For consistency, also update wireTypeUserInfo to not use a pointer.

Measuring via one of the end-to-end benchmarks and benchinit:

goos: linux
goarch: amd64
pkg: encoding/gob
cpu: AMD Ryzen 7 PRO 5850U with Radeon Graphics
│     old     │                new                 │
│   sec/op    │   sec/op     vs base               │
EndToEndPipe-16   736.8n ± 5%   733.9n ± 5%       ~ (p=0.971 n=10)
EncodingGob       177.6µ ± 0%   173.6µ ± 0%  -2.27% (p=0.000 n=10)
geomean           11.44µ        11.29µ       -1.34%

│     old      │                  new                  │
│     B/op     │     B/op      vs base                 │
EndToEndPipe-16   1.766Ki ± 0%   1.766Ki ± 0%       ~ (p=1.000 n=10) ¹
EncodingGob       38.47Ki ± 0%   38.27Ki ± 0%  -0.50% (p=0.000 n=10)
geomean           8.241Ki        8.220Ki       -0.25%
¹ all samples are equal

│    old     │                 new                 │
│ allocs/op  │ allocs/op   vs base                 │
EndToEndPipe-16   2.000 ± 0%   2.000 ± 0%       ~ (p=1.000 n=10) ¹
EncodingGob       652.0 ± 0%   642.0 ± 0%  -1.53% (p=0.000 n=10)
geomean           36.11        35.83       -0.77%
¹ all samples are equal

Change-Id: I528080b7d990ed595683f155a1ae25dcd26394b2
Reviewed-on: https://go-review.googlesource.com/c/go/+/479398
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Rob Pike <r@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/encoding/gob/type.go

index 41204bfb7fbb00d0167232818a1d35223a3e079a..f8b7b24db794fc2d9476e00861e05650aed36c60 100644 (file)
@@ -263,7 +263,7 @@ var (
 
 // Predefined because it's needed by the Decoder
 var tWireType = mustGetTypeInfo(reflect.TypeOf((*wireType)(nil)).Elem()).id
-var wireTypeUserInfo *userTypeInfo // userTypeInfo of (*wireType)
+var wireTypeUserInfo *userTypeInfo // userTypeInfo of wireType
 
 func init() {
        // Some magic numbers to make sure there are no surprises.
@@ -284,7 +284,7 @@ func init() {
        }
        idToType = idToType[:firstUserId]
        registerBasics()
-       wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)))
+       wireTypeUserInfo = userType(reflect.TypeOf((*wireType)(nil)).Elem())
 }
 
 // Array type
@@ -675,7 +675,7 @@ type typeInfo struct {
        id      typeId
        encInit sync.Mutex // protects creation of encoder
        encoder atomic.Pointer[encEngine]
-       wire    *wireType
+       wire    wireType
 }
 
 // typeInfoMap is an atomic pointer to map[reflect.Type]*typeInfo.
@@ -736,27 +736,27 @@ func buildTypeInfo(ut *userTypeInfo, rt reflect.Type) (*typeInfo, error) {
                gt := userType.id().gobType().(*gobEncoderType)
                switch ut.externalEnc {
                case xGob:
-                       info.wire = &wireType{GobEncoderT: gt}
+                       info.wire.GobEncoderT = gt
                case xBinary:
-                       info.wire = &wireType{BinaryMarshalerT: gt}
+                       info.wire.BinaryMarshalerT = gt
                case xText:
-                       info.wire = &wireType{TextMarshalerT: gt}
+                       info.wire.TextMarshalerT = gt
                }
                rt = ut.user
        } else {
                t := info.id.gobType()
                switch typ := rt; typ.Kind() {
                case reflect.Array:
-                       info.wire = &wireType{ArrayT: t.(*arrayType)}
+                       info.wire.ArrayT = t.(*arrayType)
                case reflect.Map:
-                       info.wire = &wireType{MapT: t.(*mapType)}
+                       info.wire.MapT = t.(*mapType)
                case reflect.Slice:
                        // []byte == []uint8 is a special case handled separately
                        if typ.Elem().Kind() != reflect.Uint8 {
-                               info.wire = &wireType{SliceT: t.(*sliceType)}
+                               info.wire.SliceT = t.(*sliceType)
                        }
                case reflect.Struct:
-                       info.wire = &wireType{StructT: t.(*structType)}
+                       info.wire.StructT = t.(*structType)
                }
        }