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
go/internal/gcimporter: too much CPU wasted on copying bytes #46564
Comments
cc @dominikh who has profiled his static analysis tools for a while |
I don't have much to say about this specific issue/"proposal", but I have a data point to contribute: I have a custom fork of gcimporter in Staticcheck, with the following changes to improve performance:
The 2nd and 3rd point likely have overlap with what's proposed here. |
To comment on the suggestion to use io.Reader instead: with my changes, the amount of data read is quite reduced, making (the equivalent to) ReadAll much less expensive. Also, it's not a trivial change; IImportData is written around having random access to the data. An io.Reader alone wouldn't suffice, we'd also need seeking, and it would quite uglify the code. Mmap would be an alternative, if it didn't come with all the downsides of mmap. |
The compiler's importer (which gcimporter is derived from) simply mmaps the files and then lets them linger until process termination. This is acceptable for the compiler because it only reads a bounded number of exports. It's also necessary because the compiler simply returns string references that point directly into the mmap'd memory. As @dominikh mentions, the export data format is structured around random access, so changing to an io.Reader isn't going to help. Changing to a ReaderAt would potentially work though without too much trouble: just change importReader.declReader into an io.SectionReader or something. I've also designed a new export data format. When I get around to the go/types importer for it, I'll make sure to explore using ReaderAt instead of reading the file into memory as a byte slice. |
Change https://golang.org/cl/325429 mentions this issue: |
Sorry for delay with the pull request, had to figure out test breakage. I've made a quick performance comparison of
I got it that the code is under a heavy refactoring now but the fix is pretty local and gives good boost. Actually, the boost is even bigger on our internal codebase. |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I'm using
go vet
to do static checks on my project code. Saidio.ReadAll
wastes some 30% of time on my codebase. I've managed to reproduce the issue on smaller codebase. The code to reproduce is here: https://gist.githubusercontent.com/g7r/fef9fbf7577bb380de26587c08681b12/raw/1486d5d986f5f3222befca5197cee806632d82d2/repro_test.go. Rungo test -bench . -benchtime 10000x -cpuprofile cpu.prof repro_test.go
to gather profile.What did you expect to see?
I expect not to see that large chunk of profile is dedicated to move memory while reading file into byte slice.
What did you see instead?
A lot of memory is being moved during file read. See attached profile screenshot:
I suggest we should remove
io.ReadAll
and useReader
iniImportData
.The text was updated successfully, but these errors were encountered: