[dev.link] cmd/link: rewrite heap algorithm

Instead of using container/heap package, implement a simple
specialized heap algorithm for the work queue in the deadcode
pass, to avoid allocations and function pointer calls.

Linking cmd/compile,

name           old time/op    new time/op    delta
Deadcode_GC      59.8ms ± 4%    42.2ms ± 4%  -29.45%  (p=0.008 n=5+5)

name           old alloc/op   new alloc/op   delta
Deadcode_GC      3.53MB ± 0%    2.10MB ± 0%  -40.57%  (p=0.008 n=5+5)

name           old allocs/op  new allocs/op  delta
Deadcode_GC        187k ± 0%        8k ± 0%  -95.48%  (p=0.008 n=5+5)

Change-Id: Ibb21801d5b8e4a7eaf429856702e02720cd1772f
Reviewed-on: https://go-review.googlesource.com/c/go/+/236565
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Zhang 2020-06-03 19:34:29 -04:00
parent e4d6bfdbdf
commit 7179e426e2
3 changed files with 145 additions and 18 deletions

View file

@ -10,32 +10,16 @@ import (
"cmd/internal/sys"
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"container/heap"
"fmt"
"unicode"
)
var _ = fmt.Print
type workQueue []loader.Sym
// Implement container/heap.Interface.
func (q *workQueue) Len() int { return len(*q) }
func (q *workQueue) Less(i, j int) bool { return (*q)[i] < (*q)[j] }
func (q *workQueue) Swap(i, j int) { (*q)[i], (*q)[j] = (*q)[j], (*q)[i] }
func (q *workQueue) Push(i interface{}) { *q = append(*q, i.(loader.Sym)) }
func (q *workQueue) Pop() interface{} { i := (*q)[len(*q)-1]; *q = (*q)[:len(*q)-1]; return i }
// Functions for deadcode pass to use.
// Deadcode pass should call push/pop, not Push/Pop.
func (q *workQueue) push(i loader.Sym) { heap.Push(q, i) }
func (q *workQueue) pop() loader.Sym { return heap.Pop(q).(loader.Sym) }
func (q *workQueue) empty() bool { return len(*q) == 0 }
type deadcodePass struct {
ctxt *Link
ldr *loader.Loader
wq workQueue
wq heap // work queue, using min-heap for beter locality
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
markableMethods []methodref // methods of reached types
@ -48,7 +32,6 @@ func (d *deadcodePass) init() {
if objabi.Fieldtrack_enabled != 0 {
d.ldr.Reachparent = make([]loader.Sym, d.ldr.NSym())
}
heap.Init(&d.wq)
if d.ctxt.BuildMode == BuildModeShared {
// Mark all symbols defined in this library as reachable when