bbr: исправить передачу потерь в BBR + пол для cwnd на уровне BBR_CWND_MIN_TARGET*mss
- etcp.c: rs->lost из link->bbr_loss_since_ack (был хардкод 0), вызов bbr_note_loss при ретрансмите - etcp_connections.h: поле bbr_loss_since_ack для per-link учёта потерь в байтах - etcp_bbr.c: везде где BBR_CWND_MIN_TARGET — умножить на mss (юнит-мизматч пакеты/байты) - bbr_quantization_budget, bbr_set_cwnd, bbr_bound_cwnd_for_inflight_model, bbr_probe_rtt_cwnd - bbr_init_lower_bounds: инициализация inflight_hi из cwnd (был ~0U навсегда) - control_server.c + etcpmon: экспорт BBR-метрик (bw_hi/lo, inflight_hi/lo, режим, потери) - tests/bbr_integration: интеграционный тест BBR (15с, 50ms/5%loss/1Mbit) с таблицей метрик - устранён death spiral BBR при высоких потерях: cwnd теперь не падает ниже 4*mss
This commit is contained in:
1 parent
6c79939db3
commit
4f0baa37db
13 files changed
+615
-78
No files matched your search
@@ -864,53 +864,23 @@ void etcpmon_client_add_to_history(struct etcpmon_client* client, struct etcpmon
|
||||
|
||||
struct metrics_history* h = &client->history;
|
||||
int idx = h->head;
|
||||
// for (int m = 0; m < GRAPH_METRICS_COUNT; m++) {
|
||||
// float v = h->values[m][idx];
|
||||
// if (v < h->min_val[m]) h->min_val[m] = v;
|
||||
// if (v > h->max_val[m]) h->max_val[m] = v;
|
||||
// }
|
||||
|
||||
if (client->log_file) {
|
||||
fprintf(client->log_file, "add_to_history: rtt_last=%u rtt_avg10=%u rtt_avg100=%u jitter=%u\n",
|
||||
metrics->etcp.rtt_last, metrics->etcp.rtt_avg_10, metrics->etcp.rtt_avg_100, metrics->etcp.jitter);
|
||||
fflush(client->log_file);
|
||||
/* BBR per-link metrics (use first link as representative) */
|
||||
if (client->last_links_count > 0 && client->last_links) {
|
||||
struct etcpmon_link_metrics* l = &client->last_links[0];
|
||||
h->values[GRAPH_METRIC_INFLIGHT_BYTES][idx] = l->inflight_bytes / 1024.f;
|
||||
h->values[GRAPH_METRIC_INFLIGHT_LIM][idx] = l->inflight_lim_bytes / 1024.f;
|
||||
h->values[GRAPH_METRIC_MIN_RTT][idx] = l->bbr_min_rtt_us / 1000.f;
|
||||
h->values[GRAPH_METRIC_BW_HI][idx] = l->bbr_bw_hi / 125.f;
|
||||
h->values[GRAPH_METRIC_PACING_RATE][idx] = l->bbr_pacing_rate / 125.f;
|
||||
h->values[GRAPH_METRIC_BW_LO][idx] = l->bbr_bw_lo / 125.f;
|
||||
h->values[GRAPH_METRIC_INFLIGHT_HI][idx] = l->bbr_inflight_hi / 1024.f;
|
||||
h->values[GRAPH_METRIC_BBR_MODE][idx] = (float)l->bbr_mode;
|
||||
}
|
||||
|
||||
float scale = 0.1f; // to ms (protocol: 0.1ms units)
|
||||
h->values[GRAPH_METRIC_RTT_LAST][idx] = (float)metrics->etcp.rtt_last * scale;
|
||||
h->values[GRAPH_METRIC_RTT_AVG10][idx] = (float)metrics->etcp.rtt_avg_10 * scale;
|
||||
h->values[GRAPH_METRIC_RTT_AVG100][idx] = (float)metrics->etcp.rtt_avg_100 * scale;
|
||||
h->values[GRAPH_METRIC_JITTER][idx] = (float)metrics->etcp.jitter * scale;
|
||||
|
||||
uint32_t retrans_delta = 0;
|
||||
uint32_t acks_delta = 0;
|
||||
uint64_t bytes_delta = 0;
|
||||
|
||||
if (h->count > 0) {
|
||||
if (metrics->etcp.retrans_count >= h->last_retrans) {
|
||||
retrans_delta = metrics->etcp.retrans_count - h->last_retrans;
|
||||
}
|
||||
if (metrics->etcp.ack_count >= h->last_acks) {
|
||||
acks_delta = metrics->etcp.ack_count - h->last_acks;
|
||||
}
|
||||
if (metrics->etcp.bytes_sent_total >= h->last_bytes_sent) {
|
||||
bytes_delta = metrics->etcp.bytes_sent_total - h->last_bytes_sent;
|
||||
}
|
||||
}
|
||||
|
||||
h->last_retrans = metrics->etcp.retrans_count;
|
||||
h->last_acks = metrics->etcp.ack_count;
|
||||
h->last_bytes_sent = metrics->etcp.bytes_sent_total;
|
||||
|
||||
h->values[GRAPH_METRIC_RETRANS][idx] = (float)retrans_delta;
|
||||
h->values[GRAPH_METRIC_ACKS][idx] = (float)acks_delta;
|
||||
h->values[GRAPH_METRIC_INFLIGHT][idx] = (float)metrics->etcp.unacked_bytes;
|
||||
h->values[GRAPH_METRIC_BYTES_SENT][idx] = (float)bytes_delta;
|
||||
|
||||
h->head = (h->head + 1) % GRAPH_HISTORY_SIZE;
|
||||
if (h->count < GRAPH_HISTORY_SIZE) {
|
||||
h->count++;
|
||||
}
|
||||
if (h->count < GRAPH_HISTORY_SIZE) h->count++;
|
||||
}
|
||||
|
||||
if (client->log_file) {
|
||||
fprintf(client->log_file, "history updated: count=%d head=%d\n", h->count, h->head);
|
||||
|
||||
@@ -21,14 +21,14 @@ extern "C" {
|
||||
|
||||
/* Graph metrics types */
|
||||
typedef enum {
|
||||
GRAPH_METRIC_RTT_LAST = 0,
|
||||
GRAPH_METRIC_RTT_AVG10,
|
||||
GRAPH_METRIC_RTT_AVG100,
|
||||
GRAPH_METRIC_JITTER,
|
||||
GRAPH_METRIC_RETRANS,
|
||||
GRAPH_METRIC_ACKS,
|
||||
GRAPH_METRIC_INFLIGHT,
|
||||
GRAPH_METRIC_BYTES_SENT,
|
||||
GRAPH_METRIC_INFLIGHT_BYTES = 0,
|
||||
GRAPH_METRIC_INFLIGHT_LIM,
|
||||
GRAPH_METRIC_MIN_RTT,
|
||||
GRAPH_METRIC_BW_HI,
|
||||
GRAPH_METRIC_PACING_RATE,
|
||||
GRAPH_METRIC_BW_LO,
|
||||
GRAPH_METRIC_INFLIGHT_HI,
|
||||
GRAPH_METRIC_BBR_MODE,
|
||||
GRAPH_METRIC_COUNT
|
||||
} graph_metric_type_t;
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
#include <stdio.h>
|
||||
#include "etcpmon_gui.h"
|
||||
const COLORREF graph_colors[GRAPH_METRICS_COUNT] = {
|
||||
RGB(255,0,0), RGB(0,255,0), RGB(0,0,255), RGB(255,255,0),
|
||||
RGB(255,0,255), RGB(0,255,255), RGB(255,128,0), RGB(128,0,255)
|
||||
RGB(255,0,0), RGB(0,200,0), RGB(0,128,255), RGB(255,128,0),
|
||||
RGB(160,0,200), RGB(0,180,180), RGB(255,0,128), RGB(200,200,0)
|
||||
};
|
||||
const char* graph_metric_names[GRAPH_METRICS_COUNT] = {
|
||||
"RTT Last","RTT Avg10","RTT Avg100","Jitter",
|
||||
"Retrns","ACKs","Inflght","Bytes/s"
|
||||
"InflB","Cwnd","minRTT","bwHi",
|
||||
"Pace","bwLo","infHi","Mode"
|
||||
};
|
||||
static void RecalculateMinMax(struct metrics_history* hist, int vis, int oldest)
|
||||
{
|
||||
@@ -165,17 +165,21 @@ void UpdateChannelValues(struct etcpmon_app* app, int history_idx)
|
||||
if (!app->hChannelValue[i]) continue;
|
||||
float val = h->values[i][history_idx];
|
||||
char buf[32] = {0};
|
||||
if (i == GRAPH_METRIC_BYTES_SENT) {
|
||||
if (val >= 1024*1024) snprintf(buf, sizeof(buf), "%.1f MB/s", val/(1024.*1024.));
|
||||
else if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f KB/s", val/1024.);
|
||||
else snprintf(buf, sizeof(buf), "%.0f B/s", val);
|
||||
} else if (i == GRAPH_METRIC_INFLIGHT) {
|
||||
if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f KB", val/1024.);
|
||||
else snprintf(buf, sizeof(buf), "%.0f B", val);
|
||||
} else if (i == GRAPH_METRIC_RETRANS || i == GRAPH_METRIC_ACKS) {
|
||||
snprintf(buf, sizeof(buf), "%.0f /s", val);
|
||||
} else {
|
||||
if (i == GRAPH_METRIC_BW_HI || i == GRAPH_METRIC_BW_LO || i == GRAPH_METRIC_PACING_RATE) {
|
||||
if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f MB/s", val/1024.);
|
||||
else snprintf(buf, sizeof(buf), "%.1f KB/s", val);
|
||||
} else if (i == GRAPH_METRIC_INFLIGHT_BYTES || i == GRAPH_METRIC_INFLIGHT_LIM || i == GRAPH_METRIC_INFLIGHT_HI) {
|
||||
if (val >= 1024*1024) snprintf(buf, sizeof(buf), "%.1f MB", val/(1024.*1024.));
|
||||
else if (val >= 1024) snprintf(buf, sizeof(buf), "%.1f KB", val/1024.);
|
||||
else snprintf(buf, sizeof(buf), "%.0f B", val);
|
||||
} else if (i == GRAPH_METRIC_MIN_RTT) {
|
||||
snprintf(buf, sizeof(buf), "%.1f ms", val);
|
||||
} else if (i == GRAPH_METRIC_BBR_MODE) {
|
||||
static const char* mnames[] = {"STARTUP","DRAIN","PROBE_BW","PROBE_RTT"};
|
||||
int m = (int)val; if (m < 0) m = 0; if (m > 3) m = 3;
|
||||
snprintf(buf, sizeof(buf), "%s", mnames[m]);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "%.1f", val);
|
||||
}
|
||||
if (strcmp(buf, last_text[i]) == 0)
|
||||
continue;
|
||||
|
||||
@@ -239,8 +239,8 @@ static void CreateControls(struct etcpmon_app* app) {
|
||||
y += GRAPH_HEIGHT + 8;
|
||||
|
||||
const char* channel_short_names[] = {
|
||||
"RTT-L", "RTT10", "RTT100", "Jitter",
|
||||
"Retrns", "ACKs", "Inflght", "Bytes/s"
|
||||
"InflB", "Cwnd", "minRTT", "bwHi",
|
||||
"Pace", "bwLo", "infHi", "Mode"
|
||||
};
|
||||
|
||||
int block_w = 200;
|
||||
@@ -1436,8 +1436,27 @@ void etcpmon_gui_update_metrics(struct etcpmon_app* app,
|
||||
links[i].inflight_lim_bytes,
|
||||
links[i].inflight_packets);
|
||||
|
||||
char line3[320];
|
||||
const char* mode_names[] = {"STARTUP","DRAIN","PROBE_BW","PROBE_RTT"};
|
||||
const char* cycle_names[] = {"UP","DOWN","CRUISE","REFILL"};
|
||||
snprintf(line3, sizeof(line3),
|
||||
" BBR: mode=%s cycle=%s full_bw=%s loss=%s pace=%.1f KB/s rtt=%u us "
|
||||
"bwHi=%.1f KB/s bwLo=%.1f KB/s infHi=%u lo=%u gain=%.2f",
|
||||
mode_names[links[i].bbr_mode > 3 ? 0 : links[i].bbr_mode],
|
||||
cycle_names[links[i].bbr_cycle_idx > 3 ? 0 : links[i].bbr_cycle_idx],
|
||||
links[i].bbr_full_bw_reached ? "yes" : "no",
|
||||
links[i].bbr_loss_in_round ? "yes" : "no",
|
||||
(float)links[i].bbr_pacing_rate / 125.0f,
|
||||
links[i].bbr_min_rtt_us,
|
||||
(float)links[i].bbr_bw_hi / 125.0f,
|
||||
(float)links[i].bbr_bw_lo / 125.0f,
|
||||
links[i].bbr_inflight_hi,
|
||||
links[i].bbr_inflight_lo,
|
||||
(float)links[i].bbr_pacing_gain / 256.0f);
|
||||
|
||||
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)line1);
|
||||
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)line2);
|
||||
SendMessageA(app->hListLinks, LB_ADDSTRING, 0, (LPARAM)line3);
|
||||
}
|
||||
InvalidateRect(app->hListLinks, NULL, FALSE);
|
||||
}
|
||||
|
||||
@@ -237,6 +237,20 @@ struct etcpmon_link_metrics {
|
||||
uint32_t inflight_bytes;
|
||||
uint32_t inflight_packets;
|
||||
uint32_t inflight_lim_bytes;
|
||||
|
||||
/* BBR congestion control metrics */
|
||||
uint8_t bbr_mode; /* 0=STARTUP, 1=DRAIN, 2=PROBE_BW, 3=PROBE_RTT */
|
||||
uint8_t bbr_cycle_idx; /* 0=UP, 1=DOWN, 2=CRUISE, 3=REFILL */
|
||||
uint8_t bbr_full_bw_reached; /* startup completed? 0/1 */
|
||||
uint8_t bbr_loss_in_round; /* loss in current round? 0/1 */
|
||||
uint32_t bbr_pacing_rate; /* bytes/sec */
|
||||
uint32_t bbr_min_rtt_us; /* min RTT (microseconds) */
|
||||
uint32_t bbr_bw_hi; /* max bandwidth estimate (bytes/sec, converted from BW_UNIT scale) */
|
||||
uint32_t bbr_bw_lo; /* conservative bandwidth estimate (bytes/sec) */
|
||||
uint32_t bbr_inflight_hi; /* upper inflight bound (bytes) */
|
||||
uint32_t bbr_inflight_lo; /* lower inflight bound (bytes) */
|
||||
uint16_t bbr_pacing_gain; /* pacing gain (BBR_UNIT fixed-point: 710=2.77x, 192=0.75x) */
|
||||
uint16_t pad_bbr; /* padding for 4-byte alignment */
|
||||
};
|
||||
|
||||
/* TUN interface metrics */
|
||||
|
||||
Reference in new issue
Block a user