graph_cubic.c revision 06b2a236
1/* Copyright (c) 2017 - 2021 LiteSpeed Technologies Inc. See LICENSE. */ 2/* 3 * This is not really a test: this program prints out cwnd histogram 4 * for visual inspection. 5 */ 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#ifndef WIN32 11#include <sys/ioctl.h> 12#include <termios.h> 13#include <unistd.h> 14#else 15#include <getopt.h> 16#endif 17 18#include "lsquic_types.h" 19#include "lsquic_int_types.h" 20#include "lsquic_cong_ctl.h" 21#include "lsquic_packet_common.h" 22#include "lsquic_packet_out.h" 23#include "lsquic_cubic.h" 24 25static const struct cong_ctl_if *const cci = &lsquic_cong_cubic_if; 26 27#define MS(n) ((n) * 1000) /* MS: Milliseconds */ 28 29enum event { EV_ACK, EV_LOSS, EV_TIMEOUT, }; 30 31static const char *const evstr[] = { 32 [EV_ACK] = "ACK", 33 [EV_LOSS] = "LOSS", 34 [EV_TIMEOUT] = "TIMEOUT", 35}; 36 37struct rec 38{ 39 enum event event; 40 unsigned cwnd; 41}; 42 43#define REC(ev) do { \ 44 if (i >= n_recs_alloc) \ 45 { \ 46 if (n_recs_alloc) \ 47 n_recs_alloc *= 2; \ 48 else \ 49 n_recs_alloc = 20; \ 50 recs = realloc(recs, n_recs_alloc * \ 51 sizeof(recs[0])); \ 52 } \ 53 recs[i].event = ev; \ 54 recs[i].cwnd = cci->cci_get_cwnd(&cubic); \ 55 if (max_cwnd < recs[i].cwnd) \ 56 max_cwnd = recs[i].cwnd; \ 57} while (0) 58 59int 60main (int argc, char **argv) 61{ 62 int i, n, opt; 63 int n_recs_alloc = 0; 64 int app_limited = 0; 65 unsigned unit = 100; /* Default to 100 ms */ 66 unsigned rtt_ms = 10; /* Default to 10 ms */ 67 struct lsquic_cubic cubic; 68 struct rec *recs = NULL; 69 unsigned max_cwnd, width; 70 char *line; 71#ifndef WIN32 72 struct winsize winsize; 73#endif 74 enum cubic_flags flags; 75 struct lsquic_packet_out packet_out; 76 77 cci->cci_init(&cubic, 0, 0); 78 max_cwnd = 0; 79 i = 0; 80 memset(&packet_out, 0, sizeof(packet_out)); 81 82 while (-1 != (opt = getopt(argc, argv, "s:u:r:f:l:A:L:T:"))) 83 { 84 switch (opt) 85 { 86 case 's': 87 cubic.cu_ssthresh = atoi(optarg); 88 break; 89 case 'r': 90 rtt_ms = atoi(optarg); 91 break; 92 case 'f': 93 flags = atoi(optarg); 94 lsquic_cubic_set_flags(&cubic, flags); 95 break; 96 case 'l': 97 app_limited = atoi(optarg); 98 break; 99 case 'A': 100 n = i + atoi(optarg); 101 for ( ; i < n; ++i) 102 { 103 packet_out.po_sent = MS(unit * i) - MS(rtt_ms); 104 cci->cci_ack(&cubic, &packet_out, 1370, MS(unit * i), app_limited); 105 REC(EV_ACK); 106 } 107 break; 108 case 'L': 109 n = i + atoi(optarg); 110 for ( ; i < n; ++i) 111 { 112 cci->cci_loss(&cubic); 113 REC(EV_LOSS); 114 } 115 break; 116 case 'T': 117 n = i + atoi(optarg); 118 for ( ; i < n; ++i) 119 { 120 cci->cci_timeout(&cubic); 121 REC(EV_TIMEOUT); 122 } 123 break; 124 case 'u': 125 unit = atoi(optarg); 126 break; 127 default: 128 exit(1); 129 } 130 } 131 132#ifndef WIN32 133 if (isatty(STDIN_FILENO)) 134 { 135 if (0 == ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize)) 136 width = winsize.ws_col; 137 else 138 { 139 perror("ioctl"); 140 width = 80; 141 } 142 } 143 else 144#endif 145 width = 80; 146 147 width -= 5 /* cwnd */ + 1 /* space */ + 1 /* event type */ + 148 1 /* space */ + 1 /* newline */; 149 line = malloc(width); 150 memset(line, '+', width); 151 152 for (n = i, i = 0; i < n; ++i) 153 printf("%c % 5d %.*s\n", *evstr[recs[i].event], recs[i].cwnd, 154 (int) ((float) recs[i].cwnd / max_cwnd * width), line); 155 156 free(recs); 157 free(line); 158 159 return 0; 160} 161