Skip to main content

mpc_bench/
comm.rs

1use std::{
2    cmp,
3    sync::mpsc::{channel, Receiver, Sender},
4    thread::sleep,
5    time::{Duration, Instant},
6    vec::IntoIter,
7};
8
9use queues::{IsQueue, Queue};
10
11/// A NetworkDescription is responsible for instantiating the networks it describes by spawning channels for each party.
12pub trait NetworkDescription {
13    /// Instantiates the Channels for each party.
14    fn instantiate(&self, n_parties: usize) -> Vec<Channels>;
15}
16
17#[derive(Default)]
18/// A full mesh network description.
19pub struct FullMesh {
20    latency: Duration,
21    seconds_per_byte: Duration,
22}
23
24impl FullMesh {
25    /// Construct a FullMesh network description without communication overhead.
26    pub fn new() -> Self {
27        FullMesh {
28            latency: Duration::ZERO,
29            seconds_per_byte: Duration::ZERO,
30        }
31    }
32
33    /// Construct a FullMesh network description with the specified `latency` and bandwidth constraints (maximum `bytes_per_second`).
34    pub fn new_with_overhead(latency: Duration, bytes_per_second: f64) -> Self {
35        FullMesh {
36            latency,
37            seconds_per_byte: Duration::from_secs_f64(1. / bytes_per_second),
38        }
39    }
40}
41
42impl NetworkDescription for FullMesh {
43    fn instantiate(&self, n_parties: usize) -> Vec<Channels> {
44        let mut receivers = vec![];
45        let mut senders: Vec<Vec<Sender<_>>> = (0..n_parties).map(|_| vec![]).collect();
46
47        for _ in 0..n_parties {
48            let (sender, receiver) = channel();
49
50            receivers.push(receiver);
51
52            for sender_vec in senders.iter_mut() {
53                sender_vec.push(sender.clone());
54            }
55        }
56
57        receivers
58            .into_iter()
59            .enumerate()
60            .zip(senders)
61            .map(|((id, r), s)| Channels::new(id, s, r, self.latency, self.seconds_per_byte))
62            .collect()
63    }
64}
65
66/// A message that is sent from the party with id `from_id` to another, containing a `Vec` of bytes.
67pub struct Message {
68    arrival_time: Instant,
69    from_id: usize,
70    contents: Vec<u8>,
71}
72
73/// Returns bytes with a delay, to simulate latency and bandwidth overhead
74pub struct DelayedByteIterator {
75    wake_time: Instant,
76    bytes: IntoIter<u8>,
77    seconds_per_byte: Duration,
78}
79
80impl DelayedByteIterator {
81    /// Creates a DelayedByteIterator for the given `bytes`, and immediately delaying for `latency`, after which each byte is returned with `seconds_per_byte` delay.
82    pub fn new(bytes: Vec<u8>, start_time: Instant, seconds_per_byte: Duration) -> Self {
83        DelayedByteIterator {
84            wake_time: start_time + seconds_per_byte,
85            bytes: bytes.into_iter(),
86            seconds_per_byte,
87        }
88    }
89}
90
91impl Iterator for DelayedByteIterator {
92    type Item = u8;
93
94    fn next(&mut self) -> Option<Self::Item> {
95        self.bytes.next().map(|byte| {
96            // Delays to fit the bandwidth constraints (returns immediately when the iterator is empty)
97            let dur = self.wake_time - Instant::now();
98            sleep(dur);
99
100            self.wake_time += self.seconds_per_byte;
101            byte
102        })
103    }
104}
105
106/// The communication channels for one party. These also keep track of how many bytes are sent.
107pub struct Channels {
108    id: usize,
109    senders: Vec<Sender<Message>>,
110    receiver: Receiver<Message>,
111    buffer: Vec<Queue<(Instant, Vec<u8>)>>,
112    sent_bytes: Vec<usize>,
113    latency: Duration,
114    seconds_per_byte: Duration,
115    next_vacancy: Instant,
116}
117
118impl Channels {
119    /// Contructs a new channel with communication overhead.
120    pub fn new(
121        id: usize,
122        senders: Vec<Sender<Message>>,
123        receiver: Receiver<Message>,
124        latency: Duration,
125        seconds_per_byte: Duration,
126    ) -> Self {
127        let sender_count = senders.len();
128
129        Channels {
130            id,
131            senders,
132            receiver,
133            buffer: (0..sender_count - 1).map(|_| Queue::new()).collect(),
134            sent_bytes: vec![0; sender_count],
135            latency,
136            seconds_per_byte,
137            next_vacancy: Instant::now(),
138        }
139    }
140
141    fn add_sent_bytes(&mut self, byte_count: usize, to_id: &usize) {
142        self.sent_bytes[*to_id] += byte_count;
143    }
144
145    /// Blocks until this party receives a message from the party with `from_id`. A message is a
146    /// vector of bytes `Vec<u8>`. This can be achieved for example using `bincode` serialization.
147    /// The simulated delays are planned in such a way that they mimick the given bandwidth and latency constraints in the case where messages are scheduled optimally.
148    pub fn receive(&mut self, from_id: &usize) -> DelayedByteIterator {
149        debug_assert_ne!(
150            *from_id, self.id,
151            "`from_id = {}` may not be the same as `self.id = {}`",
152            from_id, self.id
153        );
154
155        let reduced_id = if *from_id < self.id {
156            *from_id
157        } else {
158            *from_id - 1
159        };
160
161        let (arrival_time, bytes) = match self.buffer[reduced_id].size() {
162            0 => loop {
163                let message = self.receiver.recv().unwrap();
164
165                if message.from_id == *from_id {
166                    break (message.arrival_time, message.contents);
167                }
168
169                let message_reduced_id = if message.from_id < self.id {
170                    message.from_id
171                } else {
172                    message.from_id - 1
173                };
174                self.buffer[message_reduced_id]
175                    .add((message.arrival_time, message.contents))
176                    .unwrap();
177            },
178            _ => self.buffer[reduced_id].remove().unwrap(),
179        };
180
181        // Sleep until the next vacancy (the previously received message is only done transferring at that moment)
182        sleep(self.next_vacancy - Instant::now());
183
184        // The message must have arrived, so make sure to sleep until then (this sleep may be skipped if the message already arrived earlier)
185        sleep(arrival_time - Instant::now());
186
187        // If we already passed the next vacancy, we can skip the iterator ahead for the time we missed between the next vacancy/arrival time and now.
188        let start_time = cmp::max(self.next_vacancy, arrival_time);
189
190        // Set the next vacancy to be when this iterator finishes
191        self.next_vacancy = start_time + self.seconds_per_byte * bytes.len() as u32;
192
193        // We subtract this time from the arrival time for simplicity.
194        DelayedByteIterator::new(bytes, start_time, self.seconds_per_byte)
195    }
196
197    /// Sends a vector of bytes to the party with `to_id` and keeps track of the number of bits sent
198    /// to this party.
199    pub fn send(&mut self, message: &[u8], to_id: &usize) {
200        let byte_count = message.len();
201
202        self.senders[*to_id]
203            .send(Message {
204                arrival_time: Instant::now() + self.latency,
205                from_id: self.id,
206                contents: message.to_vec(),
207            })
208            .unwrap();
209
210        self.add_sent_bytes(byte_count, to_id);
211    }
212
213    /// Broadcasts a message (a vector of bytes) to all parties and keeps track of the number of
214    /// bits sent.
215    pub fn broadcast(&mut self, message: &[u8]) {
216        let byte_count = message.len();
217
218        for sender in &self.senders {
219            sender
220                .send(Message {
221                    arrival_time: Instant::now() + self.latency,
222                    from_id: self.id,
223                    contents: message.to_vec(),
224                })
225                .unwrap();
226        }
227
228        for i in 0..self.senders.len() {
229            self.add_sent_bytes(byte_count, &i);
230        }
231    }
232}