Skip to content

Commit 6279114

Browse files
committed
chore: Avoid Box<dyn CongestionControl>
For discussion - is this worth it? (The extra dep could be avoided if we implement a dispatch macro ourselves.)
1 parent 4c45dc6 commit 6279114

6 files changed

Lines changed: 57 additions & 36 deletions

File tree

Cargo.lock

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ license = "MIT OR Apache-2.0"
3030
rust-version = "1.90.0"
3131

3232
[workspace.dependencies]
33+
enum_dispatch = { version = "0.3", default-features = false }
3334
enum-map = { version = "2.7", default-features = false }
3435
enumset = { version = "1.1", default-features = false }
3536
hex = { version = "0.4", default-features = false }

neqo-transport/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ workspace = true
1818

1919
[dependencies]
2020
# Checked against https://searchfox.org/mozilla-central/source/Cargo.lock 2024-11-11
21+
enum_dispatch = { workspace = true }
2122
enum-map = { workspace = true }
2223
enumset = { workspace = true }
2324
indexmap = { version = "2", default-features = false } # See https://github.com/mozilla/neqo/issues/1858

neqo-transport/src/cc/classic_cc.rs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,11 @@ impl<T> ClassicCongestionControl<T> {
190190
pub const fn max_datagram_size(&self) -> usize {
191191
self.pmtud.plpmtu()
192192
}
193+
194+
#[cfg(test)]
195+
pub const fn cwnd_initial(&self) -> usize {
196+
cwnd_initial(self.pmtud.plpmtu())
197+
}
193198
}
194199

195200
impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
@@ -218,11 +223,6 @@ impl<T: WindowAdjustment> CongestionControl for ClassicCongestionControl<T> {
218223
self.max_datagram_size() * 2
219224
}
220225

221-
#[cfg(test)]
222-
fn cwnd_initial(&self) -> usize {
223-
cwnd_initial(self.pmtud.plpmtu())
224-
}
225-
226226
fn pmtud(&self) -> &Pmtud {
227227
&self.pmtud
228228
}
@@ -841,7 +841,7 @@ mod tests {
841841
use crate::{
842842
Pmtud,
843843
cc::{
844-
CWND_INITIAL_PKTS, CongestionControl, CongestionControlAlgorithm, CongestionEvent,
844+
CWND_INITIAL_PKTS, CongestionControl as _, CongestionController, CongestionEvent,
845845
classic_cc::Phase,
846846
cubic::Cubic,
847847
new_reno::NewReno,
@@ -884,21 +884,8 @@ mod tests {
884884
)
885885
}
886886

887-
fn congestion_control(cc: CongestionControlAlgorithm) -> Box<dyn CongestionControl> {
888-
match cc {
889-
CongestionControlAlgorithm::NewReno => Box::new(ClassicCongestionControl::new(
890-
NewReno::default(),
891-
Pmtud::new(IP_ADDR, MTU),
892-
)),
893-
CongestionControlAlgorithm::Cubic => Box::new(ClassicCongestionControl::new(
894-
Cubic::default(),
895-
Pmtud::new(IP_ADDR, MTU),
896-
)),
897-
}
898-
}
899-
900887
fn persistent_congestion_by_algorithm(
901-
mut cc: Box<dyn CongestionControl>,
888+
mut cc: CongestionController,
902889
reduced_cwnd: usize,
903890
lost_packets: &[sent::Packet],
904891
persistent_expected: bool,
@@ -922,14 +909,19 @@ mod tests {
922909
}
923910

924911
fn persistent_congestion(lost_packets: &[sent::Packet], persistent_expected: bool) {
925-
let cc = congestion_control(CongestionControlAlgorithm::NewReno);
912+
let cc = ClassicCongestionControl::new(NewReno::default(), Pmtud::new(IP_ADDR, MTU));
926913
let cwnd_initial = cc.cwnd_initial();
927-
persistent_congestion_by_algorithm(cc, cwnd_initial / 2, lost_packets, persistent_expected);
914+
persistent_congestion_by_algorithm(
915+
CongestionController::NewReno(cc),
916+
cwnd_initial / 2,
917+
lost_packets,
918+
persistent_expected,
919+
);
928920

929-
let cc = congestion_control(CongestionControlAlgorithm::Cubic);
921+
let cc = ClassicCongestionControl::new(Cubic::default(), Pmtud::new(IP_ADDR, MTU));
930922
let cwnd_initial = cc.cwnd_initial();
931923
persistent_congestion_by_algorithm(
932-
cc,
924+
CongestionController::Cubic(cc),
933925
cwnd_initial * Cubic::BETA_USIZE_DIVIDEND / Cubic::BETA_USIZE_DIVISOR,
934926
lost_packets,
935927
persistent_expected,

neqo-transport/src/cc/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{
1111
time::{Duration, Instant},
1212
};
1313

14+
use enum_dispatch::enum_dispatch;
1415
use enum_map::Enum;
1516
use neqo_common::qlog::Qlog;
1617

@@ -31,6 +32,7 @@ pub enum CongestionEvent {
3132
Spurious,
3233
}
3334

35+
#[enum_dispatch]
3436
pub trait CongestionControl: Display + Debug {
3537
fn set_qlog(&mut self, qlog: Qlog);
3638

@@ -46,10 +48,6 @@ pub trait CongestionControl: Display + Debug {
4648
#[must_use]
4749
fn cwnd_min(&self) -> usize;
4850

49-
#[cfg(test)]
50-
#[must_use]
51-
fn cwnd_initial(&self) -> usize;
52-
5351
#[must_use]
5452
fn pmtud(&self) -> &Pmtud;
5553

@@ -103,6 +101,19 @@ pub enum CongestionControlAlgorithm {
103101
Cubic,
104102
}
105103

104+
/// A concrete congestion controller, dispatching to either `NewReno` or `Cubic`.
105+
///
106+
/// This enum avoids the heap allocation and vtable indirection of `Box<dyn CongestionControl>`
107+
/// on the per-packet hot path.
108+
#[enum_dispatch(CongestionControl)]
109+
#[derive(Debug, strum::Display)]
110+
pub enum CongestionController {
111+
#[strum(to_string = "{0}")]
112+
NewReno(ClassicCongestionControl<NewReno>),
113+
#[strum(to_string = "{0}")]
114+
Cubic(ClassicCongestionControl<Cubic>),
115+
}
116+
106117
#[cfg(test)]
107118
#[cfg_attr(coverage_nightly, coverage(off))]
108119
mod tests;

neqo-transport/src/sender.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ use neqo_common::{qdebug, qlog::Qlog};
1212

1313
use crate::{
1414
ConnectionParameters, Stats,
15-
cc::{ClassicCongestionControl, CongestionControl, CongestionControlAlgorithm, Cubic, NewReno},
15+
cc::{
16+
ClassicCongestionControl, CongestionControl as _, CongestionControlAlgorithm,
17+
CongestionController, Cubic, NewReno,
18+
},
1619
pace::Pacer,
1720
pmtud::Pmtud,
1821
recovery::sent,
@@ -25,7 +28,7 @@ pub const PACING_BURST_SIZE: usize = 2;
2528

2629
#[derive(Debug)]
2730
pub struct PacketSender {
28-
cc: Box<dyn CongestionControl>,
31+
cc: CongestionController,
2932
pacer: Pacer,
3033
}
3134

@@ -35,12 +38,12 @@ impl PacketSender {
3538
let mtu = pmtud.plpmtu();
3639
Self {
3740
cc: match conn_params.get_cc_algorithm() {
38-
CongestionControlAlgorithm::NewReno => {
39-
Box::new(ClassicCongestionControl::new(NewReno::default(), pmtud))
40-
}
41-
CongestionControlAlgorithm::Cubic => {
42-
Box::new(ClassicCongestionControl::new(Cubic::default(), pmtud))
43-
}
41+
CongestionControlAlgorithm::NewReno => CongestionController::NewReno(
42+
ClassicCongestionControl::new(NewReno::default(), pmtud),
43+
),
44+
CongestionControlAlgorithm::Cubic => CongestionController::Cubic(
45+
ClassicCongestionControl::new(Cubic::default(), pmtud),
46+
),
4447
},
4548
pacer: Pacer::new(
4649
conn_params.pacing_enabled(),

0 commit comments

Comments
 (0)