Skip to content

Commit

Permalink
Merge pull request #1629 from private-octopus/media-net-down-test
Browse files Browse the repository at this point in the history
Add Startup resume state
  • Loading branch information
huitema authored Feb 9, 2024
2 parents 032f557 + 231c237 commit 5a24917
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 14 deletions.
21 changes: 21 additions & 0 deletions PerfAndStressTest/PerfAndStressTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,27 @@ namespace PerfAndStressTest
Assert::AreEqual(ret, 0);
}

TEST_METHOD(bdp_short)
{
int ret = bdp_short_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(bdp_short_hi)
{
int ret = bdp_short_hi_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(bdp_short_lo)
{
int ret = bdp_short_lo_test();

Assert::AreEqual(ret, 0);
}

TEST_METHOD(stress)
{
int ret = stress_test();
Expand Down
117 changes: 105 additions & 12 deletions picoquic/bbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ typedef enum {
picoquic_bbr_alg_probe_bw_refill,
picoquic_bbr_alg_probe_bw_up,
picoquic_bbr_alg_probe_rtt,
picoquic_bbr_alg_startup_long_rtt
picoquic_bbr_alg_startup_long_rtt,
picoquic_bbr_alg_startup_resume
} picoquic_bbr_alg_state_t;

typedef enum {
Expand All @@ -89,8 +90,9 @@ typedef enum {

/* Constants in BBRv3 */
#define BBRPacingMarginPercent 1 /* discount factor of 1% used to scale BBR.bw to produce BBR.pacing_rate */
#define BBRStartupPacingGain 2.77 /* constant, 4*ln(2), approx 2.77 */
#define BBRStartupCwndGain 2.0 /* constant */




#define BBRLossThresh 0.2 /* maximum tolerated packet loss (default: 20%) */
#define BBRBeta 0.7 /* Multiplicative decrease on packet loss (default: 0.7) */
Expand All @@ -105,6 +107,14 @@ typedef enum {
#define BBRProbeRTTDuration 200000 /* 200msec, 200000 microsecs */
#define BBRProbeRTTInterval 5000000 /* 5 seconds */

#define BBRStartupPacingGain 2.77 /* constant, 4*ln(2), approx 2.77 */
#define BBRStartupCwndGain 2.0 /* constant */
#define BBRStartupIncreaseThreshold 1.25

#define BBRStartupResumePacingGain 1.25 /* arbitrary */
#define BBRStartupResumeCwndGain 1.25 /* arbitrary */
#define BBRStartupResumeIncreaseThreshold 1.125

#define BBRProbeBwDownPacingGain 0.9
#define BBRProbeBwDownCwndGain 2.0
#define BBRProbeBwCruisePacingGain 1.0
Expand All @@ -113,6 +123,7 @@ typedef enum {
#define BBRProbeBwRefillCwndGain 2.0
#define BBRProbeBwUpPacingGain 1.25
#define BBRProbeBwUpCwndGain 2.25

#define BBRMinRttMarginPercent 5 /* Margin factor of 20% for avoiding firing RTT Probe too often */
#define BBRLongRttThreshold 250000

Expand Down Expand Up @@ -206,6 +217,7 @@ typedef struct st_picoquic_bbr_state_t {
/* manage startup long_rtt */
picoquic_min_max_rtt_t rtt_filter;
uint64_t bdp_seed;
unsigned int probe_bdp_seed;

/* Experimental extensions, may or maynot be a good idea. */
uint64_t wifi_shadow_rtt; /* Shadow RTT used for wifi connections. */
Expand Down Expand Up @@ -265,6 +277,7 @@ static void BBRStartProbeBW_CRUISE(picoquic_bbr_state_t* bbr_state);
static void BBRStartProbeBW_REFILL(picoquic_bbr_state_t* bbr_state, picoquic_path_t * path_x);
static void BBREnterStartup(picoquic_bbr_state_t* bbr_state);
static void BBRReEnterStartup(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time);
static void BBRCheckStartupHighLoss(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t* rs);
static void BBRUpdateRound(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x);
static void BBRStartRound(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x);
static void BBRSetRsFromAckState(picoquic_path_t* path_x, picoquic_per_ack_state_t* ack_state, bbr_per_ack_state_t* rs);
Expand Down Expand Up @@ -496,6 +509,10 @@ static void BBRSetCwnd(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x,
path_x->cwin = bbr_state->max_inflight;
}
}
else if (bbr_state->state == picoquic_bbr_alg_startup_resume &&
bbr_state->bdp_seed > path_x->cwin) {
path_x->cwin = bbr_state->bdp_seed;
}
else if (path_x->cwin < bbr_state->max_inflight || path_x->delivered < PICOQUIC_CWIN_INITIAL) {
path_x->cwin = path_x->cwin+ rs->newly_acked;
}
Expand Down Expand Up @@ -678,12 +695,19 @@ static void BBRUpdateMaxInflight(picoquic_bbr_state_t* bbr_state, picoquic_path_
* BBRUpdateModelAndState(). There is probably no need to do an extra
* call here. */
uint64_t inflight = BBRBDPMultiple(bbr_state, path_x, bbr_state->cwnd_gain);

inflight += bbr_state->extra_acked;

if (bbr_state->min_rtt < bbr_state->wifi_shadow_rtt && bbr_state->min_rtt > 0){
inflight = (uint64_t)(((double)inflight) * ((double)bbr_state->wifi_shadow_rtt) / ((double)bbr_state->min_rtt));
}
bbr_state->max_inflight = BBRQuantizationBudget(bbr_state, path_x, inflight);
#if 0
if (bbr_state->state == picoquic_bbr_alg_startup &&
bbr_state->bdp_seed > bbr_state->max_inflight) {
bbr_state->max_inflight = bbr_state->bdp_seed;
}
#endif
}

/* Pacing rate functions */
Expand All @@ -701,6 +725,16 @@ static void BBRInitPacingRate(picoquic_bbr_state_t* bbr_state, picoquic_path_t*
static void BBRSetPacingRateWithGain(picoquic_bbr_state_t* bbr_state, double pacing_gain)
{
double rate = pacing_gain * ((double)(bbr_state->bw * (100 - BBRPacingMarginPercent))) / (double)100;

if (bbr_state->state == picoquic_bbr_alg_startup_resume &&
!bbr_state->filled_pipe &&
bbr_state->bdp_seed > 0) {
double bdp_rate = (((double)bbr_state->bdp_seed*1000000.0) / (double)bbr_state->min_rtt);
if (bdp_rate > rate) {
rate = bdp_rate;
}
}

if (bbr_state->filled_pipe || rate > bbr_state->pacing_rate) {
bbr_state->pacing_rate = rate;
}
Expand Down Expand Up @@ -1459,6 +1493,57 @@ static void BBRCheckDrain(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path
}
/* End of drain specific algorithms */

/* Startup extension to support careful resume */
static void BBRCheckStartupFullBandwidthGeneric(picoquic_bbr_state_t* bbr_state,
bbr_per_ack_state_t * rs, double threshold)
{
if (bbr_state->filled_pipe ||
!bbr_state->round_start || rs->is_app_limited) {
return; /* no need to check for a full pipe now */
}

if ((double)bbr_state->max_bw >= threshold*((double)bbr_state->full_bw)) {
/* still growing? */
bbr_state->full_bw = bbr_state->max_bw; /* record new baseline level */
bbr_state->full_bw_count = 0;
return;
}
bbr_state->full_bw_count++; /* another round w/o much growth */
if (bbr_state->full_bw_count >= 3) {
bbr_state->filled_pipe = 1;
}
}

static void BBREnterStartupResume(picoquic_bbr_state_t* bbr_state)
{
/* This code is called either when the "bdp seed" is set, or
* upon "Enter Startup"
*/
bbr_state->state = picoquic_bbr_alg_startup_resume;
bbr_state->pacing_gain = BBRStartupResumePacingGain;
bbr_state->cwnd_gain = BBRStartupResumeCwndGain;
}

static void BBRCheckStartupResume(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t* rs, uint64_t current_time)
{
if (bbr_state->state == picoquic_bbr_alg_startup_resume) {
BBRCheckStartupHighLoss(bbr_state, path_x, rs);
if (!bbr_state->filled_pipe && (double)bbr_state->max_bw > BBRStartupResumeIncreaseThreshold * bbr_state->bdp_seed) {
BBREnterStartup(bbr_state);
}
else {
BBRCheckStartupFullBandwidthGeneric(bbr_state, rs, BBRStartupResumeIncreaseThreshold);
if (bbr_state->filled_pipe) {
if (bbr_state->full_bw_count > 0) {
bbr_state->probe_probe_bw_quickly = 1;
bbr_state->full_bw_count = 0;
}
BBREnterDrain(bbr_state, path_x, current_time);
}
}
}
}

/* Startup specific processes for BBRv3 */
static void BBRCheckStartupHighLoss(picoquic_bbr_state_t* bbr_state, picoquic_path_t * path_x, bbr_per_ack_state_t * rs)
{
Expand Down Expand Up @@ -1500,16 +1585,18 @@ static void BBRCheckStartupFullBandwidth(picoquic_bbr_state_t* bbr_state,
static void BBRCheckStartupDone(picoquic_bbr_state_t* bbr_state,
picoquic_path_t * path_x, bbr_per_ack_state_t * rs, uint64_t current_time)
{
BBRCheckStartupFullBandwidth(bbr_state, rs);
BBRCheckStartupHighLoss(bbr_state, path_x, rs);
if (bbr_state->state == picoquic_bbr_alg_startup) {
BBRCheckStartupFullBandwidth(bbr_state, rs);
BBRCheckStartupHighLoss(bbr_state, path_x, rs);

if (bbr_state->state == picoquic_bbr_alg_startup &&
bbr_state->filled_pipe) {
if (bbr_state->full_bw_count > 0) {
bbr_state->probe_probe_bw_quickly = 1;
bbr_state->full_bw_count = 0;
if (bbr_state->state == picoquic_bbr_alg_startup &&
bbr_state->filled_pipe) {
if (bbr_state->full_bw_count > 0) {
bbr_state->probe_probe_bw_quickly = 1;
bbr_state->full_bw_count = 0;
}
BBREnterDrain(bbr_state, path_x, current_time);
}
BBREnterDrain(bbr_state, path_x, current_time);
}
}

Expand Down Expand Up @@ -1580,7 +1667,8 @@ static void BBRExitStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path

void BBRCheckStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_per_ack_state_t* rs, uint64_t current_time)
{
if (bbr_state->state == picoquic_bbr_alg_startup &&
if ((bbr_state->state == picoquic_bbr_alg_startup ||
bbr_state->state == picoquic_bbr_alg_startup_resume) &&
path_x->rtt_min > BBRLongRttThreshold) {
BBREnterStartupLongRTT(bbr_state, path_x);
}
Expand Down Expand Up @@ -1623,6 +1711,10 @@ void BBRUpdateStartupLongRtt(picoquic_bbr_state_t* bbr_state, picoquic_path_t* p
void BBRSetBdpSeed(picoquic_bbr_state_t* bbr_state, uint64_t bdp_seed)
{
bbr_state->bdp_seed = bdp_seed;
if (bbr_state->state == picoquic_bbr_alg_startup &&
bbr_state->bdp_seed > bbr_state->max_bw) {
BBREnterStartupResume(bbr_state);
}
}

/* BBRv3 per loss steps.
Expand Down Expand Up @@ -1696,6 +1788,7 @@ static void BBRUpdateModelAndState(picoquic_bbr_state_t* bbr_state, picoquic_pat
BBRUpdateCongestionSignals(bbr_state, path_x, rs);
BBRUpdateACKAggregation(bbr_state, path_x, rs, current_time);
BBRCheckStartupLongRtt(bbr_state, 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);
BBRCheckDrain(bbr_state, path_x, current_time);
Expand Down
3 changes: 3 additions & 0 deletions picoquic_t/picoquic_t.c
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ static const picoquic_test_def_t test_table[] = {
#if 0
{ "bdp_cubic", bdp_cubic_test },
#endif
{ "bdp_short", bdp_short_test },
{ "bdp_short_hi", bdp_short_hi_test },
{ "bdp_short_lo", bdp_short_lo_test },
{ "cid_length", cid_length_test },
{ "optimistic_ack", optimistic_ack_test },
{ "optimistic_hole", optimistic_hole_test },
Expand Down
3 changes: 3 additions & 0 deletions picoquictest/picoquictest.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ int bdp_cubic_test();
int bdp_rtt_test();
int bdp_ip_test();
int bdp_delay_test();
int bdp_short_test();
int bdp_short_hi_test();
int bdp_short_lo_test();
int long_rtt_test();
int high_latency_basic_test();
int high_latency_bbr_test();
Expand Down
47 changes: 45 additions & 2 deletions picoquictest/tls_api_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -12505,7 +12505,10 @@ typedef enum {
bdp_test_option_ip,
bdp_test_option_delay,
bdp_test_option_reno,
bdp_test_option_cubic
bdp_test_option_cubic,
bdp_test_option_short,
bdp_test_option_short_lo,
bdp_test_option_short_hi,
} bdp_test_option_enum;

int bdp_option_test_one(bdp_test_option_enum bdp_test_option)
Expand Down Expand Up @@ -12545,7 +12548,29 @@ int bdp_option_test_one(bdp_test_option_enum bdp_test_option)
test_ctx->c_to_s_link->picosec_per_byte = (1000000ull * 8) / 20;
test_ctx->s_to_c_link->picosec_per_byte = (1000000ull * 8) / 20;

if (i > 0) {
if (bdp_test_option == bdp_test_option_short ||
bdp_test_option == bdp_test_option_short_lo ||
bdp_test_option == bdp_test_option_short_hi) {
/* Test that the BDP option also works well if delay < 250 ms */
max_completion_time = 4500000;
test_ctx->c_to_s_link->microsec_latency = 100000ull;
test_ctx->s_to_c_link->microsec_latency = 100000ull;
buffer_size = 2 * test_ctx->c_to_s_link->microsec_latency;
if (i == 0) {
if (bdp_test_option == bdp_test_option_short_lo) {
test_ctx->c_to_s_link->picosec_per_byte *= 2;
test_ctx->s_to_c_link->picosec_per_byte *= 2;
}
else if (bdp_test_option == bdp_test_option_short_hi) {
test_ctx->c_to_s_link->picosec_per_byte /= 2;
test_ctx->s_to_c_link->picosec_per_byte /= 2;
}
}
else if (i == 1 && bdp_test_option == bdp_test_option_short_lo) {
max_completion_time = 4650000;
}
}
else if (i > 0) {
switch (bdp_test_option) {
case bdp_test_option_none:
break;
Expand Down Expand Up @@ -12637,6 +12662,9 @@ int bdp_option_test_one(bdp_test_option_enum bdp_test_option)
}
else if (bdp_test_option == bdp_test_option_basic ||
bdp_test_option == bdp_test_option_reno ||
bdp_test_option == bdp_test_option_short ||
bdp_test_option == bdp_test_option_short_hi ||
bdp_test_option == bdp_test_option_short_lo ||
bdp_test_option == bdp_test_option_cubic) {
if (!test_ctx->cnx_server->cwin_notified_from_seed) {
DBG_PRINTF("BDP RTT test (bdp test: %d), cnx %d, cwin not seed on server.\n",
Expand Down Expand Up @@ -12712,6 +12740,21 @@ int bdp_reno_test()
return bdp_option_test_one(bdp_test_option_reno);
}

int bdp_short_test()
{
return bdp_option_test_one(bdp_test_option_short);
}

int bdp_short_hi_test()
{
return bdp_option_test_one(bdp_test_option_short_hi);
}

int bdp_short_lo_test()
{
return bdp_option_test_one(bdp_test_option_short_lo);
}

#if defined(_WINDOWS) && !defined(_WINDOWS64)
int bdp_cubic_test()
{
Expand Down

0 comments on commit 5a24917

Please sign in to comment.