Browse Source

Add aligned router delivery metering for video adaptation

master
evgeny 4 days ago
parent
commit
61faca84d7
  1. 45
      src/routing_layer/route_tx_stats.c
  2. 25
      src/routing_layer/route_tx_stats.h

45
src/routing_layer/route_tx_stats.c

@ -0,0 +1,45 @@
#include "route_tx_stats.h"
#include "../../lib/debug_config.h"
#include <string.h>
/* Эпоха принадлежит каналу; освобождение неподтверждённых пакетов не вызывает ack. */
void route_tx_meter_reset(struct route_tx_meter *meter, uint64_t now_us) {
if (!meter) { DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "TX meter reset without state"); return; }
memset(meter, 0, sizeof(*meter));
meter->started_us = meter->last_us = now_us;
}
/* Сохраняем реальные моменты ACK, независимо от задержки таймера потребителя статистики. */
int route_tx_meter_ack(struct route_tx_meter *meter, uint64_t now_us, uint64_t bytes) {
if (!meter || !bytes || now_us < meter->last_us || bytes > UINT64_MAX - meter->bytes || meter->packets == UINT64_MAX) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "TX meter invalid ACK time=%llu bytes=%llu",
(unsigned long long)now_us, (unsigned long long)bytes);
return -1;
}
uint64_t tick = now_us / ROUTE_TX_SAMPLE_US;
struct route_tx_bucket *bucket = &meter->buckets[tick % ROUTE_TX_BUCKETS];
if (bucket->tick_plus_one != tick + 1) *bucket = (struct route_tx_bucket){.tick_plus_one = tick + 1};
bucket->bytes += bytes; bucket->packets++;
meter->bytes += bytes; meter->packets++; meter->last_us = now_us;
return 0;
}
/* Сумма только завершённых ячеек: idle интервалы остаются нулевыми. */
int route_tx_meter_window(const struct route_tx_meter *meter, uint64_t now_us, struct route_tx_window *out) {
if (!meter || !out || now_us < meter->last_us) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCPROUTE, "TX meter invalid snapshot time=%llu", (unsigned long long)now_us);
return -1;
}
uint64_t end = now_us / ROUTE_TX_SAMPLE_US;
struct route_tx_window result = {.end_us = end * ROUTE_TX_SAMPLE_US};
result.valid = result.end_us >= meter->started_us && result.end_us - meter->started_us >= ROUTE_TX_WINDOW_US;
for (unsigned i = 0; i < ROUTE_TX_BUCKETS; i++) {
const struct route_tx_bucket *bucket = &meter->buckets[i];
if (!bucket->tick_plus_one) continue;
uint64_t tick = bucket->tick_plus_one - 1;
if (tick >= end || end - tick > 10) continue;
result.bytes += bucket->bytes; result.packets += bucket->packets;
}
*out = result;
return 0;
}

25
src/routing_layer/route_tx_stats.h

@ -0,0 +1,25 @@
/* Учёт первой доставки payload логического канала. Один uasync-поток.
* Десять завершённых интервалов по 50мс и текущий интервал; reset начинает новую историю.
* Повторы учитывает вызывающий: add вызывается только при снятии подтверждённого inflight. */
#ifndef ROUTE_TX_STATS_H
#define ROUTE_TX_STATS_H
#include <stdint.h>
#define ROUTE_TX_SAMPLE_US 50000u
#define ROUTE_TX_WINDOW_US 500000u
#define ROUTE_TX_BUCKETS 11
struct route_tx_bucket { uint64_t tick_plus_one, bytes, packets; };
struct route_tx_meter {
struct route_tx_bucket buckets[ROUTE_TX_BUCKETS];
uint64_t started_us, last_us, bytes, packets;
};
struct route_tx_window { uint64_t end_us, bytes, packets; int valid; };
void route_tx_meter_reset(struct route_tx_meter *meter, uint64_t now_us);
int route_tx_meter_ack(struct route_tx_meter *meter, uint64_t now_us, uint64_t bytes);
/* Неполное окно после reset возвращает valid=0; текущая незавершённая ячейка исключается. */
int route_tx_meter_window(const struct route_tx_meter *meter, uint64_t now_us, struct route_tx_window *out);
#endif
Loading…
Cancel
Save