Add repeatable NAT benchmarks for table size, payload size and full-pool misses

This commit is contained in:
evgeny committed 2026-10-21 22:55:24 +02:00
1 parent 55cc721c9b
commit 2c10272e15
1 file changed
+68 -1
+68 -1
View File
@@ -10,6 +10,8 @@
#include <stdlib.h>
#include <string.h>
#include "../lib/platform_compat.h"
#include "../lib/u_async.h"
#include "../lib/mem.h"
#include "../lib/debug_config.h"
#include "../src/eim_nat.h"
#include "etcp.h"
@@ -475,10 +477,75 @@ static void stress_large_table_init_free(void) {
PASS();
}
/* Восстановить только изменяемые NAT поля: длина payload не попадает в стоимость поиска/пересчёта заголовков. */
static void benchmark_reset(uint8_t* packet, const uint8_t* original) {
memcpy(packet + 10, original + 10, 2);
memcpy(packet + 12, original + 12, 4);
memcpy(packet + 20, original + 20, 2);
}
/* Воспроизводимый microbenchmark: подготовка и аллокации вне измерений, одинаковый build и отключённая диагностика. */
static int benchmark_nat(void) {
debug_set_category_level(DEBUG_CATEGORY_NAT, DEBUG_LEVEL_DISABLED);
const uint32_t populations[] = {1, 1000, 10000, 60000};
const size_t lengths[] = {64, 1500};
for (size_t length_index = 0; length_index < 2; length_index++) {
size_t len = lengths[length_index];
uint8_t original[1500] = {0}, packet[1500];
size_t built;
uint8_t* seed = make_udp_pkt(0x0a000002, 40000, 0x08080808, 53, &built);
if (!seed) return 1;
memcpy(original, seed, built); free(seed);
uint16_t word = htobe16(len); memcpy(original + 2, &word, 2);
word = htobe16(len - 20); memcpy(original + 24, &word, 2);
memset(original + 10, 0, 2);
uint32_t sum = 0;
for (size_t j = 0; j < 20; j += 2) { memcpy(&word, original + j, 2); sum += word; }
sum = (sum & 0xffff) + (sum >> 16); sum = (sum & 0xffff) + (sum >> 16);
word = (uint16_t)~sum; memcpy(original + 10, &word, 2);
for (size_t population_index = 0; population_index < 4; population_index++) {
uint32_t count = populations[population_index];
struct global_config g = make_config(1, count > 1 ? count : 2);
struct eim_nat_ctx ctx;
if (eim_nat_init_ctx(&ctx, &g)) return 1;
memcpy(packet, original, len);
size_t allocations = u_get_allocated_count();
uint64_t start = get_time_us();
for (uint32_t i = 0; i < count; i++) {
benchmark_reset(packet, original);
if (eim_nat_egress(&ctx, packet, len, i + 1, NULL)) { eim_nat_destroy_ctx(&ctx); return 1; }
}
uint64_t creation = get_time_us() - start;
start = get_time_us();
const uint32_t iterations = 200000;
for (uint32_t i = 0; i < iterations; i++) {
benchmark_reset(packet, original);
if (eim_nat_egress(&ctx, packet, len, (i * 2654435761u) % count + 1, NULL)) { eim_nat_destroy_ctx(&ctx); return 1; }
}
uint64_t hits = get_time_us() - start;
if (count == 1) { benchmark_reset(packet, original); eim_nat_egress(&ctx, packet, len, 2, NULL); }
start = get_time_us();
for (uint32_t i = 0; i < iterations; i++) {
benchmark_reset(packet, original);
if (eim_nat_egress(&ctx, packet, len, UINT64_MAX, NULL) != EIM_NAT_ERROR) { eim_nat_destroy_ctx(&ctx); return 1; }
}
uint64_t misses = get_time_us() - start;
int balanced = u_get_allocated_count() == allocations;
printf("BENCH bytes=%zu flows=%u create_ns=%.1f hit_ns=%.1f full_miss_ns=%.1f heap_growth=%d\n", len, count,
creation * 1000.0 / count, hits * 1000.0 / iterations, misses * 1000.0 / iterations, !balanced);
eim_nat_destroy_ctx(&ctx);
if (!balanced) return 1;
}
}
return 0;
}
// ==================== Main ====================
int main(void) {
int main(int argc, char** argv) {
debug_config_init();
debug_set_level(DEBUG_LEVEL_ERROR);
if (argc == 2 && !strcmp(argv[1], "--benchmark")) return benchmark_nat();
if (argc != 1) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "Usage: test_nat_stress [--benchmark]"); return 1; }
stress_many_sessions();
stress_table_full_and_lookup();