-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: combining two inlined functions with interfaces produces non-inlineable code #61036
Comments
We have had to introduce comments (https://github.com/fyne-io/fyne/blob/03384a7a3aa88f328724e399301ad38b321dcd84/geometry.go#L78, https://github.com/fyne-io/fyne/blob/03384a7a3aa88f328724e399301ad38b321dcd84/geometry.go#L109 and two more further up) in the codebase of Fyne in order to make sure that someone doesn't try to simplify the code in the future. A 15 to 20x slowdown + one allocation for such a small and simple change is not something we want to see in very commonly used types inside the toolkit. |
/cc @golang/compiler |
I spent a little time looking at this, but I am not sure this is really an actionable bug per se. There is always going to be a certain amount of inaccuracy when it comes to the cost that estimates the "cost" of inlining a given function; this is one of those cases where the numbers come out slightly differently with inline code vs a function call. Enforcing exact quality of inlining "cost" calculation for hand-inlined code vs call to an out of line function is not a goal that we're trying to achieve. |
I can see the point about not directly comparing inlining costs in that way, it was just a tool for me to try and get some sense into why it behaves like it does. It seems to me like this is something that the compiler should be able to figure out and the fact that it manages to do it when there is a concrete type but not with an interface which seems strange to me. |
The current inliner is known to be very naive, and we're currently working to overhaul it. I hope that should improve your particular use case too, but we need to consider the entire Go ecosystem when tuning optimization policies, so I don't think we can commit to always inlining when you'd like us to. That said, we have Either way, I don't think this issue is particularly actionable, so I'm closing it. |
Cool. Seems sensible to me. I'm looking forward for more improvements to the inliner. Are the improvements scheduled for any particular Go release in the future? I only found #17566 that mentioned |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
With latest stable release (Go 1.20.5), yes. I have not tested Go 1.21 release candidate.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Link to code: https://go.dev/play/p/78gWoQEaUui
We have the
AddXY
method that is inlineable with a cost of 12 andComponents
that is inlineable with cost of 5 as methods on the size type:We then create two functions and an interface. Combining the two functions for simplified code we get
AddSlowVector()
which gets a cost of 85 and thus isn't inlineable. However, manually inliningAddXY()
to produceAddFastVector()
gets us a cost of 79 and is inlineable and 15x faster with zero allocations.What did you expect to see?
I would expect these two to produce the exact same code because both
Components()
andAddXY()
are inlineable with very small costs (the sum is less than the 80 cost limit). SimplifyingAddFastVector()
to not duplicate the code fromAddXY
should be inlineable and not be much slower. It would seem logical for the compiler to basically produce the fast function by inliningAddXY
in the slow function.What did you see instead?
Simplifying
AddFastVector()
intoAddSlowVector()
produces a 15x slower function that allocates once. Not using an interface for the input into the function decreases the inline cost a lot and does not exhibit the same slowdown. I do understand that interfaces need to be devirtualized and that produces some overhead but there should not be such a huge difference between the two functions (that are both using interfaces) in my opinion.The text was updated successfully, but these errors were encountered: