Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e9d45a3
HyStart++ impl, HyStart++ (D)CUBIC example, HyStart as option
hfstco Feb 17, 2025
aa087f9
moved functions to CC part of the code
hfstco Feb 18, 2025
186816b
Merge branch 'private-octopus:master' into hystart++_as_option
hfstco Feb 18, 2025
d16ddfa
added simple example hystart++ test case
hfstco Feb 18, 2025
27e2c28
try to fix linker error
hfstco Feb 18, 2025
c4f5436
Add hystart_test.c to VS solution
huitema Feb 18, 2025
c4b48c9
Merge remote-tracking branch 'refs/remotes/private_octopus/master' in…
hfstco Feb 19, 2025
95b3512
HyStart++ picoquic_ns impl & example
hfstco Feb 19, 2025
a91228b
introduced hystart_alg enum, typo, hystart = 0 (default)
hfstco Feb 19, 2025
77569c6
unittest1 fix
hfstco Feb 19, 2025
1a07304
prague impl
hfstco Feb 20, 2025
549c2f3
partial hystart++ support for newreno
hfstco Feb 25, 2025
736354e
newreno hystart++ bypass to avoid multiple failing tests, until newre…
hfstco Feb 25, 2025
4e0ce94
Merge remote-tracking branch 'private_octopus/master' into hystart++
hfstco Mar 5, 2025
c02d06f
Merge remote-tracking branch 'refs/remotes/private_octopus/master' in…
hfstco Mar 17, 2025
a0bc6b5
IS_IN_CSS fix, window_end fix
hfstco Mar 17, 2025
2f27936
Merge remote-tracking branch 'private_octopus/master' into hystart++
hfstco Apr 16, 2025
5952858
Merge remote-tracking branch 'private_octopus/master' into hystart++
hfstco Apr 20, 2025
9887a91
Merge remote-tracking branch 'private_octopus/master' into hystart++
hfstco May 1, 2025
8ba66ec
Remove HyStart algorithm configuration for enhanced modularity
hfstco May 3, 2025
5fe159a
Add cc_compete_cubic2_hystart_pp_test function.
hfstco May 4, 2025
9477fd2
Update config usage reference to remove HyStart option
hfstco May 8, 2025
cd68dd1
Refactor HyStart++ logic into a shared utility function.
hfstco May 8, 2025
3ede626
Refactor HyStart++ initialization by removing redundancy
hfstco May 8, 2025
b09e564
Remove deprecated HYSTART option from configuration enum
hfstco May 8, 2025
b5fc0d9
Add HyStart++ support to BBR congestion control.
hfstco May 8, 2025
b93ba29
Consolidate hystart tests into a single unified framework
hfstco May 9, 2025
b107c2e
BBR fix and HyStart tests
hfstco May 9, 2025
9ec0ad9
Revert CMakeLists.txt compiler optimization changes
hfstco May 9, 2025
1b19377
Merge remote-tracking branch 'picoquic/master' into hystart++
hfstco Aug 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ set(PICOQUIC_TEST_LIBRARY_FILES
picoquictest/getter_test.c
picoquictest/hashtest.c
picoquictest/high_latency_test.c
picoquictest/hystart_test.c
picoquictest/intformattest.c
picoquictest/l4s_test.c
picoquictest/mbedtls_test.c
Expand Down
13 changes: 13 additions & 0 deletions UnitTest1/unittest1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,13 @@ namespace UnitTest1
Assert::AreEqual(ret, 0);
}

TEST_METHOD(cc_compete_cubic2_hystart_pp)
{
int ret = cc_compete_cubic2_hystart_pp_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(cc_compete_prague2)
{
int ret = cc_compete_prague2_test();
Expand Down Expand Up @@ -3438,6 +3445,12 @@ namespace UnitTest1
Assert::AreEqual(ret, 0);
}

TEST_METHOD(hystart) {
int ret = hystart_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(cplusplus) {
int ret = cplusplustest();

Expand Down
1 change: 1 addition & 0 deletions picohttp_t/picohttp_t.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ static const picoquic_test_def_t test_table[] = {
{ "quicperf_multi", quicperf_multi_test },
{ "quicperf_overflow", quicperf_overflow_test },
{ "cc_compete_cubic2", cc_compete_cubic2_test },
{ "cc_compete_cubic2_hystart_pp", cc_compete_cubic2_hystart_pp_test },
{ "cc_compete_prague2", cc_compete_prague2_test },
{ "cc_compete_d_cubic", cc_compete_d_cubic_test },
{ "cc_ns_asym", cc_ns_asym_test },
Expand Down
46 changes: 32 additions & 14 deletions picoquic/bbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ typedef struct st_picoquic_bbr_state_t {
picoquic_min_max_rtt_t rtt_filter;
uint64_t bdp_seed;
unsigned int probe_bdp_seed;
/* HyStart++ */
picoquic_hystart_alg_t hystart_alg;
picoquic_hystart_pp_state_t hystart_pp_state;

/* Experimental extensions, may or maynot be a good idea. */
char const* option_string;
Expand Down Expand Up @@ -545,6 +548,11 @@ static void BBRSetOptions(picoquic_bbr_state_t* bbr_state)
break;
}
}
case 'Y':
/* Reading digits into an uint64_t */
bbr_state->hystart_alg = atoi(x);
x++;
break;
case ':':
/* Ignore */
break;
Expand All @@ -556,7 +564,7 @@ static void BBRSetOptions(picoquic_bbr_state_t* bbr_state)
}

/* Initialization of the BBR state */
static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time, char const * option_string)
static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, uint64_t current_time, char const * option_string)
{
/* TODO:
init_windowed_max_filter(filter = BBR.MaxBwFilter, value = 0, time = 0)
Expand Down Expand Up @@ -593,11 +601,17 @@ static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x,
BBRInitFullPipe(bbr_state);
BBRInitPacingRate(bbr_state, path_x);
BBREnterStartup(bbr_state, path_x);

/* HyStart++ */
memset(&bbr_state->hystart_pp_state, 0, sizeof(picoquic_hystart_pp_state_t));
if (IS_HYSTART_PP(bbr_state->hystart_alg)) {
picoquic_hystart_pp_reset(&bbr_state->hystart_pp_state, cnx, path_x);
}
}

static void picoquic_bbr_reset(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time)
static void picoquic_bbr_reset(picoquic_bbr_state_t* bbr_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, uint64_t current_time)
{
BBROnInit(bbr_state, path_x, current_time, bbr_state->option_string);
BBROnInit(bbr_state, cnx, path_x, current_time, bbr_state->option_string);
}

static void picoquic_bbr_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time)
Expand All @@ -607,7 +621,7 @@ static void picoquic_bbr_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, cha

path_x->congestion_alg_state = (void*)bbr_state;
if (bbr_state != NULL) {
BBROnInit(bbr_state, path_x, current_time, option_string);
BBROnInit(bbr_state, cnx, path_x, current_time, option_string);
}
}

Expand Down Expand Up @@ -2125,7 +2139,7 @@ static void BBRExitStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path
BBRCheckDrain(bbr_state, path_x, current_time);
}

void BBRCheckStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t* rs, uint64_t current_time)
void BBRCheckStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, bbr_per_ack_state_t* rs, uint64_t current_time)
{
if ((bbr_state->state == picoquic_bbr_alg_startup ||
bbr_state->state == picoquic_bbr_alg_startup_resume) &&
Expand All @@ -2136,9 +2150,11 @@ void BBRCheckStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* pa
return;
}

if (picoquic_cc_hystart_test(&bbr_state->rtt_filter, rs->rtt_sample,
if (bbr_state->hystart_alg == picoquic_hystart_alg_hystart_t && picoquic_cc_hystart_test(&bbr_state->rtt_filter, rs->rtt_sample,
path_x->pacing.packet_time_microsec, current_time, 0)) {
BBRExitStartupLongRtt(bbr_state, path_x, current_time);
} else if (bbr_state->hystart_alg == picoquic_hystart_alg_hystart_pp_t && picoquic_cc_hystart_pp_test(&bbr_state->hystart_pp_state, cnx, path_x, rs->rtt_sample)) {
BBRExitStartupLongRtt(bbr_state, path_x, current_time);
}
else if (rs->ecn_alpha > BBRExcessiveEcnCE) {
BBRExitStartupLongRtt(bbr_state, path_x, current_time);
Expand All @@ -2155,7 +2171,8 @@ void BBRCheckStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* pa
void BBRUpdateStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t* rs, uint64_t current_time)
{
if (path_x->last_time_acked_data_frame_sent > path_x->last_sender_limited_time) {
path_x->cwin += picoquic_cc_slow_start_increase(path_x, rs->newly_acked);
path_x->cwin += picoquic_cc_slow_start_increase_ex(path_x, rs->newly_acked,
(IS_HYSTART_PP(bbr_state->hystart_alg)) ? IS_IN_CSS(bbr_state->hystart_pp_state) : 0);
}

uint64_t max_win = path_x->peak_bandwidth_estimate * bbr_state->min_rtt / 1000000;
Expand Down Expand Up @@ -2308,12 +2325,12 @@ static void BBRAdvanceEcnFrac(picoquic_bbr_state_t* bbr_state, picoquic_path_t*
/* BBRv3 per ACK steps
* The function BBRUpdateOnACK is executed for each ACK notification on the API
*/
static void BBRUpdateModelAndState(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t * rs, uint64_t current_time)
static void BBRUpdateModelAndState(picoquic_bbr_state_t* bbr_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, bbr_per_ack_state_t * rs, uint64_t current_time)
{
BBRUpdateLatestDeliverySignals(bbr_state, path_x, rs);
BBRUpdateCongestionSignals(bbr_state, path_x, rs);
BBRUpdateACKAggregation(bbr_state, path_x, rs, current_time);
BBRCheckStartupLongRtt(bbr_state, path_x, rs, current_time);
BBRCheckStartupLongRtt(bbr_state, cnx, path_x, rs, current_time);
BBRCheckStartupResume(bbr_state, path_x, rs, current_time);
BBRCheckStartupDone(bbr_state, path_x, rs, current_time);
BBRCheckRecovery(bbr_state, path_x, rs, current_time);
Expand All @@ -2333,9 +2350,9 @@ static void BBRUpdateControlParameters(picoquic_bbr_state_t* bbr_state, picoquic
BBRSetCwnd(bbr_state, path_x, rs);
}

void BBRUpdateOnACK(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t * rs, uint64_t current_time)
void BBRUpdateOnACK(picoquic_bbr_state_t* bbr_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, bbr_per_ack_state_t * rs, uint64_t current_time)
{
BBRUpdateModelAndState(bbr_state, path_x, rs, current_time);
BBRUpdateModelAndState(bbr_state, cnx, path_x, rs, current_time);
if (bbr_state->state == picoquic_bbr_alg_startup_long_rtt) {
BBRUpdateStartupLongRtt(bbr_state, path_x, rs, current_time);
}
Expand Down Expand Up @@ -2388,14 +2405,15 @@ static void BBRSetRsFromAckState(picoquic_path_t* path_x, picoquic_per_ack_state

static void picoquic_bbr_notify_ack(
picoquic_bbr_state_t* bbr_state,
picoquic_cnx_t* cnx,
picoquic_path_t* path_x,
picoquic_per_ack_state_t* ack_state,
uint64_t current_time)
{
bbr_per_ack_state_t rs = { 0 };
BBRSetRsFromAckState(path_x, ack_state, &rs);
BBRComputeEcnFrac(bbr_state, path_x, &rs);
BBRUpdateOnACK(bbr_state, path_x, &rs, current_time);
BBRUpdateOnACK(bbr_state, cnx, path_x, &rs, current_time);
}

/*
Expand Down Expand Up @@ -2440,7 +2458,7 @@ static void picoquic_bbr_notify(
break;
case picoquic_congestion_notification_acknowledgement:
BBRExitLostFeedback(bbr_state, path_x);
picoquic_bbr_notify_ack(bbr_state, path_x, ack_state, current_time);
picoquic_bbr_notify_ack(bbr_state, cnx, path_x, ack_state, current_time);
if (bbr_state->state == picoquic_bbr_alg_startup_long_rtt) {
picoquic_update_pacing_data(cnx, path_x, 1);
}
Expand All @@ -2452,7 +2470,7 @@ static void picoquic_bbr_notify(
case picoquic_congestion_notification_cwin_blocked:
break;
case picoquic_congestion_notification_reset:
picoquic_bbr_reset(bbr_state, path_x, current_time);
picoquic_bbr_reset(bbr_state, cnx, path_x, current_time);
break;
case picoquic_congestion_notification_seed_cwin:
BBRSetBdpSeed(bbr_state, ack_state->nb_bytes_acknowledged);
Expand Down
45 changes: 35 additions & 10 deletions picoquic/bbr1.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,9 @@ typedef struct st_picoquic_bbr1_state_t {
uint64_t bytes_delivered; /* Number of bytes signalled in ACK notify, but not processed yet */
uint64_t send_quantum;
picoquic_min_max_rtt_t rtt_filter;
/* HyStart++. */
picoquic_hystart_alg_t hystart_alg;
picoquic_hystart_pp_state_t hystart_pp_state;
uint64_t target_cwnd;
double pacing_gain;
double cwnd_gain;
Expand Down Expand Up @@ -436,19 +439,21 @@ static void picoquic_bbr1_set_options(picoquic_bbr1_state_t* bbr1_state)
break;
}
}
case ':':
/* Ignore */
case 'Y':
/* Reading digits into an uint64_t */
bbr1_state->hystart_alg = atoi(x);
x++;
break;
case ':': /* Ignore. */
default:
break;
}
}
}
}

static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_path_t* path_x, uint64_t current_time)
static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_cnx_t* cnx, picoquic_path_t* path_x, uint64_t current_time)
{
memset(bbr1_state, 0, sizeof(picoquic_bbr1_state_t));
path_x->cwin = PICOQUIC_CWIN_INITIAL;
bbr1_state->rt_prop = UINT64_MAX;
picoquic_bbr1_set_options(bbr1_state);
Expand All @@ -464,6 +469,12 @@ static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_path
BBR1EnterStartup(bbr1_state);
BBR1SetSendQuantum(bbr1_state, path_x);
BBR1UpdateTargetCwnd(bbr1_state);

/* HyStart++ */
memset(&bbr1_state->hystart_pp_state, 0, sizeof(picoquic_hystart_pp_state_t));
if (IS_HYSTART_PP(bbr1_state->hystart_alg)) {
picoquic_hystart_pp_reset(&bbr1_state->hystart_pp_state, cnx, path_x);
}
}

static void picoquic_bbr1_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time)
Expand All @@ -473,8 +484,9 @@ static void picoquic_bbr1_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, ch

path_x->congestion_alg_state = (void*)bbr1_state;
if (bbr1_state != NULL) {
memset(bbr1_state, 0, sizeof(picoquic_bbr1_state_t));
bbr1_state->option_string = option_string;
picoquic_bbr1_reset(bbr1_state, path_x, current_time);
picoquic_bbr1_reset(bbr1_state, cnx, path_x, current_time);
}
}

Expand Down Expand Up @@ -1238,9 +1250,21 @@ static void picoquic_bbr1_notify(
}

if (bbr1_state->state == picoquic_bbr1_alg_startup_long_rtt) {
if (picoquic_cc_hystart_test(&bbr1_state->rtt_filter, (cnx->is_time_stamp_enabled) ? ack_state->one_way_delay : ack_state->rtt_measurement,
cnx->path[0]->pacing.packet_time_microsec, current_time, cnx->is_time_stamp_enabled)) {
BBR1ExitStartupLongRtt(bbr1_state, path_x, current_time);
switch (bbr1_state->hystart_alg) {
case picoquic_hystart_alg_hystart_t:
if (picoquic_cc_hystart_test(&bbr1_state->rtt_filter, (cnx->is_time_stamp_enabled) ? ack_state->one_way_delay : ack_state->rtt_measurement,
cnx->path[0]->pacing.packet_time_microsec, current_time, cnx->is_time_stamp_enabled)) {
BBR1ExitStartupLongRtt(bbr1_state, path_x, current_time);
}
break;
case picoquic_hystart_alg_hystart_pp_t:
if (picoquic_cc_hystart_pp_test(&bbr1_state->hystart_pp_state, cnx, path_x, ack_state->rtt_measurement)) {
BBR1ExitStartupLongRtt(bbr1_state, path_x, current_time);
}
break;
case picoquic_hystart_alg_disabled_t:
default:
break;
}
}

Expand All @@ -1255,7 +1279,8 @@ static void picoquic_bbr1_notify(
bbr1_state->rt_prop_stamp = current_time;
}
if (path_x->last_time_acked_data_frame_sent > path_x->last_sender_limited_time) {
path_x->cwin += picoquic_cc_slow_start_increase(path_x, bbr1_state->bytes_delivered);
path_x->cwin += picoquic_cc_slow_start_increase_ex(path_x, ack_state->nb_bytes_acknowledged,
(IS_HYSTART_PP(bbr1_state->hystart_alg)) ? IS_IN_CSS(bbr1_state->hystart_pp_state) : 0);
}
bbr1_state->bytes_delivered = 0;

Expand Down Expand Up @@ -1288,7 +1313,7 @@ static void picoquic_bbr1_notify(
case picoquic_congestion_notification_cwin_blocked:
break;
case picoquic_congestion_notification_reset:
picoquic_bbr1_reset(bbr1_state, path_x, current_time);
picoquic_bbr1_reset(bbr1_state, cnx, path_x, current_time);
break;
case picoquic_congestion_notification_seed_cwin:
if (bbr1_state->state == picoquic_bbr1_alg_startup_long_rtt) {
Expand Down
Loading
Loading