1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:14:43 -07:00

cmd/compile: write "properties" to export data for inlinable funcs

Augment the ir.Inline container to include an entry for function
properties (currently serialized as a string), and if
GOEXPERIMENT=newinliner is set, compute and store function
properties for all inline candidates processed by the inliner.

The idea here is that if the function properties are going to drive
inlining decisions, we'd like to have the same info from non-local /
imported functions as for local / in-package functions, hence we need
to include the properties in the export data.

Hand testing on the compiler itself and with k8s kubelet shows that
this increases the size of export data overall by about 2-3 percent,
so a pretty modest increase.

Updates #61502.

Change-Id: I9d1c311aa8418d02ffea3629c3dd9d8076886d15
Reviewed-on: https://go-review.googlesource.com/c/go/+/511562
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Than McIntosh 2023-06-29 13:22:26 -04:00
parent 906a073b0b
commit 323cf73091
5 changed files with 54 additions and 13 deletions

View File

@ -29,6 +29,7 @@ package inline
import (
"fmt"
"go/constant"
"internal/goexperiment"
"sort"
"strconv"
@ -292,11 +293,15 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) {
base.Fatalf("CanInline no nname %+v", fn)
}
canInline := func(fn *ir.Func) { CanInline(fn, profile) }
var funcProps *inlheur.FuncProps
if goexperiment.NewInliner {
funcProps = inlheur.AnalyzeFunc(fn, canInline)
}
if base.Debug.DumpInlFuncProps != "" {
inlheur.DumpFuncProps(fn, base.Debug.DumpInlFuncProps,
func(fn *ir.Func) {
CanInline(fn, profile)
})
inlheur.DumpFuncProps(fn, base.Debug.DumpInlFuncProps, canInline)
}
var reason string // reason, if any, that the function was not inlined
@ -363,6 +368,9 @@ func CanInline(fn *ir.Func, profile *pgo.Profile) {
CanDelayResults: canDelayResults(fn),
}
if goexperiment.NewInliner {
n.Func.Inl.Properties = funcProps.SerializeToString()
}
if base.Flag.LowerM > 1 {
fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, budget-visitor.budget, fn.Type(), ir.Nodes(fn.Body))

View File

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/ir"
"encoding/json"
"fmt"
"internal/goexperiment"
"io"
"os"
"path/filepath"
@ -48,6 +49,24 @@ type fnInlHeur struct {
props *FuncProps
}
var fpmap = map[*ir.Func]fnInlHeur{}
func AnalyzeFunc(fn *ir.Func, canInline func(*ir.Func)) *FuncProps {
if fih, ok := fpmap[fn]; ok {
return fih.props
}
fp := computeFuncProps(fn, canInline)
file, line := fnFileLine(fn)
entry := fnInlHeur{
fname: fn.Sym().Name,
file: file,
line: line,
props: fp,
}
fpmap[fn] = entry
return fp
}
// computeFuncProps examines the Go function 'fn' and computes for it
// a function "properties" object, to be used to drive inlining
// heuristics. See comments on the FuncProps type for more info.
@ -148,6 +167,16 @@ func captureFuncDumpEntry(fn *ir.Func, canInline func(*ir.Func)) {
if strings.HasPrefix(fn.Sym().Name, ".eq.") {
return
}
fih, ok := fpmap[fn]
if goexperiment.NewInliner {
// Props object should already be present.
if !ok {
panic("unexpected missing props")
}
} else {
AnalyzeFunc(fn, canInline)
fih = fpmap[fn]
}
if dumpBuffer == nil {
dumpBuffer = make(map[*ir.Func]fnInlHeur)
}
@ -156,15 +185,7 @@ func captureFuncDumpEntry(fn *ir.Func, canInline func(*ir.Func)) {
// so don't add them more than once.
return
}
fp := computeFuncProps(fn, canInline)
file, line := fnFileLine(fn)
entry := fnInlHeur{
fname: fn.Sym().Name,
file: file,
line: line,
props: fp,
}
dumpBuffer[fn] = entry
dumpBuffer[fn] = fih
}
// dumpFilePreamble writes out a file-level preamble for a given

View File

@ -200,6 +200,10 @@ type Inline struct {
Dcl []*Name
HaveDcl bool // whether we've loaded Dcl
// Function properties, encoded as a string (these are used for
// making inlining decisions). See cmd/compile/internal/inline/inlheur.
Properties string
// CanDelayResults reports whether it's safe for the inliner to delay
// initializing the result parameters until immediately before the
// "return" statement.

View File

@ -6,6 +6,7 @@ package noder
import (
"internal/buildcfg"
"internal/goexperiment"
"internal/pkgbits"
"io"
@ -296,6 +297,9 @@ func (l *linker) relocFuncExt(w *pkgbits.Encoder, name *ir.Name) {
if inl := name.Func.Inl; w.Bool(inl != nil) {
w.Len(int(inl.Cost))
w.Bool(inl.CanDelayResults)
if goexperiment.NewInliner {
w.String(inl.Properties)
}
}
w.Sync(pkgbits.SyncEOF)

View File

@ -8,6 +8,7 @@ import (
"fmt"
"go/constant"
"internal/buildcfg"
"internal/goexperiment"
"internal/pkgbits"
"path/filepath"
"strings"
@ -1118,6 +1119,9 @@ func (r *reader) funcExt(name *ir.Name, method *types.Sym) {
Cost: int32(r.Len()),
CanDelayResults: r.Bool(),
}
if goexperiment.NewInliner {
fn.Inl.Properties = r.String()
}
}
} else {
r.addBody(name.Func, method)