-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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/cgo: unsafe.Pointer containing bytes.Buffer slice data triggers argument check panic -- workaround causes performance degredation #14704
Comments
Can you clarify what you are measuring when you measure a slowdown? It seems to me that you have code that fails the cgo check, and you are replacing it with code that passes the cgo check. The code that fails the cgo check won't run, so what are you timing? |
@ianlancetaylor Forgive me for not explaining that clearly. The only time I have seen the cgo check fail is when it is passed a short You should be able to see this. Changing the code I provided so that That is what I am benchmarking in my lmdb-go project, byte slices that are unaffected by this issue. And after compensating for this corner case I see processing in the normal case degrading farther than I would like it to. As I eluded to, I don't think the behavior here is captured well by the cgo change proposal, or any other documentation that I have seen about the restrictions (like the cmd/cgo docs). I was under the impression that the code example from the issue description was passing the address of a struct field (i.e. the byte array field inside bytes.Buffer), in which case the documentation states
I don't think the documentation is very clear about the need to perform the indirection at the cgo call site (as was suggested in #14210 and demonstrated at http://play.golang.org/p/eX1pSIjmo4). It never says explicitly says my code should work but it doesn't say that it shouldn't work either. |
Thanks for the additional details. The documentation doesn't spell out the need to perform the indirection at the cgo call site because there is no intent that that be a permanent requirement. The intent is what you quote from the docs: the memory in question is the memory occupied by the field. The question is how to implement that. |
Thanks for the explanation. I have probably read you say as much before. But I now finally understand it in this context. So thank you for your patience as well. I will try a little more to improve my own change, and to reduce the performance penalty I am seeing. It's not clear to me how escape analysis works with cgo. Though it seems to me that with the new restrictions pointers passed through cgo would be considered non-escaping? (edit: obviously unless they could be determined to escape for other reasons) |
I also am not sure what is escaping here. I think you can run |
Ah yes. I had forgotten about that flag. It certainly prints out a lot of stuff. I will poke around, see what I can do with it, and get back soon. Previously I did try manually inlining the function which takes the []byte address. It did not seem to provide a visible performance improvement. But I will look again with this flag enabled and see if I did something dumb. Thanks. |
I seem to have gotten the relevant benchmarks for my project slightly closer to the original version. But there is still a sizable gulf between performance of the original and fixed code on normal-case input, which do not trigger any panics. In regards to escaping pointers, it seems like cgo may be assuming that all pointers passed to cgo escape. This is understandable because it cannot be verified but it does seem like that could be relaxed if cgo is to assume that people comply with the restrictions it states (though cannot enforce). Following is a simple example and the output of http://play.golang.org/p/gG3o96a4rD
|
I think it's best to keep issues focused on a single problem. The problem of pointers escaping when passed to cgo is a different problem. See #10303. |
It is unclear to me what this issue is about. Can someone summarize what remains? |
I think that any fix for this is the same as #14210, so closing as a duplicate. |
go version
)? go1.6go env
)? linux/amd64I'm creating this issue to track a problem I brought up in #14210 (comment) but for which the cause/fix was different. I took some time before filing the issue to collect more information about the problem and the fix for my own understanding. My apologies for the delay. But it didn't look like a duplicate has been filed since.
I was also told to replace my code that looked like the above example with code which takes the address of a
[]byte
at the actual cgo call site to help the tool figure out which memory region I was referring to. I have done so, and it works, but I have found the result to be significantly slower that before I made this change (both benchmarks takes from a stock go1.6 build -- no flags).The changes I made to work around the above panic in my actual project can be found here: bmatsuo/lmdb-go@40ebaca
And the performance comparison against master can be seen in my pull request: bmatsuo/lmdb-go#57 (comment)
My benchmarks, unfortunately, have more noise than I would like but there is a definite pattern that shows this change having a real impact on call times (especially for some functions which should execute be extremely quickly). The relevant benchmarks show a 7-43% performance penalty from this change (100ns+ per affected C call).
The text was updated successfully, but these errors were encountered: