Skip to content

Memory allocations optimization #1695

@dkropachev

Description

@dkropachev

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()
	}
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions