Closed noteflakes closed 2 years ago
Actually, implementing a Buffer
class means we need to instantiate the buffer, a whole lot of ceremony at the Ruby runtime level (including GC work) that we don't actually need. The only difference between doing this and using plain Ruby strings is that we just remove the need to copy the data to the string buffer, which in the global level is a negligible cost.
An idea: since we want to minimize the overhead of buffers in both CPU time and memory, would there be a way to refrain from creating a Buffer
instance? The idea is to pass a pointer to the buffer struct as a ruby FIXNUM. It's a bit of a hack but it should work (we should make sure this covers 64-bit pointers):
// in the callsite
struct polyphony_buffer buffer = {data, len};
...
VALUE res = Polyphony_backend_write(2, bio_props->io, FIX2NUM((uint)&buffer), Qnil);
// in the called method
...
if (TYPE(buf) == T_FIXNUM) {
struct polyphony_buffer *buffer = (struct polyphony_buffer *)NUM2FIX(buf);
written = write(fd, buffer->ptr, buffer->len);
}
...
This should also be highly beneficial to the planned deflate/gzip methods (#77).
In the future we might want to add support for raw buffers in Backend#chain
, Backend#splice_chunks
, but we leave that for now as the core functionality is there.
For some use cases it would be beneficial to be able to do IO with raw buffers (i.e. pointer + size). Use cases include:
The first concrete usage I have in mind is for use in a custom OpenSSL BIO where the read / write hooks have the following signature:
The buffer is basically a wrapper for (data, size), so:
(Code adapted from this example.)