Skip to content

Commit 3287939

Browse files
authored
chore: Avoid Box<dyn CongestionControl> (#3451)
* chore: Avoid `Box<dyn CongestionControl>` For discussion - is this worth it? (The extra dep could be avoided if we implement a dispatch macro ourselves.) * Use shared macro * Fix
1 parent 143849d commit 3287939

4 files changed

Lines changed: 163 additions & 28 deletions

File tree

neqo-common/src/lib.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ pub enum MessageType {
107107
Response,
108108
}
109109

110+
/// Dispatch a method call on an enum to its variants' inner values.
111+
///
112+
/// The variant list is given once in a local wrapper; method bodies stay clean:
113+
///
114+
/// ```ignore
115+
/// // Once per enum, in the impl module:
116+
/// macro_rules! dispatch {
117+
/// ($self:ident . $method:ident $args:tt) => {
118+
/// neqo_common::dispatch!([Variant1, Variant2, Variant3] $self . $method $args)
119+
/// };
120+
/// }
121+
///
122+
/// impl SomeTrait for MyEnum {
123+
/// fn method(&self) -> T { dispatch!(self.method()) }
124+
/// }
125+
/// ```
126+
#[macro_export]
127+
macro_rules! dispatch {
128+
([$($variant:ident),+ $(,)?] $self:ident . $method:ident $args:tt) => {
129+
match $self {
130+
$( Self::$variant(v) => v.$method $args, )+
131+
}
132+
};
133+
}
134+
110135
#[cfg(test)]
111136
#[cfg_attr(coverage_nightly, coverage(off))]
112137
mod tests {

neqo-transport/src/cc/classic_cc.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,11 @@ impl<S, T> ClassicCongestionController<S, T> {
229229
pub const fn max_datagram_size(&self) -> usize {
230230
self.pmtud.plpmtu()
231231
}
232+
233+
#[cfg(test)]
234+
pub const fn cwnd_initial(&self) -> usize {
235+
cwnd_initial(self.pmtud.plpmtu())
236+
}
232237
}
233238

234239
impl<S, T> CongestionController for ClassicCongestionController<S, T>
@@ -261,11 +266,6 @@ where
261266
self.max_datagram_size() * 2
262267
}
263268

264-
#[cfg(test)]
265-
fn cwnd_initial(&self) -> usize {
266-
cwnd_initial(self.pmtud.plpmtu())
267-
}
268-
269269
fn pmtud(&self) -> &Pmtud {
270270
&self.pmtud
271271
}

neqo-transport/src/cc/mod.rs

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ pub trait CongestionController: Display + Debug {
4848
#[must_use]
4949
fn cwnd_min(&self) -> usize;
5050

51-
#[cfg(test)]
52-
#[must_use]
53-
fn cwnd_initial(&self) -> usize;
54-
5551
#[must_use]
5652
fn pmtud(&self) -> &Pmtud;
5753

@@ -115,6 +111,116 @@ pub enum SlowStart {
115111
HyStart,
116112
}
117113

114+
/// A concrete congestion controller, dispatching across all combinations of
115+
/// algorithm and slow-start strategy.
116+
///
117+
/// This enum avoids the heap allocation and vtable indirection of `Box<dyn CongestionController>`
118+
/// on the per-packet hot path.
119+
#[derive(Debug, strum::Display)]
120+
pub enum CongestionControlImplementation {
121+
#[strum(to_string = "{0}")]
122+
ClassicNewReno(ClassicCongestionController<ClassicSlowStart, NewReno>),
123+
#[strum(to_string = "{0}")]
124+
HyStartNewReno(ClassicCongestionController<HyStart, NewReno>),
125+
#[strum(to_string = "{0}")]
126+
ClassicCubic(ClassicCongestionController<ClassicSlowStart, Cubic>),
127+
#[strum(to_string = "{0}")]
128+
HyStartCubic(ClassicCongestionController<HyStart, Cubic>),
129+
}
130+
131+
macro_rules! dispatch {
132+
($self:ident . $method:ident $args:tt) => {
133+
neqo_common::dispatch!(
134+
[ClassicNewReno, HyStartNewReno, ClassicCubic, HyStartCubic]
135+
$self . $method $args
136+
)
137+
};
138+
}
139+
140+
impl CongestionController for CongestionControlImplementation {
141+
fn set_qlog(&mut self, qlog: Qlog) {
142+
dispatch!(self.set_qlog(qlog));
143+
}
144+
145+
fn cwnd(&self) -> usize {
146+
dispatch!(self.cwnd())
147+
}
148+
149+
fn bytes_in_flight(&self) -> usize {
150+
dispatch!(self.bytes_in_flight())
151+
}
152+
153+
fn cwnd_avail(&self) -> usize {
154+
dispatch!(self.cwnd_avail())
155+
}
156+
157+
fn cwnd_min(&self) -> usize {
158+
dispatch!(self.cwnd_min())
159+
}
160+
161+
fn pmtud(&self) -> &Pmtud {
162+
dispatch!(self.pmtud())
163+
}
164+
165+
fn pmtud_mut(&mut self) -> &mut Pmtud {
166+
dispatch!(self.pmtud_mut())
167+
}
168+
169+
fn on_packets_acked(
170+
&mut self,
171+
acked_pkts: &[sent::Packet],
172+
rtt_est: &RttEstimate,
173+
now: Instant,
174+
cc_stats: &mut CongestionControlStats,
175+
) {
176+
dispatch!(self.on_packets_acked(acked_pkts, rtt_est, now, cc_stats));
177+
}
178+
179+
fn on_packets_lost(
180+
&mut self,
181+
first_rtt_sample_time: Option<Instant>,
182+
prev_largest_acked_sent: Option<Instant>,
183+
pto: Duration,
184+
lost_packets: &[sent::Packet],
185+
now: Instant,
186+
cc_stats: &mut CongestionControlStats,
187+
) -> bool {
188+
dispatch!(self.on_packets_lost(
189+
first_rtt_sample_time,
190+
prev_largest_acked_sent,
191+
pto,
192+
lost_packets,
193+
now,
194+
cc_stats,
195+
))
196+
}
197+
198+
fn on_ecn_ce_received(
199+
&mut self,
200+
largest_acked_pkt: &sent::Packet,
201+
now: Instant,
202+
cc_stats: &mut CongestionControlStats,
203+
) -> bool {
204+
dispatch!(self.on_ecn_ce_received(largest_acked_pkt, now, cc_stats))
205+
}
206+
207+
fn recovery_packet(&self) -> bool {
208+
dispatch!(self.recovery_packet())
209+
}
210+
211+
fn discard(&mut self, pkt: &sent::Packet, now: Instant) {
212+
dispatch!(self.discard(pkt, now));
213+
}
214+
215+
fn on_packet_sent(&mut self, pkt: &sent::Packet, now: Instant) {
216+
dispatch!(self.on_packet_sent(pkt, now));
217+
}
218+
219+
fn discard_in_flight(&mut self, now: Instant) {
220+
dispatch!(self.discard_in_flight(now));
221+
}
222+
}
223+
118224
#[cfg(test)]
119225
#[cfg_attr(coverage_nightly, coverage(off))]
120226
mod tests;

neqo-transport/src/sender.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use neqo_common::{qdebug, qlog::Qlog};
1313
use crate::{
1414
ConnectionParameters, SlowStart, Stats,
1515
cc::{
16-
ClassicCongestionController, ClassicSlowStart, CongestionControl, CongestionController,
17-
Cubic, HyStart, NewReno,
16+
ClassicCongestionController, ClassicSlowStart, CongestionControl,
17+
CongestionControlImplementation, CongestionController as _, Cubic, HyStart, NewReno,
1818
},
1919
pace::Pacer,
2020
pmtud::Pmtud,
@@ -29,7 +29,7 @@ pub const PACING_BURST_SIZE: usize = 2;
2929

3030
#[derive(Debug)]
3131
pub struct PacketSender {
32-
cc: Box<dyn CongestionController>,
32+
cc: CongestionControlImplementation,
3333
pacer: Pacer,
3434
qlog: Qlog,
3535
}
@@ -45,34 +45,38 @@ impl PacketSender {
4545
conn_params.get_slow_start(),
4646
) {
4747
(CongestionControl::NewReno, SlowStart::Classic) => {
48-
Box::new(ClassicCongestionController::new(
49-
ClassicSlowStart::default(),
50-
NewReno::default(),
51-
pmtud,
52-
spurious_recovery,
53-
))
48+
CongestionControlImplementation::ClassicNewReno(
49+
ClassicCongestionController::new(
50+
ClassicSlowStart::default(),
51+
NewReno::default(),
52+
pmtud,
53+
spurious_recovery,
54+
),
55+
)
5456
}
5557
(CongestionControl::NewReno, SlowStart::HyStart) => {
56-
Box::new(ClassicCongestionController::new(
57-
HyStart::new(
58-
conn_params.pacing_enabled(),
59-
conn_params.get_hystart_css_baseline(),
58+
CongestionControlImplementation::HyStartNewReno(
59+
ClassicCongestionController::new(
60+
HyStart::new(
61+
conn_params.pacing_enabled(),
62+
conn_params.get_hystart_css_baseline(),
63+
),
64+
NewReno::default(),
65+
pmtud,
66+
spurious_recovery,
6067
),
61-
NewReno::default(),
62-
pmtud,
63-
spurious_recovery,
64-
))
68+
)
6569
}
6670
(CongestionControl::Cubic, SlowStart::Classic) => {
67-
Box::new(ClassicCongestionController::new(
71+
CongestionControlImplementation::ClassicCubic(ClassicCongestionController::new(
6872
ClassicSlowStart::default(),
6973
Cubic::default(),
7074
pmtud,
7175
spurious_recovery,
7276
))
7377
}
7478
(CongestionControl::Cubic, SlowStart::HyStart) => {
75-
Box::new(ClassicCongestionController::new(
79+
CongestionControlImplementation::HyStartCubic(ClassicCongestionController::new(
7680
HyStart::new(
7781
conn_params.pacing_enabled(),
7882
conn_params.get_hystart_css_baseline(),

0 commit comments

Comments
 (0)