/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ /* * This is not really a test: this program prints out cwnd histogram * for visual inspection. */ #include #include #include #ifndef WIN32 #include #include #include #else #include #endif #include "lsquic_types.h" #include "lsquic_int_types.h" #include "lsquic_cong_ctl.h" #include "lsquic_packet_common.h" #include "lsquic_packet_out.h" #include "lsquic_cubic.h" static const struct cong_ctl_if *const cci = &lsquic_cong_cubic_if; #define MS(n) ((n) * 1000) /* MS: Milliseconds */ enum event { EV_ACK, EV_LOSS, EV_TIMEOUT, }; static const char *const evstr[] = { [EV_ACK] = "ACK", [EV_LOSS] = "LOSS", [EV_TIMEOUT] = "TIMEOUT", }; struct rec { enum event event; unsigned cwnd; }; #define REC(ev) do { \ if (i >= n_recs_alloc) \ { \ if (n_recs_alloc) \ n_recs_alloc *= 2; \ else \ n_recs_alloc = 20; \ recs = realloc(recs, n_recs_alloc * \ sizeof(recs[0])); \ } \ recs[i].event = ev; \ recs[i].cwnd = cci->cci_get_cwnd(&cubic); \ if (max_cwnd < recs[i].cwnd) \ max_cwnd = recs[i].cwnd; \ } while (0) int main (int argc, char **argv) { int i, n, opt; int n_recs_alloc = 0; int app_limited = 0; unsigned unit = 100; /* Default to 100 ms */ unsigned rtt_ms = 10; /* Default to 10 ms */ struct lsquic_cubic cubic; struct rec *recs = NULL; unsigned max_cwnd, width; char *line; #ifndef WIN32 struct winsize winsize; #endif enum cubic_flags flags; struct lsquic_packet_out packet_out; cci->cci_init(&cubic, 0, 0); max_cwnd = 0; i = 0; memset(&packet_out, 0, sizeof(packet_out)); while (-1 != (opt = getopt(argc, argv, "s:u:r:f:l:A:L:T:"))) { switch (opt) { case 's': cubic.cu_ssthresh = atoi(optarg); break; case 'r': rtt_ms = atoi(optarg); break; case 'f': flags = atoi(optarg); lsquic_cubic_set_flags(&cubic, flags); break; case 'l': app_limited = atoi(optarg); break; case 'A': n = i + atoi(optarg); for ( ; i < n; ++i) { packet_out.po_sent = MS(unit * i) - MS(rtt_ms); cci->cci_ack(&cubic, &packet_out, 1370, MS(unit * i), app_limited); REC(EV_ACK); } break; case 'L': n = i + atoi(optarg); for ( ; i < n; ++i) { cci->cci_loss(&cubic); REC(EV_LOSS); } break; case 'T': n = i + atoi(optarg); for ( ; i < n; ++i) { cci->cci_timeout(&cubic); REC(EV_TIMEOUT); } break; case 'u': unit = atoi(optarg); break; default: exit(1); } } #ifndef WIN32 if (isatty(STDIN_FILENO)) { if (0 == ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize)) width = winsize.ws_col; else { perror("ioctl"); width = 80; } } else #endif width = 80; width -= 5 /* cwnd */ + 1 /* space */ + 1 /* event type */ + 1 /* space */ + 1 /* newline */; line = malloc(width); memset(line, '+', width); for (n = i, i = 0; i < n; ++i) printf("%c % 5d %.*s\n", *evstr[recs[i].event], recs[i].cwnd, (int) ((float) recs[i].cwnd / max_cwnd * width), line); free(recs); free(line); return 0; }