-
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: make the inliner assign unsafe conversions lower costs #42739
Comments
It's past the Go 1.16 freeze, so I don't foresee us fixing this for Go 1.16. Maybe for Go 1.17. But for Go 1.17, we'll also have unsafe.Slice (#19367), which would be considered cheap. Would using that in Go 1.17 suffice for your use cases? |
Oh yeah, I forgot about that. It might help here. I checked out your CL 202080 to give it a spin. I'm probably being dense, but I wasn't able to find a particularly convenient way to use
Am I missing something? Nevertheless, the function I wrote using that conversion was inlined. I don't know what the actual cost was, unfortunately. Edit: That's because CL 202080 is pretty old now and it predates the better
|
Yeah, the accepted unsafe.Slice proposal does not include a way to to get the raw pointer from a (The original proposal allowed this though, using the proposed
CL 202080 is from 2019, so it's based on ~1.13 code. It looks like it predates the "with cost" debugging addition for -m=2. But if I'm mistaken and you can reproduce that failure at tip, then yes, please file an issue. |
I was mistaken about this. You are exactly right. |
@cespare to maybe unblock you now, this has cost 70: func myHashString2(s string) uint64 {
return myHash(*(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)})))
} Untested, but should work. (Btw, |
@josharian thanks! That helps -- now I can get both of my functions inlined. (I'd been discounting methods that don't start by declaring |
I went looking for more places where this optimization would apply. I found many instances of unsafe conversions like this, but very few where the underlying function looked like a candidate for inlining. (In a big private codebase, for instance, many of the unsafe conversions are casting large arrays, such as when loading data with mmap, but these functions aren't small and they aren't being called in a hot loop.) The closest example I found was a function which works around the issue that
This has a weight of 125 in the inliner currently and I can't get it below 109 using the sort of tricks we used above. However, based on some experiments I did with mutating this function I'm guessing that even if the unsafe conversion were very low-cost, the function would still have an overall cost higher than 80. My intuition now is that the only cases where my proposed optimization would matter are very similar to my code: a thin wrapper around a hash function (or similar) which has a Given that, I'll close this issue. I think that #2205 would be the better fix anyway, since it would mean we don't need unsafe conversions in the first place. There has been a tiny bit of activity on #2205 recently so perhaps it will see movement in the next few years. |
In case someone looks at this later, the situation is a little improved as of Go 1.20. The inliner has changed a bit and assigns slightly lower costs to these functions, and additionally the new way to write this conversion which would be the most natural and concise would use
Here are the numbers I get on tip:
|
What version of Go are you using (
go version
)?I also tested with tip.
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?linux/amd64
Details
I have a hash function with an assembly implementation. The function accepts a
[]byte
, but I also supply a string version of the function which accepts astring
. In order to avoid copying the string (#2205) the wrapper function does an unsafe[]byte
to string conversion:Unfortunately, this trivial function is assigned a cost of 91 by the inliner, which exceeds the budget of 80. This seems unreasonably high to me. I suspect it's to do with the syntactic complexity of using unsafe, which has the appearance of a bunch of function calls/conversions even though it compiles down to nearly nothing.
#17566 is a general issue for overhauling the inliner's cost model. It's not clear if/when that might happen, though.
In the meantime, would it make sense to special-case unsafe conversions in the inliner?
The partial workaround I came up with to trick the inliner (see cespare/xxhash#50) is demonstrated by this repro code (play link):
Unfortunately, that only works for one of the two functions I wish to inline. The other one has a slightly higher cost and I can't get the inliner to assign a weight less than 84.
/cc @mdempsky @dr2chase @randall77 @josharian
The text was updated successfully, but these errors were encountered: