]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: check method name in PGO devirtualization
authorCherry Mui <cherryyz@google.com>
Tue, 6 Jun 2023 02:28:48 +0000 (22:28 -0400)
committerCherry Mui <cherryyz@google.com>
Tue, 6 Jun 2023 14:45:44 +0000 (14:45 +0000)
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 <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
src/cmd/compile/internal/devirtualize/pgo.go

index a3402485430166208af69de2006b4c5a7685ecea..068e0ef8f22e9dcb61523e750a9e4cf03f1fca4c 100644 (file)
@@ -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)
                }