]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: reduce allocations in prove by reusing posets
authorGiovanni Bajo <rasky@develer.com>
Mon, 30 Apr 2018 22:57:57 +0000 (00:57 +0200)
committerGiovanni Bajo <rasky@develer.com>
Mon, 14 May 2018 14:44:55 +0000 (14:44 +0000)
In prove, reuse posets between different functions by storing them
in the per-worker cache.

Allocation count regression caused by prove improvements is down
from 5% to 3% after this CL.

Updates #25179

Change-Id: I6d14003109833d9b3ef5165fdea00aa9c9e952e8
Reviewed-on: https://go-review.googlesource.com/110455
Run-TryBot: Giovanni Bajo <rasky@develer.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
src/cmd/compile/internal/ssa/cache.go
src/cmd/compile/internal/ssa/func.go
src/cmd/compile/internal/ssa/poset.go
src/cmd/compile/internal/ssa/poset_test.go
src/cmd/compile/internal/ssa/prove.go

index b30af6304d48b44790925bb06579cd2d39511167..f306a1959e75cc3ee6afe4359af1a9ed90d76913 100644 (file)
@@ -24,6 +24,7 @@ type Cache struct {
        domblockstore []ID         // scratch space for computing dominators
        scrSparseSet  []*sparseSet // scratch sparse sets to be re-used.
        scrSparseMap  []*sparseMap // scratch sparse maps to be re-used.
+       scrPoset      []*poset     // scratch poset to be reused
 
        ValueToProgAfter []*obj.Prog
        debugState       debugState
index a2991040eec3574aafa0f1571bb27e224e71143e..900be71c4214184481e2e6c539f13c9cf418cff7 100644 (file)
@@ -130,6 +130,21 @@ func (f *Func) retSparseMap(ss *sparseMap) {
        f.Cache.scrSparseMap = append(f.Cache.scrSparseMap, ss)
 }
 
+// newPoset returns a new poset from the internal cache
+func (f *Func) newPoset() *poset {
+       if len(f.Cache.scrPoset) > 0 {
+               po := f.Cache.scrPoset[len(f.Cache.scrPoset)-1]
+               f.Cache.scrPoset = f.Cache.scrPoset[:len(f.Cache.scrPoset)-1]
+               return po
+       }
+       return newPoset()
+}
+
+// retPoset returns a poset to the internal cache
+func (f *Func) retPoset(po *poset) {
+       f.Cache.scrPoset = append(f.Cache.scrPoset, po)
+}
+
 // newValue allocates a new Value with the given fields and places it at the end of b.Values.
 func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
        var v *Value
index 26a689404dc52afdc12a0e04e17732cf55475dbe..37b607977c31c0e121adb2e08780081df4905674 100644 (file)
@@ -152,13 +152,8 @@ type poset struct {
        undo      []posetUndo   // undo chain
 }
 
-func newPoset(unsigned bool) *poset {
-       var flags uint8
-       if unsigned {
-               flags |= posetFlagUnsigned
-       }
+func newPoset() *poset {
        return &poset{
-               flags:     flags,
                values:    make(map[ID]uint32),
                constants: make([]*Value, 0, 8),
                nodes:     make([]posetNode, 1, 16),
@@ -168,6 +163,14 @@ func newPoset(unsigned bool) *poset {
        }
 }
 
+func (po *poset) SetUnsigned(uns bool) {
+       if uns {
+               po.flags |= posetFlagUnsigned
+       } else {
+               po.flags &^= posetFlagUnsigned
+       }
+}
+
 // Handle children
 func (po *poset) setchl(i uint32, l posetEdge) { po.nodes[i].l = l }
 func (po *poset) setchr(i uint32, r posetEdge) { po.nodes[i].r = r }
index 89635ce54d1b0e5331058f1f947a78adf2668d78..cb739d9a0cecd1a541f8256b4f94436a06d35812 100644 (file)
@@ -64,7 +64,8 @@ func testPosetOps(t *testing.T, unsigned bool, ops []posetTestOp) {
                }
        }
 
-       po := newPoset(unsigned)
+       po := newPoset()
+       po.SetUnsigned(unsigned)
        for idx, op := range ops {
                t.Logf("op%d%v", idx, op)
                switch op.typ {
index b30dab9fe340679ea8154c54e3d941302b16ba15..8e248340880b30c7e0f594e13661568f07e95dd9 100644 (file)
@@ -181,10 +181,12 @@ type factsTable struct {
 var checkpointFact = fact{}
 var checkpointBound = limitFact{}
 
-func newFactsTable() *factsTable {
+func newFactsTable(f *Func) *factsTable {
        ft := &factsTable{}
-       ft.order[0] = newPoset(false) // signed
-       ft.order[1] = newPoset(true)  // unsigned
+       ft.order[0] = f.newPoset() // signed
+       ft.order[1] = f.newPoset() // unsigned
+       ft.order[0].SetUnsigned(false)
+       ft.order[1].SetUnsigned(true)
        ft.facts = make(map[pair]relation)
        ft.stack = make([]fact, 4)
        ft.limits = make(map[ID]limit)
@@ -666,7 +668,8 @@ var (
 // its negation. If either leads to a contradiction, it can trim that
 // successor.
 func prove(f *Func) {
-       ft := newFactsTable()
+       ft := newFactsTable(f)
+       ft.checkpoint()
 
        // Find length and capacity ops.
        var zero *Value
@@ -794,6 +797,20 @@ func prove(f *Func) {
                        ft.restore()
                }
        }
+
+       ft.restore()
+
+       // Return the posets to the free list
+       for _, po := range ft.order {
+               // Make sure it's empty as it should be. A non-empty poset
+               // might cause errors and miscompilations if reused.
+               if checkEnabled {
+                       if err := po.CheckEmpty(); err != nil {
+                               f.Fatalf("prove poset not empty after function %s: %v", f.Name, err)
+                       }
+               }
+               f.retPoset(po)
+       }
 }
 
 // getBranch returns the range restrictions added by p