-
Notifications
You must be signed in to change notification settings - Fork 18k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/compile: PGO devirtualization selects an edge with a weight of 0 as the hottest one #72092
Comments
Related Issues
Related Code Changes (Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.) |
CC @golang/compiler @prattmic |
Nice find. I agree we shouldn't devirtualize if the weight is zero. |
Keep in mind that weight 0 can mean two different things:
The second case means it is a brand new function. Brand new functions are actually reasonably likely to be hot, as someone just wrote them. It would be nice if we had a way to distinguish those two cases. If we could, brand new functions should probably get some default weight to start. |
Change https://go.dev/cl/655475 mentions this issue: |
@randall77, if I understand correctly, we may encounter the second case when using an outdated profile. Since this usage can negatively affect some other optimizations, I think preventing devirtualization for zero-weight edges won't be the biggest problem. Anyway, it seems to me that the problem of checking the relevance of the profile is separate. I suggest moving it to a new issue. |
Go version
go version devel go1.25-4f45b2b7e0 Tue Mar 4 03:10:17 2025 -0800 linux/arm64
Output of
go env
in your module/workspace:What did you do?
Consider the following example (it is based on the function
(*Resolver).resolveAddrList
fromnet/dial.go
):Build and collect a profile:
What did you see happen?
As can be seen,
Unreachable
is never called. Hence, it hasn't appeared in the profile:However, the call
hint.Network()
in theUnreachable
function has been devirtualized:The reason is the following.
WeightedCG
contains all functions from a package being compiled. In our case (taken using-d=pgodebug=3
):There are nodes for both
(*UnixAddr).Network
and(*NotUnixAddr).Network
functions. The edgeUnreachable -> (*UnixAddr).Network
has a zero weight because there are no suitable samples in the profile.PGO devirtualization considers the call
hint.Network()
and tries to find the most appropriate candidate. For theUnreachable
node, it goes throughOutEdges
with the same callsite offset. Note that we can't distinguish callsitesaddr.Network()
andhint.Network()
because they are placed on the same line. The edge to(*UnixAddr).Network
is the only one because there are no samples related to theUnreachable
function. This callee'sAST != nil
, and the method receiver type implements the interfaceAddr
. So,hint.Network()
is devirtualized to(*UnixAddr).Network
, although this caller relates toaddr.Network()
and the weight of the edge is 0.I suppose we shouldn't devirtualize a call when a weight of its hottest edge is 0 even if its
AST != nil
. Moreover, the devirtualized call will be inlined later (as can be seen in the debug output shown above), and this leads to unjustified increase of code size.What did you expect to see?
The call
hint.Network()
shouldn't be devirtualized.The text was updated successfully, but these errors were encountered: