From 78a267e3796e5f0a9939b1152576a072de1a2669 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 6 Oct 2016 15:50:47 -0700 Subject: [PATCH] cmd/compile: cache pointer and slice types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anonymous pointer and slice types are very common and identical anyway, so just reuse them rather than allocating new ones everywhere they appear. Turns out to be a small code/stack size win because SSA relies on gc.Type identity for reusing temporary stack slots: text data bss dec hex filename 6453005 231643 146328 6830976 683b80 go.old 6446660 231643 146328 6824631 6822b7 go.new Saves on memory usage during compile time too, and maybe a small CPU time win, but the benchmarks are pretty noisy: name old time/op new time/op delta Template 342ms ± 8% 339ms ± 9% ~ (p=0.332 n=99+99) Unicode 183ms ± 9% 181ms ±11% ~ (p=0.274 n=95+98) GoTypes 1.05s ± 4% 1.04s ± 3% -1.22% (p=0.000 n=97+95) Compiler 4.49s ± 7% 4.46s ± 6% ~ (p=0.058 n=96+91) name old user-ns/op new user-ns/op delta Template 520M ±17% 522M ±20% ~ (p=0.544 n=98+100) Unicode 331M ±27% 327M ±30% ~ (p=0.615 n=98+98) GoTypes 1.54G ±10% 1.53G ±12% ~ (p=0.173 n=99+100) Compiler 6.33G ±10% 6.33G ±10% ~ (p=0.682 n=98+98) name old alloc/op new alloc/op delta Template 44.5MB ± 0% 44.1MB ± 0% -0.80% (p=0.000 n=97+99) Unicode 37.5MB ± 0% 37.3MB ± 0% -0.44% (p=0.000 n=98+100) GoTypes 126MB ± 0% 124MB ± 0% -1.41% (p=0.000 n=98+99) Compiler 518MB ± 0% 508MB ± 0% -1.90% (p=0.000 n=98+100) name old allocs/op new allocs/op delta Template 441k ± 0% 434k ± 0% -1.76% (p=0.000 n=100+97) Unicode 368k ± 0% 365k ± 0% -0.69% (p=0.000 n=99+99) GoTypes 1.26M ± 0% 1.23M ± 0% -2.27% (p=0.000 n=100+99) Compiler 4.60M ± 0% 4.46M ± 0% -2.96% (p=0.000 n=100+99) Change-Id: I94abce5c57aed0f9c48f567b3ac24c627d4c7c91 Reviewed-on: https://go-review.googlesource.com/30632 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/sizeof_test.go | 2 +- src/cmd/compile/internal/gc/subr.go | 35 ---------------------- src/cmd/compile/internal/gc/type.go | 23 ++++++++++++-- src/cmd/compile/internal/gc/typecheck.go | 5 ++++ 4 files changed, 27 insertions(+), 38 deletions(-) diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go index 1a0e53057c..185b19135a 100644 --- a/src/cmd/compile/internal/gc/sizeof_test.go +++ b/src/cmd/compile/internal/gc/sizeof_test.go @@ -26,7 +26,7 @@ func TestSizeof(t *testing.T) { {Name{}, 52, 80}, {Node{}, 92, 144}, {Sym{}, 60, 112}, - {Type{}, 52, 80}, + {Type{}, 60, 96}, {MapType{}, 20, 40}, {ForwardType{}, 16, 32}, {FuncType{}, 28, 48}, diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 39951ac05a..449a5a62cb 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1122,24 +1122,6 @@ func typehash(t *Type) uint32 { return binary.LittleEndian.Uint32(h[:4]) } -var initPtrtoDone bool - -var ( - ptrToUint8 *Type - ptrToAny *Type - ptrToString *Type - ptrToBool *Type - ptrToInt32 *Type -) - -func initPtrto() { - ptrToUint8 = typPtr(Types[TUINT8]) - ptrToAny = typPtr(Types[TANY]) - ptrToString = typPtr(Types[TSTRING]) - ptrToBool = typPtr(Types[TBOOL]) - ptrToInt32 = typPtr(Types[TINT32]) -} - // ptrto returns the Type *t. // The returned struct must not be modified. func ptrto(t *Type) *Type { @@ -1149,23 +1131,6 @@ func ptrto(t *Type) *Type { if t == nil { Fatalf("ptrto: nil ptr") } - // Reduce allocations by pre-creating common cases. - if !initPtrtoDone { - initPtrto() - initPtrtoDone = true - } - switch t { - case Types[TUINT8]: - return ptrToUint8 - case Types[TINT32]: - return ptrToInt32 - case Types[TANY]: - return ptrToAny - case Types[TSTRING]: - return ptrToString - case Types[TBOOL]: - return ptrToBool - } return typPtr(t) } diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index 4db2b255c8..2dd1184fff 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -146,6 +146,9 @@ type Type struct { nod *Node // canonical OTYPE node Orig *Type // original type (type literal or predefined type) + sliceOf *Type + ptrTo *Type + Sym *Sym // symbol containing name, for named types Vargen int32 // unique name for OTYPE/ONAME Lineno int32 // line at which this type was declared, implicitly or explicitly @@ -414,10 +417,18 @@ func typArray(elem *Type, bound int64) *Type { return t } -// typSlice returns a new slice Type. +// typSlice returns the slice Type with element type elem. func typSlice(elem *Type) *Type { + if t := elem.sliceOf; t != nil { + if t.Elem() != elem { + Fatalf("elem mismatch") + } + return t + } + t := typ(TSLICE) t.Extra = SliceType{Elem: elem} + elem.sliceOf = t return t } @@ -446,12 +457,20 @@ func typMap(k, v *Type) *Type { return t } -// typPtr returns a new pointer type pointing to t. +// typPtr returns the pointer type pointing to t. func typPtr(elem *Type) *Type { + if t := elem.ptrTo; t != nil { + if t.Elem() != elem { + Fatalf("elem mismatch") + } + return t + } + t := typ(Tptr) t.Extra = PtrType{Elem: elem} t.Width = int64(Widthptr) t.Align = uint8(Widthptr) + elem.ptrTo = t return t } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index f2c6f5a3e9..01ca8922d4 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -3506,6 +3506,9 @@ func copytype(n *Node, t *Type) { embedlineno := n.Type.ForwardType().Embedlineno l := n.Type.ForwardType().Copyto + ptrTo := n.Type.ptrTo + sliceOf := n.Type.sliceOf + // TODO(mdempsky): Fix Type rekinding. *n.Type = *t @@ -3519,6 +3522,8 @@ func copytype(n *Node, t *Type) { t.allMethods = Fields{} t.nod = nil t.Deferwidth = false + t.ptrTo = ptrTo + t.sliceOf = sliceOf // Update nodes waiting on this type. for _, n := range l {