From: Cherry Mui Date: Tue, 6 Jun 2023 02:28:48 +0000 (-0400) Subject: cmd/compile: check method name in PGO devirtualization X-Git-Tag: go1.21rc1~93 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=fd03e6ebc91fb0b6f4dc721a323dc0b408e3b30b;p=gostls13.git cmd/compile: check method name in PGO devirtualization Currently, we devirtualize an interface call if the profile indicates a concrete callee is hot on the same line, and the concrete receiver implements the interface. But it is possible that (likely due to another call on the same line, or possibly a stale profile) the concrete call is to a different method. With the current AST construction we generate correct code, as we extract the method name from the interface call and use that to create the concrete call. But the devirtualization decision is based on an unrelated call in the profile. Check the method name when finding the hottest callee, so we won't use unrelated calls to different methods. Change-Id: I75c026997926f21bd6cc5266d3ffe99649a9b2d9 Reviewed-on: https://go-review.googlesource.com/c/go/+/500961 Run-TryBot: Cherry Mui TryBot-Result: Gopher Robot Reviewed-by: Michael Pratt --- diff --git a/src/cmd/compile/internal/devirtualize/pgo.go b/src/cmd/compile/internal/devirtualize/pgo.go index a340248543..068e0ef8f2 100644 --- a/src/cmd/compile/internal/devirtualize/pgo.go +++ b/src/cmd/compile/internal/devirtualize/pgo.go @@ -15,6 +15,7 @@ import ( "encoding/json" "fmt" "os" + "strings" ) // CallStat summarizes a single call site. @@ -396,9 +397,9 @@ func methodRecvType(fn *ir.Func) *types.Type { return recv.Type } -// interfaceCallRecvType returns the type of the interface used in an interface -// call. -func interfaceCallRecvType(call *ir.CallExpr) *types.Type { +// interfaceCallRecvTypeAndMethod returns the type and the method of the interface +// used in an interface call. +func interfaceCallRecvTypeAndMethod(call *ir.CallExpr) (*types.Type, *types.Sym) { if call.Op() != ir.OCALLINTER { base.Fatalf("Call isn't OCALLINTER: %+v", call) } @@ -408,7 +409,7 @@ func interfaceCallRecvType(call *ir.CallExpr) *types.Type { base.Fatalf("OCALLINTER doesn't contain SelectorExpr: %+v", call) } - return sel.X.Type() + return sel.X.Type(), sel.Sel } // findHotConcreteCallee returns the *ir.Func of the hottest callee of an @@ -418,7 +419,7 @@ func findHotConcreteCallee(p *pgo.Profile, caller *ir.Func, call *ir.CallExpr) ( callerNode := p.WeightedCG.IRNodes[callerName] callOffset := pgo.NodeLineOffset(call, caller) - inter := interfaceCallRecvType(call) + inter, method := interfaceCallRecvTypeAndMethod(call) var hottest *pgo.IREdge @@ -512,6 +513,15 @@ func findHotConcreteCallee(p *pgo.Profile, caller *ir.Func, call *ir.CallExpr) ( continue } + // If the method name is different it is most likely from a + // different call on the same line + if !strings.HasSuffix(e.Dst.Name(), "."+method.Name) { + if base.Debug.PGODebug >= 2 { + fmt.Printf("%v: edge %s:%d -> %s (weight %d): callee is a different method\n", ir.Line(call), callerName, callOffset, e.Dst.Name(), e.Weight) + } + continue + } + if base.Debug.PGODebug >= 2 { fmt.Printf("%v: edge %s:%d -> %s (weight %d): hottest so far\n", ir.Line(call), callerName, callOffset, e.Dst.Name(), e.Weight) }