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
Performance regression since version 0.71 #836
Comments
Attached is a profile of the modified version. Same number of syscalls and pretty much the same number of allocations. We can reduce allocations even further by re-using the same buffer on calls to read_nonblock: I'll try to put up a PR with my changes soon. |
Draft PR here: #837 Currently, I am stuck on how to handle streaming responses with a defined content length. There are 2 cases in tests:
Somehow the response wants to handle these differently, but I don't see how we can tell. Still working through that. |
I figured out a path forward. In order to handle the streaming with a response block cases, I had to add a |
Running into an issue now where the socket tests hand on drain. Still not sure why. Will try looking into it once I have some time. |
New draft PR that stays closer to the original implementation while improving perf and passing all tests: #838 |
@geemus The PR is now ready to review. With these changes Excon is now the fastest HTTP client in my benchmark. On version 0.71.0 Excon matched the performance of Net::HTTP. On version 104, Excon was the slowest of the clients I tested (http.rb, httpx, net/http, excon, typhoeus). Here is the result of one (of many) runs:
Comparison of a run with v0.71.0:
Comparison of a run with v0.104.0:
|
The PR includes a zip of HTML files that show allocations for all 3 versions. The proposed version is no worse than v104 in terms of number of allocations. |
I am running a benchmark of excon hitting an httpbin-go container repeatedly using benchmark-ips.
I found that version 0.71 was significantly faster than 0.104. Looking at a a ruby-prof graph output I see that for OpenSSL the underlying socket is already buffered and in older versions we made significantly more syscalls to the socket (903 for v0.71.0 versus 104 for v0.104.0).
The changes since version 0.71 in sockets are not many, but I see #796 as potentially being the culprit. Although we reduced the number of allocations and syscalls performance can actually suffer for OpenSSL.
Excon.zip
I plan to look into this a bit but the easiest change is changing the condition here:
excon/lib/excon/socket.rb
Line 215 in a69024d
Most sockets (including Ruby's) treat the max length as an upper bound and do not try to fill the whole buffer. Excon, however attempts to fill the entire buffer on each call to
#read_nonblock
. By just changing the condition tountil @backend_eof || @read_buffer.length != 0
we can improve performance without seriously impacting allocations or syscalls. I am trying to perform some more testing to see if this is safe to do.The text was updated successfully, but these errors were encountered: