diff options
author | Jaymz Julian <jaymzjulian@meta.com> | 2024-02-05 15:00:47 -0800 |
---|---|---|
committer | Jaymz Julian <jaymzjulian@meta.com> | 2024-02-05 15:03:25 -0800 |
commit | d4389b425de7e82031897288b730d49b4b4319c1 (patch) | |
tree | f76dbc05dec2700115de9df46156d5a5ded11d2a | |
parent | ccc159449248869f28f3f4a3960c766d3d2e36d8 (diff) | |
download | ruby-openssl-d4389b425de7e82031897288b730d49b4b4319c1.tar.gz |
Fix performance regression in do_write(s)
This causes significant performance issues when using large (>10meg) writes
Fix by adjusting the buffer write function to clear the buffer once, rather than
piece by piece, avoiding a case where a large write (in our case, around
70mbytes) will consume 100% of CPU. This takes a webrick GET request via SSL
from around 200kbyts/sec and consuming 100% of a core, to line speed on gigabit
ethernet and 6% cpu utlization.
-rw-r--r-- | lib/openssl/buffering.rb | 17 |
1 files changed, 11 insertions, 6 deletions
diff --git a/lib/openssl/buffering.rb b/lib/openssl/buffering.rb index d47e1082..aa4adee3 100644 --- a/lib/openssl/buffering.rb +++ b/lib/openssl/buffering.rb @@ -348,13 +348,18 @@ module OpenSSL::Buffering @wbuffer << s @wbuffer.force_encoding(Encoding::BINARY) @sync ||= false - if @sync or @wbuffer.size > BLOCK_SIZE - until @wbuffer.empty? - begin - nwrote = syswrite(@wbuffer) - rescue Errno::EAGAIN - retry + buffer_size = @wbuffer.size + if @sync or buffer_size > BLOCK_SIZE + nwrote = 0 + begin + while nwrote < buffer_size do + begin + nwrote += syswrite(@wbuffer[nwrote, buffer_size - nwrote]) + rescue Errno::EAGAIN + retry + end end + ensure @wbuffer[0, nwrote] = "" end end |