-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
Proposal Details
Expose what contributes to consuming the inlining budget as a debug flag
Sometimes, understanding why a function is inlined or not or what the main contributors to the function budget consumption are is not easy.
This proposal is to add a -d flag to the go tool compile command that enables traces of budget consumption.
Proof of concept
I already have a POC that does more or less the job and a tool that takes advantage of that to give a summary.
This is an example of this execution:
> go build -gcflags "-d=inlcostreason" hello.go
./hello.go:24:6: inline-function-cost: 123
./hello.go:24:6: inline-function-cost: 0,not inlining too expensive
./hello.go:25:13: inline-cost: 57,non-leaf inlining,0
./hello.go:25:13: inline-cost: 1,node,1
./hello.go:25:13: inline-cost: 1,node,2
./hello.go:25:13: inline-cost: 1,node,6
./hello.go:25:16: inline-cost: 1,node,3
./hello.go:25:16: inline-cost: 1,node,4
./hello.go:25:25: inline-cost: 1,node,5
./hello.go:26:20: inline-cost: 59,inlined function body,7
./hello.go:26:20: inline-cost: 1,node,7
...
This file, passing from a tool that I built, gives you this (showing only part of the output):
...
func usage() { // 123, total inline cost, not inlining too expensive
fmt.Fprintf(os.Stderr, "usage: helloserver [options]\n") // 63, non-leaf inlining, node
flag.PrintDefaults() // 60, inlined function body, node
os.Exit(2)
}
...To understand what I did, I just added in the right places (where the budget changes) blocks like this:
if base.Debug.InlCostReason != 0 {
base.WarnfAt(v.lastFunctionPos, "inline-cost: %d,%s,%d", inlineExtraThrowCost, "trow", v.counter)
v.counter++
}The counter avoids line deduplication, and the lastFunctionPos avoids showing already inlinable code as part of other functions. But those are implementation details that we need to figure out later the best approach here.