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 <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Matthew Dempsky 2016-10-06 15:50:47 -07:00
parent 15937ccb89
commit 78a267e379
4 changed files with 27 additions and 38 deletions

View file

@ -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},

View file

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

View file

@ -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
}

View file

@ -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 {