diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-01-08 00:34:47 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2018-01-08 00:34:47 +0000 |
commit | b02fc0f9fedd635eb64f4bb6440ab63923c2af24 (patch) | |
tree | 07157384354a277ae826bc7a9f035d23e8d75d54 /lib/net/protocol.rb | |
parent | 816efa9ae1e6917d488ddf46a76ef40bcb5298a8 (diff) | |
download | ruby-b02fc0f9fedd635eb64f4bb6440ab63923c2af24.tar.gz |
net/protocol: read directly into rbuf if it's empty
There's no need to allocate a temporary string when @rbuf is
empty, we can use it as the read_nonblock destination buffer to
save both allocation overhead and avoid a later memcpy.
This results in a halving user CPU time and tiny memory
reduction with the script below:
user system total real
before 0.603333 0.539999 1.143332 ( 1.143347)
RssAnon: 5624 kB
after 0.283334 0.560000 0.843334 ( 0.846072)
RssAnon: 5592 kB
------
require 'net/http'
require 'benchmark'
s = TCPServer.new('127.0.0.1', 0)
len = 1024 * 1024 * 1024 * 2
pid = fork do
c = s.accept
c.readpartial(16384).clear
c.send("HTTP/1.0 200 OK\r\nContent-Length: #{len}\r\n\r\n", Socket::MSG_MORE)
IO.copy_stream('/dev/zero', c, len)
c.close
end
addr = s.addr
Net::HTTP.start(addr[3], addr[1]) do |http|
http.request_get('/') do |res|
puts(Benchmark.measure { res.read_body(&:clear) })
end
end
puts File.readlines("/proc/self/status").grep(/RssAnon/)[0]
Process.waitpid2(pid)
------
* lib/net/protocol.rb (rbuf_fill): avoid allocation if rbuf is empty
[ruby-core:84678] [Feature #14326]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61663 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/net/protocol.rb')
-rw-r--r-- | lib/net/protocol.rb | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb index e1586923c8..380d31ed5d 100644 --- a/lib/net/protocol.rb +++ b/lib/net/protocol.rb @@ -172,8 +172,10 @@ module Net # :nodoc: BUFSIZE = 1024 * 16 def rbuf_fill - case rv = @io.read_nonblock(BUFSIZE, exception: false) + tmp = @rbuf.empty? ? @rbuf : nil + case rv = @io.read_nonblock(BUFSIZE, tmp, exception: false) when String + return if rv.equal?(tmp) @rbuf << rv rv.clear return |