shoop icon indicating copy to clipboard operation
shoop copied to clipboard

multithreading

Open mcginty opened this issue 8 years ago • 8 comments

everything is on the main thread, which is a couple shades of wrong. the decryption and file i/o should be happening in a separate thread to maximize throughput.

the "mio" crate seems promising.

mcginty avatar Jul 29 '16 13:07 mcginty

Thinking a little about where to put concurrency in.

The simplest thing I can think of is something like mioco.

1st coroutine is a loop that fetches the data. The puts the (nonce, data) into a channel.

2nd coroutine owns the file descriptor and key. This decrypts the (nonce, data) as they come into the channel and then writes the data to the file.

If this sounds about right, I'm interested in implementing it.

zmanian avatar Jul 31 '16 07:07 zmanian

Was thinking pretty much exactly this, yeah. If you want to take that on, I'll get to refactoring the crypto stuff so it won't be incredibly annoying for you :P.

mcginty avatar Jul 31 '16 10:07 mcginty

I'm not sure if mioco is the right solution here. Because the file should be written to in order, you don't really want to spawn a new green thread for each work unit. Given a producer, consumer arrangement using the standard concurrency constructs might be more appropriate for the problem.

Anyway I've been looking for an excuse to use Rust concurrency stuff.

zmanian avatar Jul 31 '16 14:07 zmanian

That research makes sense to me. The way I see it, mio seems to fit for wrapping UDT potentially, and then we'd have (ideally) a decryption thread and a file I/O thread. That should kill any bottlenecks.

So:

   Network I/O Thread
           ↓ 
 [encrypted data buffer]
           ↓ 
     Crypto Thread
           ↓ 
[unencrypted data buffer]
           ↓ 
    File I/O Thread
           ↓ 
        [file]

where the buffer is some reasonable size and if any of the buffers are full, the writing thread blocks until there is space.

The mio wrapping of UDT is unnecessary for the decryption/file threads so agree that can wait till if/when it seems worth it.

mcginty avatar Aug 03 '16 13:08 mcginty

Do you think channels will be all we need as buffers? No idea what they mean by an "infinite" buffer...

I've heard vague mention about interop problems between mio and the rest of the STL concurrency primitives so I will investigate if there are any issues with writing to a standard std::sync::mpsc::channel from a mio process.

zmanian avatar Aug 03 '16 15:08 zmanian

Looks like std::sync::mpsc::sync_channel might be more fitting, since we can set some sanity bounds for memory consumption.

So, for example, say we wanted to use ~50MB max memory, then we'd set each sync channel (into decryption and into file i/o) bound to about 20000, since 1300 * 2 * 20000 =~ 50MB

Also worth noting: I chose 1300 bytes as the plaintext block size just to try to keep things under 1500 bytes which is a normal UDP MTU, but it's also going to be worth tweaking that value to see what delivers max throughput via UDT.

mcginty avatar Aug 03 '16 16:08 mcginty

sync_channel looks good.

I'm noticing that channels are multi-producer so that each mio callback can own the tx side of the channel inside the closure. I think the multi-producer -> single consumer archtecture is a good fit for our buffers.

zmanian avatar Aug 03 '16 17:08 zmanian

I've been trying to wrap Handler::seal in a future. Struggling with type signatures.

zmanian avatar Sep 11 '16 18:09 zmanian