Skip to content

Commit 0b07bbd

Browse files
committed
cmd/compile/internal/inl: inline based on scoring when GOEXPERIMENT=newinliner
This patch changes the inliner to use callsite scores when deciding to inline as opposed to looking only at callee cost/hairyness. For this to work, we have to relax the inline budget cutoff as part of CanInline to allow for the possibility that a given function might start off with a cost of N where N > 80, but then be called from a callsites whose score is less than 80. Once a given function F in package P has been approved by CanInline (based on the relaxed budget) it will then be emitted as part of the export data, meaning that other packages importing P will need to also need to compute callsite scores appropriately. For a function F that calls function G, if G is marked as potentially inlinable then the hairyness computation for F will use G's cost for the call to G as opposed to the default call cost; for this to work with the new scheme (given relaxed cost change described above) we use G's cost only if it falls below inlineExtraCallCost, otherwise just use inlineExtraCallCost. Included in this patch are a bunch of skips and workarounds to selected 'errorcheck' tests in the <GOROOT>/test directory to deal with the additional "can inline" messages emitted when the new inliner is turned on. Change-Id: I9be5f8cd0cd8676beb4296faf80d2f6be7246335 Reviewed-on: https://go-review.googlesource.com/c/go/+/519197 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 7d0b611 commit 0b07bbd

File tree

10 files changed

+470
-11
lines changed

10 files changed

+470
-11
lines changed

src/cmd/compile/internal/inline/inl.go

+44-9
Original file line numberDiff line numberDiff line change
@@ -267,9 +267,12 @@ func garbageCollectUnreferencedHiddenClosures() {
267267

268268
// inlineBudget determines the max budget for function 'fn' prior to
269269
// analyzing the hairyness of the body of 'fn'. We pass in the pgo
270-
// profile if available, which can change the budget. If 'verbose' is
271-
// set, then print a remark where we boost the budget due to PGO.
272-
func inlineBudget(fn *ir.Func, profile *pgo.Profile, verbose bool) int32 {
270+
// profile if available (which can change the budget), also a
271+
// 'relaxed' flag, which expands the budget slightly to allow for the
272+
// possibility that a call to the function might have its score
273+
// adjusted downwards. If 'verbose' is set, then print a remark where
274+
// we boost the budget due to PGO.
275+
func inlineBudget(fn *ir.Func, profile *pgo.Profile, relaxed bool, verbose bool) int32 {
273276
// Update the budget for profile-guided inlining.
274277
budget := int32(inlineMaxBudget)
275278
if profile != nil {
@@ -282,6 +285,9 @@ func inlineBudget(fn *ir.Func, profile *pgo.Profile, verbose bool) int32 {
282285
}
283286
}
284287
}
288+
if relaxed {
289+
budget += inlineMaxBudget
290+
}
285291
return budget
286292
}
287293

@@ -332,8 +338,13 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) {
332338
cc = 1 // this appears to yield better performance than 0.
333339
}
334340

335-
// Compute the inline budget for this function.
336-
budget := inlineBudget(fn, profile, base.Debug.PGODebug > 0)
341+
// Used a "relaxed" inline budget if goexperiment.NewInliner is in
342+
// effect, or if we're producing a debugging dump for unit testing.
343+
relaxed := goexperiment.NewInliner ||
344+
(base.Debug.DumpInlFuncProps != "")
345+
346+
// Compute the inline budget for this func.
347+
budget := inlineBudget(fn, profile, relaxed, base.Debug.PGODebug > 0)
337348

338349
// At this point in the game the function we're looking at may
339350
// have "stale" autos, vars that still appear in the Dcl list, but
@@ -604,8 +615,23 @@ opSwitch:
604615
}
605616

606617
if fn := inlCallee(v.curFunc, n.X, v.profile); fn != nil && typecheck.HaveInlineBody(fn) {
607-
v.budget -= fn.Inl.Cost
608-
break
618+
// In the existing inliner, it makes sense to use fn.Inl.Cost
619+
// here due to the fact that an "inline F everywhere if F inlinable"
620+
// strategy is used. With the new inliner, however, it is not
621+
// a given that we'll inline a specific callsite -- it depends
622+
// on what score we assign to the callsite. For now, use the
623+
// computed cost if lower than the call cost, otherwise
624+
// use call cost (we can eventually do away with this when
625+
// we move to the "min-heap of callsites" scheme.
626+
if !goexperiment.NewInliner {
627+
v.budget -= fn.Inl.Cost
628+
break
629+
} else {
630+
if fn.Inl.Cost < inlineExtraCallCost {
631+
v.budget -= fn.Inl.Cost
632+
break
633+
}
634+
}
609635
}
610636

611637
// Call cost for non-leaf inlining.
@@ -977,7 +1003,16 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
9771003
maxCost = inlineBigFunctionMaxCost
9781004
}
9791005

980-
if callee.Inl.Cost <= maxCost {
1006+
metric := callee.Inl.Cost
1007+
if goexperiment.NewInliner {
1008+
ok, score := inlheur.GetCallSiteScore(n)
1009+
if ok {
1010+
metric = int32(score)
1011+
}
1012+
1013+
}
1014+
1015+
if metric <= maxCost {
9811016
// Simple case. Function is already cheap enough.
9821017
return true, 0
9831018
}
@@ -1001,7 +1036,7 @@ func inlineCostOK(n *ir.CallExpr, caller, callee *ir.Func, bigCaller bool) (bool
10011036
return false, maxCost
10021037
}
10031038

1004-
if callee.Inl.Cost > inlineHotMaxBudget {
1039+
if metric > inlineHotMaxBudget {
10051040
return false, inlineHotMaxBudget
10061041
}
10071042

src/cmd/compile/internal/inline/inlheur/callsite.go

+8
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ type CallSiteTab map[*ir.CallExpr]*CallSite
4444
// Package-level table of callsites.
4545
var cstab = CallSiteTab{}
4646

47+
func GetCallSiteScore(ce *ir.CallExpr) (bool, int) {
48+
cs, ok := cstab[ce]
49+
if !ok {
50+
return false, 0
51+
}
52+
return true, cs.Score
53+
}
54+
4755
type CSPropBits uint32
4856

4957
const (

test/closure3.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// errorcheckandrundir -0 -m -d=inlfuncswithclosures=1
22

3+
//go:build !goexperiment.newinliner
4+
// +build !goexperiment.newinliner
5+
36
// Copyright 2017 The Go Authors. All rights reserved.
47
// Use of this source code is governed by a BSD-style
58
// license that can be found in the LICENSE file.

test/escape4.go

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// errorcheck -0 -m
22

3+
//go:build !goexperiment.newinliner
4+
35
// Copyright 2010 The Go Authors. All rights reserved.
46
// Use of this source code is governed by a BSD-style
57
// license that can be found in the LICENSE file.

test/fixedbugs/issue19261.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// errorcheckdir -0 -m
22

3+
//go:build !goexperiment.newinliner
4+
// +build !goexperiment.newinliner
5+
36
// Copyright 2017 The Go Authors. All rights reserved.
47
// Use of this source code is governed by a BSD-style
58
// license that can be found in the LICENSE file.

test/fixedbugs/issue4099.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// errorcheck -0 -m
22

3+
//go:build !goexperiment.newinliner
4+
// +build !goexperiment.newinliner
5+
36
// Copyright 2013 The Go Authors. All rights reserved.
47
// Use of this source code is governed by a BSD-style
58
// license that can be found in the LICENSE file.
@@ -20,7 +23,7 @@ func F2([]byte)
2023
func G() {
2124
var buf1 [10]byte
2225
F1(buf1[:])
23-
26+
2427
var buf2 [10]byte // ERROR "moved to heap: buf2"
2528
F2(buf2[:])
2629
}

test/fixedbugs/issue42284.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// errorcheckdir -0 -m
22

3+
//go:build !goexperiment.newinliner
4+
// +build !goexperiment.newinliner
5+
36
// Copyright 2020 The Go Authors. All rights reserved.
47
// Use of this source code is governed by a BSD-style
58
// license that can be found in the LICENSE file.

test/fixedbugs/issue7921.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
// +build !gcflags_noopt
21
// errorcheck -0 -m
32

3+
//go:build !gcflags_noopt && !goexperiment.newinliner
4+
45
// Copyright 2018 The Go Authors. All rights reserved.
56
// Use of this source code is governed by a BSD-style
67
// license that can be found in the LICENSE file.

test/inline.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// errorcheckwithauto -0 -m -d=inlfuncswithclosures=1
22

3+
//go:build !goexperiment.newinliner
4+
// +build !goexperiment.newinliner
5+
36
// Copyright 2015 The Go Authors. All rights reserved.
47
// Use of this source code is governed by a BSD-style
58
// license that can be found in the LICENSE file.

0 commit comments

Comments
 (0)