-
Notifications
You must be signed in to change notification settings - Fork 385
Severe performance regression #125
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
Comments
I ended up writing an "end-to-end" microbenchmark in the context of our application logic, and bisected our performance degradations to a complex interaction between our application abstractions, We've written an abstraction on top of package We use The net result of this chain of optimizations ("optimizations") is that I'm really not sure where to file this bug (the obvious contenders being this package and And while hopefully it goes without saying, thanks for maintaining this package and being my rubber duck! :) |
Thanks for digging into this, please keep us informed. On Tue, Jun 28, 2016 at 3:43 PM, Carl Jackson [email protected]
|
Do you have anything more to add? If you have a work around I'd be interested in seeing it. Maybe you could submit a pull request with it? Thanks. |
This performance issue is still an issue. I haven't looked into this much so far. |
Based on my reading of your explanations it seems like you expect bufio to work like a framebuffer. Where it stores up data in the buffer and passes it along only when the buffer is full. The go developers seem to have gone more with the more traditional idea of a data buffer that fills up only if there is nothing to read from it. That is a stream that can buffer to deal with the reader/writer being out of sync. The sftp.File objects mimics this behavior. So I guess I'm not sure if this is a bug with either this package or bufio. |
@unclejack Reviewing the issues again and I can see an argument for this being a bug in bufio. You use it explicitly when you want to buffer data but when the underlying writer supports ReadFrom it skips buffering, which was the whole point of using it. I think I might file a ticket it to see what the go-devs think. |
@unclejack Have you tried...
Thanks @calmh for affirming this as a good workaround. |
IMO this is a bug in either the specification of ReadFrom(), that you shouldn't implement it on slow writers, or a bug in the implementation of ReadFrom() skipping buffering. Either way the fix for the moment seems to be to document it and the way to deal with it. I'm going to write an example for ReadFrom that demonstrates the workaround. |
Small aside here, my understanding has always been that ReadFrom and WriteTo should only be provided when they can be written to be “the most efficient way of doing this operation”. Basically, because the operations are defined as “write the whole reader from/to” the operation is able to make much more intimate assumptions using knowledge of the internal data type. Taking a look at the bytes.Buffer.ReadFrom for example… wow. That’s some super “clever” code right there… |
I'm curious how you came to this understanding? Reading the documentation it describes it as a different semantic for writing, a convenience function for when you have an io.Reader. There is nothing that implies it is for optimizing IO. It only seems that way if/when you read the ReadFrom implementations in the standard library. |
Indeed, my understand has been based only upon the implementations and the “niche” use. One could always use io.Copy to do a naive copying, even if ReadFrom doesn’t exist, so… why should such a function exist? Because in that particular situation one can potentially do a better job than a naive io.Copy (and thus why io.Copy defers to the function if it exists.) So, it’s kind of an inference about purpose based on its existence, and thus it should have a rational purpose, but since io.Copy exists, “mere convenience” doesn’t seem like a rational one. But yes, the documentation itself is unclear about this purpose… so, this understanding certainly is an exogenesis. |
In the process of upgrading an application from 873d14f to 57fcf4a, we noticed that our application performed SFTP uploads roughly 5x slower than before (download speed, oddly enough, was greatly improved!)
Doing a full bisection against production is impractical for us, but I believe I've found a microbenchmark in this package that is indicative of this performance regression:
BenchmarkWrite1k
. Prior to 2960014, I got the following results on my laptop (Early 2013 15" MBP; Go 1.6.2):After 2960014, I get:
Note that in each case I've cherry-picked
587af18cfc86e31167f25d5e12b9a3e588b8775b
to get the package to compile on Darwin.I've tried all my usual debugging and profiling tricks, and it's not obviously any of the usual suspects. Any tips about where to look next? I'm also happy to provide more information about our production application, or to test a small number of patches against production (although the microbenchmark seems pretty damning on its own)
The text was updated successfully, but these errors were encountered: