Description
Hello,
I'm using this library in a project. First of all, thanks, this library has made working with TLS very straightforward for me.
I'm using this library in the context of non-blocking I/O. Due to the specifics of my project I'm unable to use an OS polling library like mio
, and instead manually check sockets for readiness in a loop, sleeping for a short period between iterations. This means that the vast majority of read
calls return WouldBlock
. This has worked well with unencrypted TcpStream
s, however once I implemented an encrypted version with this library I started seeing unreasonable CPU usage even though the connection was idle.
I've been able to modify the simpleclient.rs
example to serve as a minimal testcase: https://pastebin.com/S0SPraDN. Executing this code results in consistent CPU usage of ~2% for me.
Upon investigation, it appears the code in deframer.rs#L45
first resizes the deframer buffer to maximum length, attempts a read, and truncates the buffer back to its original size if an error occurred. It seems these operations were the cause of the CPU usage I was seeing, possibly because of the allocation size of >18KB. Unfortunately these operations execute in almost every iteration of my loop, due to the returned WouldBlock
from the underlying socket.
I've been able to confirm that these operations are indeed the cause of the CPU usage through a workaround. If you insert the following at the start of the read
function the CPU usage drops back to 0%:
let mut empty_buf = [0; 0];
rd.read(&mut empty_buf)?;
The code attempts to read to an empty buffer which means it shouldn't affect the functionality of the success case. In the error case, the function immediately returns without getting to the resizing part, thus avoiding the costly operations.
However I feel like it should be possible to solve this without a workaround like this one. From PR #9 and PR #11 I gather that the current behavior and the large buffer size were introduced to avoid too many read calls to make reading more efficient. Perhaps std::io::BufReader
could be used here, which seems to have been made to solve this problem, and appears not to be using resize
internally.
However, I have no experience with either TLS nor BufReader internals, so I apologize if this would not be a workable solution.