From: Keith Randall Date: Mon, 9 Jan 2023 22:29:49 +0000 (-0800) Subject: cmd/compile: share compiler allocations of similar shapes X-Git-Tag: go1.21rc1~1553 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0e42632301f17ae384e2cc1edb273860ed8f9fac;p=gostls13.git cmd/compile: share compiler allocations of similar shapes Use the same allocator for, e.g., []int32 and []int8. Anything with similar base shapes and be coerced into a single allocator, which helps reuse memory more often. There is not much unsafe in the compiler currently. This adds quite a bit, joining cmd/compiler/internal/base/mapfile_mmap.go and some unsafe.Sizeof calls. Change-Id: I95d6d6e47c42b9f0a45f3556f4d7605735e65d99 Reviewed-on: https://go-review.googlesource.com/c/go/+/461084 Reviewed-by: Michael Pratt TryBot-Result: Gopher Robot Reviewed-by: David Chase Run-TryBot: Keith Randall --- diff --git a/src/cmd/compile/internal/ssa/_gen/allocators.go b/src/cmd/compile/internal/ssa/_gen/allocators.go index 48a2598d05..5c72fe8be1 100644 --- a/src/cmd/compile/internal/ssa/_gen/allocators.go +++ b/src/cmd/compile/internal/ssa/_gen/allocators.go @@ -23,6 +23,12 @@ type allocator struct { maxLog int // log_2 of maximum allocation size } +type derived struct { + name string // name for alloc/free functions + typ string // the type they return/accept + base string // underlying allocator +} + func genAllocators() { allocators := []allocator{ { @@ -36,65 +42,15 @@ func genAllocators() { maxLog: 32, }, { - name: "BlockSlice", - typ: "[]*Block", + name: "Int64Slice", + typ: "[]int64", capacity: "cap(%s)", - mak: "make([]*Block, %s)", - resize: "%s[:%s]", - clear: "for i := range %[1]s {\n%[1]s[i] = nil\n}", - minLog: 5, - maxLog: 32, - }, - { - name: "BoolSlice", - typ: "[]bool", - capacity: "cap(%s)", - mak: "make([]bool, %s)", - resize: "%s[:%s]", - clear: "for i := range %[1]s {\n%[1]s[i] = false\n}", - minLog: 8, - maxLog: 32, - }, - { - name: "IntSlice", - typ: "[]int", - capacity: "cap(%s)", - mak: "make([]int, %s)", + mak: "make([]int64, %s)", resize: "%s[:%s]", clear: "for i := range %[1]s {\n%[1]s[i] = 0\n}", minLog: 5, maxLog: 32, }, - { - name: "Int32Slice", - typ: "[]int32", - capacity: "cap(%s)", - mak: "make([]int32, %s)", - resize: "%s[:%s]", - clear: "for i := range %[1]s {\n%[1]s[i] = 0\n}", - minLog: 6, - maxLog: 32, - }, - { - name: "Int8Slice", - typ: "[]int8", - capacity: "cap(%s)", - mak: "make([]int8, %s)", - resize: "%s[:%s]", - clear: "for i := range %[1]s {\n%[1]s[i] = 0\n}", - minLog: 8, - maxLog: 32, - }, - { - name: "IDSlice", - typ: "[]ID", - capacity: "cap(%s)", - mak: "make([]ID, %s)", - resize: "%s[:%s]", - clear: "for i := range %[1]s {\n%[1]s[i] = 0\n}", - minLog: 6, - maxLog: 32, - }, { name: "SparseSet", typ: "*sparseSet", @@ -126,6 +82,38 @@ func genAllocators() { maxLog: 32, }, } + deriveds := []derived{ + { + name: "BlockSlice", + typ: "[]*Block", + base: "ValueSlice", + }, + { + name: "IntSlice", + typ: "[]int", + base: "Int64Slice", + }, + { + name: "Int32Slice", + typ: "[]int32", + base: "Int64Slice", + }, + { + name: "Int8Slice", + typ: "[]int8", + base: "Int64Slice", + }, + { + name: "BoolSlice", + typ: "[]bool", + base: "Int64Slice", + }, + { + name: "IDSlice", + typ: "[]ID", + base: "Int64Slice", + }, + } w := new(bytes.Buffer) fmt.Fprintf(w, "// Code generated from _gen/allocators.go using 'go generate'; DO NOT EDIT.\n") @@ -133,12 +121,22 @@ func genAllocators() { fmt.Fprintln(w, "package ssa") fmt.Fprintln(w, "import (") + fmt.Fprintln(w, "\"internal/unsafeheader\"") fmt.Fprintln(w, "\"math/bits\"") fmt.Fprintln(w, "\"sync\"") + fmt.Fprintln(w, "\"unsafe\"") fmt.Fprintln(w, ")") for _, a := range allocators { genAllocator(w, a) } + for _, d := range deriveds { + for _, base := range allocators { + if base.name == d.base { + genDerived(w, d, base) + break + } + } + } // gofmt result b := w.Bytes() var err error @@ -196,3 +194,32 @@ func genAllocator(w io.Writer, a allocator) { } fmt.Fprintf(w, "}\n") } +func genDerived(w io.Writer, d derived, base allocator) { + fmt.Fprintf(w, "func (c *Cache) alloc%s(n int) %s {\n", d.name, d.typ) + if d.typ[:2] != "[]" || base.typ[:2] != "[]" { + panic(fmt.Sprintf("bad derived types: %s %s", d.typ, base.typ)) + } + fmt.Fprintf(w, "var base %s\n", base.typ[2:]) + fmt.Fprintf(w, "var derived %s\n", d.typ[2:]) + fmt.Fprintf(w, "if unsafe.Sizeof(base)%%unsafe.Sizeof(derived) != 0 { panic(\"bad\") }\n") + fmt.Fprintf(w, "scale := unsafe.Sizeof(base)/unsafe.Sizeof(derived)\n") + fmt.Fprintf(w, "b := c.alloc%s(int((uintptr(n)+scale-1)/scale))\n", base.name) + fmt.Fprintf(w, "s := unsafeheader.Slice {\n") + fmt.Fprintf(w, " Data: unsafe.Pointer(&b[0]),\n") + fmt.Fprintf(w, " Len: n,\n") + fmt.Fprintf(w, " Cap: cap(b)*int(scale),\n") + fmt.Fprintf(w, " }\n") + fmt.Fprintf(w, "return *(*%s)(unsafe.Pointer(&s))\n", d.typ) + fmt.Fprintf(w, "}\n") + fmt.Fprintf(w, "func (c *Cache) free%s(s %s) {\n", d.name, d.typ) + fmt.Fprintf(w, "var base %s\n", base.typ[2:]) + fmt.Fprintf(w, "var derived %s\n", d.typ[2:]) + fmt.Fprintf(w, "scale := unsafe.Sizeof(base)/unsafe.Sizeof(derived)\n") + fmt.Fprintf(w, "b := unsafeheader.Slice {\n") + fmt.Fprintf(w, " Data: unsafe.Pointer(&s[0]),\n") + fmt.Fprintf(w, " Len: int((uintptr(len(s))+scale-1)/scale),\n") + fmt.Fprintf(w, " Cap: int((uintptr(cap(s))+scale-1)/scale),\n") + fmt.Fprintf(w, " }\n") + fmt.Fprintf(w, "c.free%s(*(*%s)(unsafe.Pointer(&b)))\n", base.name, base.typ) + fmt.Fprintf(w, "}\n") +} diff --git a/src/cmd/compile/internal/ssa/allocators.go b/src/cmd/compile/internal/ssa/allocators.go index d782464c02..ff70795f82 100644 --- a/src/cmd/compile/internal/ssa/allocators.go +++ b/src/cmd/compile/internal/ssa/allocators.go @@ -3,8 +3,10 @@ package ssa import ( + "internal/unsafeheader" "math/bits" "sync" + "unsafe" ) var poolFreeValueSlice [27]sync.Pool @@ -45,232 +47,42 @@ func (c *Cache) freeValueSlice(s []*Value) { poolFreeValueSlice[b-5].Put(sp) } -var poolFreeBlockSlice [27]sync.Pool +var poolFreeInt64Slice [27]sync.Pool -func (c *Cache) allocBlockSlice(n int) []*Block { - var s []*Block +func (c *Cache) allocInt64Slice(n int) []int64 { + var s []int64 n2 := n if n2 < 32 { n2 = 32 } b := bits.Len(uint(n2 - 1)) - v := poolFreeBlockSlice[b-5].Get() - if v == nil { - s = make([]*Block, 1<