From 2c10272e15ccbcf7cb3dc1d442f3320106d68465 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 21 Oct 2026 22:55:24 +0200 Subject: [PATCH] Add repeatable NAT benchmarks for table size, payload size and full-pool misses --- tests/test_nat_stress.c | 69 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/tests/test_nat_stress.c b/tests/test_nat_stress.c index 08c1ead1..ae8fe696 100644 --- a/tests/test_nat_stress.c +++ b/tests/test_nat_stress.c @@ -10,6 +10,8 @@ #include #include #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();