From: Matthew Dempsky Date: Thu, 6 Oct 2016 22:50:47 +0000 (-0700) Subject: cmd/compile: cache pointer and slice types X-Git-Tag: go1.8beta1~983 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=78a267e3796e5f0a9939b1152576a072de1a2669;p=gostls13.git cmd/compile: cache pointer and slice types 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 --- 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 {