From 323cf730912bc4ad975766118ba2da88a6e80a6b Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Thu, 29 Jun 2023 13:22:26 -0400 Subject: [PATCH] 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 Reviewed-by: Matthew Dempsky --- src/cmd/compile/internal/inline/inl.go | 16 ++++++-- .../internal/inline/inlheur/analyze.go | 39 ++++++++++++++----- src/cmd/compile/internal/ir/func.go | 4 ++ src/cmd/compile/internal/noder/linker.go | 4 ++ src/cmd/compile/internal/noder/reader.go | 4 ++ 5 files changed, 54 insertions(+), 13 deletions(-) diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 4b7a141666..85d68ae0ba 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -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)) diff --git a/src/cmd/compile/internal/inline/inlheur/analyze.go b/src/cmd/compile/internal/inline/inlheur/analyze.go index 8d44b37b6a..a52b7ba04b 100644 --- a/src/cmd/compile/internal/inline/inlheur/analyze.go +++ b/src/cmd/compile/internal/inline/inlheur/analyze.go @@ -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 diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 0e44ea7c52..952f6fb929 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -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. diff --git a/src/cmd/compile/internal/noder/linker.go b/src/cmd/compile/internal/noder/linker.go index 00a7743085..3bc5c32e1b 100644 --- a/src/cmd/compile/internal/noder/linker.go +++ b/src/cmd/compile/internal/noder/linker.go @@ -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) diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index bf7bfb7d48..35dfe3d674 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -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) -- 2.50.0