Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/cc/cc_cubic.c
Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | struct cubic { | ||||
/* Cubic K in fixed point form with CUBIC_SHIFT worth of precision. */ | /* Cubic K in fixed point form with CUBIC_SHIFT worth of precision. */ | ||||
int64_t K; | int64_t K; | ||||
/* Sum of RTT samples across an epoch in ticks. */ | /* Sum of RTT samples across an epoch in ticks. */ | ||||
int64_t sum_rtt_ticks; | int64_t sum_rtt_ticks; | ||||
/* cwnd at the most recent congestion event. */ | /* cwnd at the most recent congestion event. */ | ||||
unsigned long max_cwnd; | unsigned long max_cwnd; | ||||
/* cwnd at the previous congestion event. */ | /* cwnd at the previous congestion event. */ | ||||
unsigned long prev_max_cwnd; | unsigned long prev_max_cwnd; | ||||
/* Number of congestion events. */ | /* various flags */ | ||||
uint32_t num_cong_events; | uint32_t flags; | ||||
#define CUBICFLAG_cong_event 0x01 /* congestion expirienced */ | |||||
tuexen: Please use all CAPS in constant name. Fix typo in comment: experienced.
Maybe use 0x00000001… | |||||
#define CUBICFLAG_in_slowstart 0x02 /* in slow start */ | |||||
Done Inline ActionsPlease use all CAPS. tuexen: Please use all CAPS. | |||||
/* Minimum observed rtt in ticks. */ | /* Minimum observed rtt in ticks. */ | ||||
int min_rtt_ticks; | int min_rtt_ticks; | ||||
/* Mean observed rtt between congestion epochs. */ | /* Mean observed rtt between congestion epochs. */ | ||||
int mean_rtt_ticks; | int mean_rtt_ticks; | ||||
/* ACKs since last congestion event. */ | /* ACKs since last congestion event. */ | ||||
int epoch_ack_count; | int epoch_ack_count; | ||||
/* Time of last congestion event in ticks. */ | /* Time of last congestion event in ticks. */ | ||||
int t_last_cong; | int t_last_cong; | ||||
Show All 30 Lines | cubic_ack_received(struct cc_var *ccv, uint16_t type) | ||||
* doing ABC and we've sent a cwnd's worth of bytes. | * doing ABC and we've sent a cwnd's worth of bytes. | ||||
*/ | */ | ||||
if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | if (type == CC_ACK && !IN_RECOVERY(CCV(ccv, t_flags)) && | ||||
(ccv->flags & CCF_CWND_LIMITED) && (!V_tcp_do_rfc3465 || | (ccv->flags & CCF_CWND_LIMITED) && (!V_tcp_do_rfc3465 || | ||||
CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | ||||
(V_tcp_do_rfc3465 && ccv->flags & CCF_ABC_SENTAWND))) { | (V_tcp_do_rfc3465 && ccv->flags & CCF_ABC_SENTAWND))) { | ||||
/* Use the logic in NewReno ack_received() for slow start. */ | /* Use the logic in NewReno ack_received() for slow start. */ | ||||
if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | ||||
cubic_data->min_rtt_ticks == TCPTV_SRTTBASE) | cubic_data->min_rtt_ticks == TCPTV_SRTTBASE) { | ||||
if (!(cubic_data->flags & CUBICFLAG_in_slowstart)) | |||||
cubic_data->flags |= CUBICFLAG_in_slowstart; | |||||
Not Done Inline ActionsMaybe just setting the flag? tuexen: Maybe just setting the flag? | |||||
Done Inline ActionsAn unconditional assignment of a single bit will always be a read access, followed by a write access (and associated cache line updates), whereas the intent of the conditional was to make this mostly just a read-access, with the write rarely happening... A single (constant) write access by itself wouldn't account for much, but I'm still trying to prevent too many memory accesses... rscheff: An unconditional assignment of a single bit will always be a read access, followed by a write… | |||||
newreno_cc_algo.ack_received(ccv, type); | newreno_cc_algo.ack_received(ccv, type); | ||||
else { | } else { | ||||
if ((ticks_since_cong = | if ((ticks_since_cong = | ||||
ticks - cubic_data->t_last_cong) < 0) { | ticks - cubic_data->t_last_cong) < 0) { | ||||
/* | /* | ||||
* dragging t_last_cong along | * dragging t_last_cong along | ||||
*/ | */ | ||||
ticks_since_cong = INT_MAX; | ticks_since_cong = INT_MAX; | ||||
cubic_data->t_last_cong = ticks - INT_MAX; | cubic_data->t_last_cong = ticks - INT_MAX; | ||||
} | } | ||||
if (cubic_data->flags & CUBICFLAG_in_slowstart) { | |||||
cubic_data->flags &= ~CUBICFLAG_in_slowstart; | |||||
cubic_data->t_last_cong = ticks; | |||||
cubic_data->K = 0; | |||||
} | |||||
/* | /* | ||||
* The mean RTT is used to best reflect the equations in | * The mean RTT is used to best reflect the equations in | ||||
* the I-D. Using min_rtt in the tf_cwnd calculation | * the I-D. Using min_rtt in the tf_cwnd calculation | ||||
* causes w_tf to grow much faster than it should if the | * causes w_tf to grow much faster than it should if the | ||||
* RTT is dominated by network buffering rather than | * RTT is dominated by network buffering rather than | ||||
* propagation delay. | * propagation delay. | ||||
*/ | */ | ||||
w_tf = tf_cwnd(ticks_since_cong, | w_tf = tf_cwnd(ticks_since_cong, | ||||
Show All 33 Lines | if (CCV(ccv, snd_cwnd) <= CCV(ccv, snd_ssthresh) || | ||||
/* | /* | ||||
* If we're not in slow start and we're probing for a | * If we're not in slow start and we're probing for a | ||||
* new cwnd limit at the start of a connection | * new cwnd limit at the start of a connection | ||||
* (happens when hostcache has a relevant entry), | * (happens when hostcache has a relevant entry), | ||||
* keep updating our current estimate of the | * keep updating our current estimate of the | ||||
* max_cwnd. | * max_cwnd. | ||||
*/ | */ | ||||
if (cubic_data->num_cong_events == 0 && | if (((cubic_data->flags & CUBICFLAG_cong_event) == 0) && | ||||
cubic_data->max_cwnd < CCV(ccv, snd_cwnd)) { | cubic_data->max_cwnd < CCV(ccv, snd_cwnd)) { | ||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
cubic_data->K = cubic_k(cubic_data->max_cwnd / | cubic_data->K = cubic_k(cubic_data->max_cwnd / | ||||
CCV(ccv, t_maxseg)); | CCV(ccv, t_maxseg)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | cubic_cong_signal(struct cc_var *ccv, uint32_t type) | ||||
cubic_data = ccv->cc_data; | cubic_data = ccv->cc_data; | ||||
switch (type) { | switch (type) { | ||||
case CC_NDUPACK: | case CC_NDUPACK: | ||||
if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | if (!IN_FASTRECOVERY(CCV(ccv, t_flags))) { | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | ||||
cubic_ssthresh_update(ccv); | cubic_ssthresh_update(ccv); | ||||
cubic_data->num_cong_events++; | cubic_data->flags |= CUBICFLAG_cong_event; | ||||
cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | ||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
cubic_data->K = cubic_k(cubic_data->max_cwnd / CCV(ccv, t_maxseg)); | |||||
} | } | ||||
ENTER_RECOVERY(CCV(ccv, t_flags)); | ENTER_RECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
case CC_ECN: | case CC_ECN: | ||||
if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | if (!IN_CONGRECOVERY(CCV(ccv, t_flags))) { | ||||
cubic_ssthresh_update(ccv); | cubic_ssthresh_update(ccv); | ||||
cubic_data->num_cong_events++; | cubic_data->flags |= CUBICFLAG_cong_event; | ||||
cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | cubic_data->prev_max_cwnd = cubic_data->max_cwnd; | ||||
cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | cubic_data->max_cwnd = CCV(ccv, snd_cwnd); | ||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
cubic_data->K = cubic_k(cubic_data->max_cwnd / CCV(ccv, t_maxseg)); | |||||
CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | CCV(ccv, snd_cwnd) = CCV(ccv, snd_ssthresh); | ||||
ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ENTER_CONGRECOVERY(CCV(ccv, t_flags)); | ||||
} | } | ||||
break; | break; | ||||
case CC_RTO: | case CC_RTO: | ||||
/* | /* | ||||
* Grab the current time and record it so we know when the | * Grab the current time and record it so we know when the | ||||
* most recent congestion event was. Only record it when the | * most recent congestion event was. Only record it when the | ||||
* timeout has fired more than once, as there is a reasonable | * timeout has fired more than once, as there is a reasonable | ||||
* chance the first one is a false alarm and may not indicate | * chance the first one is a false alarm and may not indicate | ||||
* congestion. | * congestion. | ||||
*/ | */ | ||||
if (CCV(ccv, t_rxtshift) >= 2) { | if (CCV(ccv, t_rxtshift) >= 2) { | ||||
cubic_data->num_cong_events++; | cubic_data->flags |= CUBICFLAG_cong_event; | ||||
cubic_data->t_last_cong = ticks; | cubic_data->t_last_cong = ticks; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
cubic_conn_init(struct cc_var *ccv) | cubic_conn_init(struct cc_var *ccv) | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | cubic_ssthresh_update(struct cc_var *ccv) | ||||
struct cubic *cubic_data; | struct cubic *cubic_data; | ||||
cubic_data = ccv->cc_data; | cubic_data = ccv->cc_data; | ||||
/* | /* | ||||
* On the first congestion event, set ssthresh to cwnd * 0.5, on | * On the first congestion event, set ssthresh to cwnd * 0.5, on | ||||
* subsequent congestion events, set it to cwnd * beta. | * subsequent congestion events, set it to cwnd * beta. | ||||
*/ | */ | ||||
if (cubic_data->num_cong_events == 0) | if ((cubic_data->flags & CUBICFLAG_cong_event) == 0) | ||||
CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd) >> 1; | CCV(ccv, snd_ssthresh) = CCV(ccv, snd_cwnd) >> 1; | ||||
else | else | ||||
CCV(ccv, snd_ssthresh) = ((u_long)CCV(ccv, snd_cwnd) * | CCV(ccv, snd_ssthresh) = ((u_long)CCV(ccv, snd_cwnd) * | ||||
CUBIC_BETA) >> CUBIC_SHIFT; | CUBIC_BETA) >> CUBIC_SHIFT; | ||||
} | } | ||||
DECLARE_CC_MODULE(cubic, &cubic_cc_algo); | DECLARE_CC_MODULE(cubic, &cubic_cc_algo); |
Please use all CAPS in constant name. Fix typo in comment: experienced.
Maybe use 0x00000001, since you use it for 32 bits. Now needed right now, but if you add (in the future) a constant which needs more than 2 digits, you will change the existing constants by adding leading zeros...