-
Notifications
You must be signed in to change notification settings - Fork 642
Open
Labels
Description
There are lots of peaces of code where reciever is concrete value:
type CollectionType struct {
NativeType
Key TypeInfo // only used for TypeMap
Elem TypeInfo // only used for TypeMap, TypeList and TypeSet
}
func (t CollectionType) NewWithError() (interface{}, error) {
typ, err := goType(t)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
As result when NewWithError is called golang recreate copy of reciever, i.e. CollectionType struct.
There is simple way to optimize it is to convert all of them to pointer reciever, which will make these allocations go away.
I have run test on that and here is results.
Before the fix (concrete receiver)
➜ gocql git:(dk/1693-potential-panic-on-deserialization) ✗ go test -bench . -benchmem
goos: linux
goarch: amd64
pkg: github.com/gocql/gocql
cpu: 12th Gen Intel(R) Core(TM) i9-12900HK
BenchmarkMarshal-20 1532197 751.1 ns/op 504 B/op 13 allocs/op
After the fix (pointer receiver)
➜ gocql git:(dk/1693-potential-panic-on-deserialization) ✗ go test -bench . -benchmem
goos: linux
goarch: amd64
pkg: github.com/gocql/gocql
cpu: 12th Gen Intel(R) Core(TM) i9-12900HK
BenchmarkMarshal-20 1793576 676.4 ns/op 312 B/op 11 allocs/op
As you can see size-wize memory allocations went from 504 to 312 B/op and allocations went from 13 to 11 per op.
Test code:
func BenchmarkMarshal(b *testing.B) {
typeInfo := UDTTypeInfo{NativeType{proto: 3, typ: TypeUDT}, "", "xyz", []UDTField{
{Name: "x", Type: &NativeType{proto: 3, typ: TypeInt}},
{Name: "y", Type: &NativeType{proto: 3, typ: TypeInt}},
{Name: "z", Type: &NativeType{proto: 3, typ: TypeInt}},
}}
type NewWithError struct {
Value interface{}
Error error
}
type ResultStore struct {
NewWithError NewWithError
New interface{}
String string
Type Type
Version byte
Custom string
}
store := make([]ResultStore, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rec := &store[i]
rec.NewWithError.Value, rec.NewWithError.Error = typeInfo.NewWithError()
rec.New = typeInfo.New()
rec.String = typeInfo.String()
rec.Type = typeInfo.Type()
rec.Version = typeInfo.Version()
rec.Custom = typeInfo.Custom()
}
}