From 39a67915b8fedffd4a7ffde075741c71b253f3f3 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 28 Jan 2021 18:16:08 +0100 Subject: [PATCH] sizegen: implement unit tests Signed-off-by: Vicent Marti --- go/tools/sizegen/integration/cached_size.go | 225 ++++++++++++++++++ .../sizegen/integration/integration_test.go | 85 +++++++ go/tools/sizegen/integration/types.go | 76 ++++++ go/tools/sizegen/sizegen.go | 16 +- go/tools/sizegen/sizegen_test.go | 16 ++ 5 files changed, 413 insertions(+), 5 deletions(-) create mode 100644 go/tools/sizegen/integration/cached_size.go create mode 100644 go/tools/sizegen/integration/integration_test.go create mode 100644 go/tools/sizegen/integration/types.go diff --git a/go/tools/sizegen/integration/cached_size.go b/go/tools/sizegen/integration/cached_size.go new file mode 100644 index 00000000000..7ceba285138 --- /dev/null +++ b/go/tools/sizegen/integration/cached_size.go @@ -0,0 +1,225 @@ +/* +Copyright 2021 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by Sizegen. DO NOT EDIT. + +package integration + +import ( + "math" + "reflect" + "unsafe" +) + +type cachedObject interface { + CachedSize(alloc bool) int64 +} + +func (cached *A) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(16) + } + return size +} +func (cached *Bimpl) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(8) + } + return size +} +func (cached *C) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(16) + } + // field field1 vitess.io/vitess/go/tools/sizegen/integration.B + if cc, ok := cached.field1.(cachedObject); ok { + size += cc.CachedSize(true) + } + return size +} +func (cached *D) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(8) + } + // field field1 *vitess.io/vitess/go/tools/sizegen/integration.Bimpl + if cached.field1 != nil { + size += int64(8) + } + return size +} + +//go:nocheckptr +func (cached *Map1) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(8) + } + // field field1 map[uint8]uint8 + if cached.field1 != nil { + size += int64(48) + hmap := reflect.ValueOf(cached.field1) + numBuckets := int(math.Pow(2, float64((*(*uint8)(unsafe.Pointer(hmap.Pointer() + uintptr(9))))))) + numOldBuckets := (*(*uint16)(unsafe.Pointer(hmap.Pointer() + uintptr(10)))) + size += int64(numOldBuckets * 32) + if len(cached.field1) > 0 || numBuckets > 1 { + size += int64(numBuckets * 32) + } + } + return size +} + +//go:nocheckptr +func (cached *Map2) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(8) + } + // field field1 map[uint64]vitess.io/vitess/go/tools/sizegen/integration.A + if cached.field1 != nil { + size += int64(48) + hmap := reflect.ValueOf(cached.field1) + numBuckets := int(math.Pow(2, float64((*(*uint8)(unsafe.Pointer(hmap.Pointer() + uintptr(9))))))) + numOldBuckets := (*(*uint16)(unsafe.Pointer(hmap.Pointer() + uintptr(10)))) + size += int64(numOldBuckets * 208) + if len(cached.field1) > 0 || numBuckets > 1 { + size += int64(numBuckets * 208) + } + } + return size +} + +//go:nocheckptr +func (cached *Map3) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(8) + } + // field field1 map[uint64]vitess.io/vitess/go/tools/sizegen/integration.B + if cached.field1 != nil { + size += int64(48) + hmap := reflect.ValueOf(cached.field1) + numBuckets := int(math.Pow(2, float64((*(*uint8)(unsafe.Pointer(hmap.Pointer() + uintptr(9))))))) + numOldBuckets := (*(*uint16)(unsafe.Pointer(hmap.Pointer() + uintptr(10)))) + size += int64(numOldBuckets * 208) + if len(cached.field1) > 0 || numBuckets > 1 { + size += int64(numBuckets * 208) + } + for _, v := range cached.field1 { + if cc, ok := v.(cachedObject); ok { + size += cc.CachedSize(true) + } + } + } + return size +} +func (cached *Padded) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(24) + } + return size +} +func (cached *Slice1) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(24) + } + // field field1 []vitess.io/vitess/go/tools/sizegen/integration.A + { + size += int64(cap(cached.field1)) * int64(16) + } + return size +} +func (cached *Slice2) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(24) + } + // field field1 []vitess.io/vitess/go/tools/sizegen/integration.B + { + size += int64(cap(cached.field1)) * int64(16) + for _, elem := range cached.field1 { + if cc, ok := elem.(cachedObject); ok { + size += cc.CachedSize(true) + } + } + } + return size +} +func (cached *Slice3) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(24) + } + // field field1 []*vitess.io/vitess/go/tools/sizegen/integration.Bimpl + { + size += int64(cap(cached.field1)) * int64(8) + for _, elem := range cached.field1 { + if elem != nil { + size += int64(8) + } + } + } + return size +} +func (cached *String1) CachedSize(alloc bool) int64 { + if cached == nil { + return int64(0) + } + size := int64(0) + if alloc { + size += int64(24) + } + // field field1 string + size += int64(len(cached.field1)) + return size +} diff --git a/go/tools/sizegen/integration/integration_test.go b/go/tools/sizegen/integration/integration_test.go new file mode 100644 index 00000000000..d2c22a2cbcd --- /dev/null +++ b/go/tools/sizegen/integration/integration_test.go @@ -0,0 +1,85 @@ +/* +Copyright 2021 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package integration + +import ( + "fmt" + "testing" +) + +func TestTypeSizes(t *testing.T) { + const PtrSize = 8 + const SliceHeaderSize = 3 * PtrSize + const FatPointerSize = 2 * PtrSize + const BucketHeaderSize = 8 + const BucketSize = 8 + const HashMapHeaderSize = 48 + + cases := []struct { + obj cachedObject + size int64 + }{ + {&A{}, 16}, + {&C{}, 16}, + {&C{field1: &Bimpl{}}, 24}, + {&D{}, 8}, + {&D{field1: &Bimpl{}}, 16}, + {&Padded{}, 24}, + + {&Slice1{}, 24}, + {&Slice1{field1: []A{}}, SliceHeaderSize}, + {&Slice1{field1: []A{{}}}, SliceHeaderSize + 16}, + {&Slice1{field1: []A{{}, {}, {}, {}}}, SliceHeaderSize + 16*4}, + + {&Slice2{}, SliceHeaderSize}, + {&Slice2{field1: []B{}}, SliceHeaderSize}, + {&Slice2{field1: []B{&Bimpl{}}}, SliceHeaderSize + FatPointerSize*1 + 8*1}, + {&Slice2{field1: []B{&Bimpl{}, &Bimpl{}, &Bimpl{}, &Bimpl{}}}, SliceHeaderSize + FatPointerSize*4 + 8*4}, + + {&Slice3{}, SliceHeaderSize}, + {&Slice3{field1: []*Bimpl{}}, SliceHeaderSize}, + {&Slice3{field1: []*Bimpl{nil}}, SliceHeaderSize + PtrSize*1 + 0}, + {&Slice3{field1: []*Bimpl{nil, nil, nil, nil}}, SliceHeaderSize + PtrSize*4 + 0}, + {&Slice3{field1: []*Bimpl{{}}}, SliceHeaderSize + PtrSize*1 + 8*1}, + {&Slice3{field1: []*Bimpl{{}, {}, {}, {}}}, SliceHeaderSize + PtrSize*4 + 8*4}, + + {&Map1{field1: nil}, PtrSize}, + {&Map1{field1: map[uint8]uint8{}}, PtrSize + HashMapHeaderSize}, + {&Map1{field1: map[uint8]uint8{0: 0}}, PtrSize + HashMapHeaderSize + BucketHeaderSize + 1*BucketSize + 1*BucketSize + PtrSize}, + + {&Map2{field1: nil}, PtrSize}, + {&Map2{field1: map[uint64]A{}}, PtrSize + HashMapHeaderSize}, + {&Map2{field1: map[uint64]A{0: {}}}, PtrSize + HashMapHeaderSize + BucketHeaderSize + 8*BucketSize + 16*BucketSize + PtrSize}, + + {&Map3{field1: nil}, PtrSize}, + {&Map3{field1: map[uint64]B{}}, PtrSize + HashMapHeaderSize}, + {&Map3{field1: map[uint64]B{0: &Bimpl{}}}, PtrSize + HashMapHeaderSize + BucketHeaderSize + 8*BucketSize + FatPointerSize*BucketSize + PtrSize + 8}, + {&Map3{field1: map[uint64]B{0: nil}}, PtrSize + HashMapHeaderSize + BucketHeaderSize + 8*BucketSize + FatPointerSize*BucketSize + PtrSize}, + + {&String1{}, PtrSize*2 + 8}, + {&String1{field1: "1234"}, PtrSize*2 + 8 + 4}, + } + + for _, tt := range cases { + t.Run(fmt.Sprintf("sizeof(%T)", tt.obj), func(t *testing.T) { + size := tt.obj.CachedSize(true) + if size != tt.size { + t.Errorf("expected %T to be %d bytes, got %d", tt.obj, tt.size, size) + } + }) + } +} diff --git a/go/tools/sizegen/integration/types.go b/go/tools/sizegen/integration/types.go new file mode 100644 index 00000000000..c05b08cfd07 --- /dev/null +++ b/go/tools/sizegen/integration/types.go @@ -0,0 +1,76 @@ +/* +Copyright 2021 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//nolint +package integration + +type A struct { + field1 uint64 + field2 uint64 +} + +type B interface { + iface() +} + +type Bimpl struct { + field1 uint64 +} + +func (b *Bimpl) iface() {} + +type C struct { + field1 B +} + +type D struct { + field1 *Bimpl +} + +type Padded struct { + field1 uint64 + field2 uint8 + field3 uint64 +} + +type Slice1 struct { + field1 []A +} + +type Slice2 struct { + field1 []B +} + +type Slice3 struct { + field1 []*Bimpl +} + +type Map1 struct { + field1 map[uint8]uint8 +} + +type Map2 struct { + field1 map[uint64]A +} + +type Map3 struct { + field1 map[uint64]B +} + +type String1 struct { + field1 string + field2 uint64 +} diff --git a/go/tools/sizegen/sizegen.go b/go/tools/sizegen/sizegen.go index 90a5960f0f0..4de3862f96d 100644 --- a/go/tools/sizegen/sizegen.go +++ b/go/tools/sizegen/sizegen.go @@ -533,12 +533,18 @@ func generateCode(loaded []*packages.Package, generate typePaths) (*sizegen, err return nil, fmt.Errorf("no scope found for type '%s'", gen) } - tt := scope.Lookup(typename) - if tt == nil { - return nil, fmt.Errorf("no type called '%s' found in '%s'", typename, pkgname) - } + if typename == "*" { + for _, name := range scope.Names() { + sizegen.generateKnownType(scope.Lookup(name).Type().(*types.Named)) + } + } else { + tt := scope.Lookup(typename) + if tt == nil { + return nil, fmt.Errorf("no type called '%s' found in '%s'", typename, pkgname) + } - sizegen.generateKnownType(tt.Type().(*types.Named)) + sizegen.generateKnownType(tt.Type().(*types.Named)) + } } return sizegen, nil diff --git a/go/tools/sizegen/sizegen_test.go b/go/tools/sizegen/sizegen_test.go index 784a585f2f4..4eb523aa383 100644 --- a/go/tools/sizegen/sizegen_test.go +++ b/go/tools/sizegen/sizegen_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2021 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + package main import (