Skip to content

Commit

Permalink
segmented-object: TcpCubic ignores rtt=0
Browse files Browse the repository at this point in the history
  • Loading branch information
yoursunny committed Jul 23, 2024
1 parent e0c16c4 commit 7b17e54
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 8 deletions.
1 change: 1 addition & 0 deletions pkg/segmented-object/src/fetch/congestion-avoidance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export abstract class CongestionAvoidance extends TypedEventTarget<EventMap> {
public get cwnd() { return this.cwnd_; }

protected updateCwnd(v: number) {
assert(Number.isFinite(v));
assert(v >= 0);
this.cwnd_ = v;
this.dispatchTypedEvent("cwndupdate", new Event("cwndupdate"));
Expand Down
3 changes: 3 additions & 0 deletions pkg/segmented-object/src/fetch/rtt-estimator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ const defaultParameters: Parameters = {
/**
* RTT estimator.
* @see {@link https://datatracker.ietf.org/doc/html/rfc6298}
*
* While the algorithm is agnostic to time units, the default parameters assume milliseconds,
* following JavaScript convention.
*/
export class RttEstimator {
private params: Parameters;
Expand Down
12 changes: 7 additions & 5 deletions pkg/segmented-object/src/fetch/tcp-cubic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { CongestionAvoidance } from "./congestion-avoidance";
/**
* TCP CUBIC algorithm.
* @see {@link https://datatracker.ietf.org/doc/html/rfc8312}
*
* RTT time unit is milliseconds, following JavaScript convention.
*/
export class TcpCubic extends CongestionAvoidance {
private readonly c: number;
Expand All @@ -26,8 +28,9 @@ export class TcpCubic extends CongestionAvoidance {
}

public override increase(now: number, rtt: number) {
if (now < this.t0) {
// increase and decrease processed out-of-order, t would be negative
if (now < this.t0 || rtt < 0.001) {
// increase and decrease processed out-of-order, t would be negative, ignore
// rtt is less than 1us, probably due to performance.now() inaccuracy, ignore
return;
}

Expand All @@ -37,9 +40,8 @@ export class TcpCubic extends CongestionAvoidance {
return;
}

const t = (now - this.t0) / 1000;
rtt /= 1000;
const wCubic = this.c * (t - this.k) ** 3 + this.wMax;
const t = now - this.t0; // milliseconds
const wCubic = this.c * (t / 1000 - this.k) ** 3 + this.wMax;
const wEst = this.wMax * this.betaCubic + this.alphaAimd * (t / rtt);
if (wCubic < wEst) { // TCP friendly region
this.updateCwnd(wEst);
Expand Down
20 changes: 17 additions & 3 deletions pkg/segmented-object/tests/fetch-algo.t.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
import { expect, test } from "vitest";
import { expect, test, vi } from "vitest";

import { TcpCubic } from "..";

test("TcpCubic", () => {
const ca = new TcpCubic();
let now = 1624060800000;

const cwndupdate = vi.fn<(evt: Event) => void>();
ca.addEventListener("cwndupdate", cwndupdate);

// slow start
for (let i = 0; i < 98; ++i) {
ca.increase(now, 100);
ca.increase(now, 99.5 + Math.random());
now += 5;
}
expect(ca.cwnd).toBeCloseTo(100);

// ignore rtt=0 sample
ca.increase(now, 0);
now += 5;

// enter congestion avoidance
ca.decrease(now);
expect(ca.cwnd).toBeCloseTo(70);
now += 5;

// ignore rtt=0 sample
ca.increase(now, 0);
now += 5;

// increase window
const firstCwnd = ca.cwnd;
let lastCwnd = firstCwnd;
for (let i = 0; i < 1000; ++i) {
ca.increase(now, 100);
ca.increase(now, 99.5 + Math.random());
const thisCwnd = ca.cwnd;
expect(thisCwnd).toBeGreaterThanOrEqual(lastCwnd);
lastCwnd = thisCwnd;
Expand All @@ -33,4 +44,7 @@ test("TcpCubic", () => {
// decrease window
ca.decrease(now);
expect(ca.cwnd).toBeLessThan(lastCwnd);

// rtt=0 samples should not trigger cwndupdate
expect(cwndupdate).toHaveBeenCalledTimes(98 + 1 + 1000 + 1);
});

0 comments on commit 7b17e54

Please sign in to comment.