]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: write "properties" to export data for inlinable funcs
authorThan McIntosh <thanm@google.com>
Thu, 29 Jun 2023 17:22:26 +0000 (13:22 -0400)
committerThan McIntosh <thanm@google.com>
Fri, 8 Sep 2023 23:02:15 +0000 (23:02 +0000)
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>
src/cmd/compile/internal/inline/inl.go
src/cmd/compile/internal/inline/inlheur/analyze.go
src/cmd/compile/internal/ir/func.go
src/cmd/compile/internal/noder/linker.go
src/cmd/compile/internal/noder/reader.go

index 4b7a141666ce3d490e0d5c6c13cc2b6ea9e6be70..85d68ae0ba377c272af8c0cc315872ad22e02812 100644 (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))
index 8d44b37b6aac075232a788cf0b4959e33f175cd1..a52b7ba04bdecec8c64d71df61dd5a448948f582 100644 (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
index 0e44ea7c5278c73cbd39de6239f87a180f713784..952f6fb92978953560203ec23518a511990b1f39 100644 (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.
index 00a77430853376eb1021c9edffa8b8c62f03f170..3bc5c32e1b52cc18a552af54bc61f0e86523fb1d 100644 (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)
index bf7bfb7d488b65019136d48df84e3055fbc8306f..35dfe3d674c34cb3df440f935efd5cfa72d861fa 100644 (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)