From c48a7ac0cc76d2d5c1682251cd8b03a8953bd6b5 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 17 Sep 2024 15:59:07 +0200 Subject: [PATCH 01/15] BMP: drop an unused mempool --- proto/bmp/bmp.c | 1 - proto/bmp/bmp.h | 1 - 2 files changed, 2 deletions(-) diff --git a/proto/bmp/bmp.c b/proto/bmp/bmp.c index 261e9fdd..599024f5 100644 --- a/proto/bmp/bmp.c +++ b/proto/bmp/bmp.c @@ -1244,7 +1244,6 @@ bmp_start(struct proto *P) struct bmp_proto *p = (void *) P; p->buffer_mpool = rp_new(P->pool, "BMP Buffer"); - p->map_mem_pool = rp_new(P->pool, "BMP Map"); p->tx_mem_pool = rp_new(P->pool, "BMP Tx"); p->update_msg_mem_pool = rp_new(P->pool, "BMP Update"); p->tx_ev = ev_new_init(p->p.pool, bmp_fire_tx, p); diff --git a/proto/bmp/bmp.h b/proto/bmp/bmp.h index d69aaafb..45844836 100644 --- a/proto/bmp/bmp.h +++ b/proto/bmp/bmp.h @@ -65,7 +65,6 @@ struct bmp_proto { // Below fields are for internal use // struct bmp_peer_map bgp_peers; // Stores 'bgp_proto' structure per BGP peer pool *buffer_mpool; // Memory pool used for BMP buffer allocations - pool *map_mem_pool; // Memory pool used for BMP map allocations pool *tx_mem_pool; // Memory pool used for packet allocations designated to BMP collector pool *update_msg_mem_pool; // Memory pool used for BPG UPDATE MSG allocations list tx_queue; // Stores queued packets going to be sent From 460321cfe979459e3b78ba87694f29865d321612 Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Thu, 28 Nov 2024 23:08:50 +0100 Subject: [PATCH 02/15] Formatting numbers with order prefixes Unit tests by Ondrej Zajicek. --- lib/printf.c | 121 +++++++++++++++++++++++++++++++++++++++++++++- lib/printf_test.c | 63 ++++++++++++++++++++++++ lib/string.h | 4 ++ 3 files changed, 187 insertions(+), 1 deletion(-) diff --git a/lib/printf.c b/lib/printf.c index 68d3bb74..318e683c 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -8,7 +8,8 @@ */ #include "nest/bird.h" -#include "string.h" +#include "lib/macro.h" +#include "lib/string.h" #include @@ -631,3 +632,121 @@ char *lp_sprintf(linpool *p, const char *fmt, ...) va_end(args); return out; } + +static const u64 decadic_multiplier[] = { + 1, 10, 100, 1000, + 10000, 100000, 1000000, 10000000, +#if 0 + 100000000, 1000000000, 10000000000, 100000000000, + 1000000000000, 10000000000000, 100000000000000, 1000000000000000, + 10000000000000000, 100000000000000000, 1000000000000000000, +#endif +}; + +static const u64 decmul_limit[] = { + ~0ULL / 1, ~0ULL / 10, + ~0ULL / 100, ~0ULL / 1000, + ~0ULL / 10000, ~0ULL / 100000, + ~0ULL / 1000000, ~0ULL / 10000000, +#if 0 + ~0ULL / 100000000, ~0ULL / 1000000000, + ~0ULL / 10000000000, ~0ULL / 100000000000, + ~0ULL / 1000000000000, ~0ULL / 10000000000000, + ~0ULL / 100000000000000, ~0ULL / 1000000000000000, + ~0ULL / 10000000000000000, ~0ULL / 100000000000000000, + ~0ULL / 1000000000000000000, +#endif +}; + +STATIC_ASSERT(sizeof decadic_multiplier == sizeof decmul_limit); + +char *fmt_order(u64 value, uint decimals, u64 kb_threshold) +{ + bool too_big = (value + 512 < 512ULL); + + u64 mv = value; + uint magnitude = 0; + while (mv > kb_threshold) + { + magnitude++; + mv = (mv + (too_big ? 0 : 512)) / 1024; + } + + uint shift = magnitude * 10; + + /* The trivial case */ + if (magnitude == 0) + return tmp_sprintf("%lu ", value); + + /* Now we can find the suffix and the main divisor */ + ASSERT_DIE(magnitude < 7); + char suffix = " kMGTPE"[magnitude]; + + /* The value before the dot is available just by dividing */ + u64 before_dot = value >> shift; + + /* Remainder is more tricky. First we need to know it. */ + u64 remainder = value - (before_dot << shift); + + /* We would like to compute (remainder * decmul) / divisor + * in integers but it's tricky because of u64 limits. */ + ASSERT_DIE(decimals < ARRAY_SIZE(decadic_multiplier)); + u64 decmul = decadic_multiplier[decimals]; + u64 product; + + if (remainder < decmul_limit[decimals]) + { + /* The easier version: Everything fits into u64 */ + product = remainder * decmul; + product >>= shift - 1; + product++; + product >>= 1; + } + else + { + /* Harder version: We have to multiply by parts. + * Fortunately, decmul always fits into 32 bits. */ + /* After this, product = lower + (upper << 32). */ + u64 lower = (remainder & ((1ULL << 32) - 1)) * decmul; + u64 upper = (remainder >> 32) * decmul; + + if (shift < 33) + { + /* Divide lower */ + lower >>= shift - 1; + + /* Add the full upper part, not shifted enough to lose any bits */ + lower += upper << (33 - shift); + } + else + { + /* First move the shifted-out bits from upper to lower */ + lower += (upper & ((1ULL << (shift - 32)) - 1)) << 32; + + /* Then we can divide */ + lower >>= shift - 1; + + /* And add the shifted upper part */ + lower += upper >> (shift - 33); + } + + /* Now we finish the division by rounding */ + product = (lower + 1) >> 1; + } + + if (product == decmul) + { + product = 0; + before_dot++; + } + + ASSERT_DIE(product < decmul); + + /* And now we finally have all the numbers to print! */ + if (decimals) + return tmp_sprintf("%lu.%0*lu %c", + before_dot, decimals, product, suffix + ); + else + return tmp_sprintf("%lu %c", before_dot, suffix); +} diff --git a/lib/printf_test.c b/lib/printf_test.c index 996f34ae..b3d4d560 100644 --- a/lib/printf_test.c +++ b/lib/printf_test.c @@ -117,6 +117,68 @@ t_bstrcmp(void) return 1; } +static int +t_fmt_order(void) +{ + struct fmt_order_tv { + u64 value; + int decimals; + u64 threshold; + const char *expect; + } test_vectors [] = { + { 9999, 1, 10000, "9999 " }, + { 10001, 1, 10000, "9.8 k" }, + { 10001, 2, 10000, "9.77 k" }, + { 10001, 3, 10000, "9.767 k" }, + { 1048575, 0, 10000, "1024 k" }, + { 1048575, 1, 10000, "1024.0 k" }, + { 1048575, 2, 10000, "1024.00 k" }, + { 1048575, 3, 10000, "1023.999 k" }, + { 1048575, 4, 10000, "1023.9990 k" }, + { 1048575, 5, 10000, "1023.99902 k" }, + { 1048575, 6, 10000, "1023.999023 k" }, + { 1048575, 0, 1000, "1 M" }, + { 1048575, 1, 1000, "1.0 M" }, + { 1048575, 2, 1000, "1.00 M" }, + { 1048575, 3, 1000, "1.000 M" }, + { 1048575, 4, 1000, "1.0000 M" }, + { 1048575, 5, 1000, "1.00000 M" }, + { 1048575, 6, 1000, "0.999999 M" }, + { 1048577, 6, 10000, "1024.000977 k" }, + { 1048577, 6, 1000, "1.000001 M" }, + { 1048577, 6, 100, "1.000001 M" }, + { 1048577, 6, 10, "1.000001 M" }, + { 1048577, 6, 1, "1.000001 M" }, + { 10000000000000, 6, 10000, "9313.225746 G" }, + { 10000000000000, 6, 1000, "9.094947 T" }, + { 123456789123456789, 0, 1000, "110 P" }, + { 123456789123456789, 4, 1000, "109.6517 P" }, + { 123456789123456789, 7, 1000, "109.6516559 P" }, + { 1234567890123456789, 0, 1000, "1 E" }, + { 1234567890123456789, 1, 1000, "1.1 E" }, + { 1234567890123456789, 2, 1000, "1.07 E" }, + { 1234567890123456789, 3, 1000, "1.071 E" }, + { 1234567890123456789, 4, 1000, "1.0708 E" }, + { 1234567890123456789, 5, 1000, "1.07082 E" }, + { 1234567890123456789, 6, 1000, "1.070817 E" }, + { 1234567890123456789, 7, 1000, "1.0708170 E" }, + { 9444732965739290427U, 3, 1000, "8.192 E" }, + { 9444732965739290427U, 6, 1000, "8.192000 E" }, + { 18446744073709551615U, 2, 1000, "16.00 E" }, + }; + + for (int i = 0; i < (int)ARRAY_SIZE(test_vectors); i++) + { + const char *result = fmt_order(test_vectors[i].value, test_vectors[i].decimals, test_vectors[i].threshold); + const char *expect = test_vectors[i].expect; + + bt_assert_msg(strncmp(result, expect, strlen(expect)) == 0, + "case %d, result \"%s\", expect \"%s\"", i, result, expect); + } + + return 1; +} + int main(int argc, char *argv[]) { @@ -126,6 +188,7 @@ main(int argc, char *argv[]) bt_test_suite(t_router_id, "print router id"); bt_test_suite(t_time, "print time"); bt_test_suite(t_bstrcmp, "bstrcmp"); + bt_test_suite(t_fmt_order, "fmt_order"); return bt_exit_value(); } diff --git a/lib/string.h b/lib/string.h index 0c21f513..8831666c 100644 --- a/lib/string.h +++ b/lib/string.h @@ -24,6 +24,8 @@ char *mb_sprintf(pool *p, const char *fmt, ...); char *mb_vsprintf(pool *p, const char *fmt, va_list args); char *lp_sprintf(linpool *p, const char *fmt, ...); char *lp_vsprintf(linpool *p, const char *fmt, va_list args); +#define tmp_sprintf(...) lp_sprintf(tmp_linpool, __VA_ARGS__) +#define tmp_vsprintf(...) lp_vsprintf(tmp_linpool, __VA_ARGS__) int buffer_vprint(buffer *buf, const char *fmt, va_list args); int buffer_print(buffer *buf, const char *fmt, ...); @@ -33,6 +35,8 @@ u64 bstrtoul10(const char *str, char **end); u64 bstrtoul16(const char *str, char **end); byte bstrtobyte16(const char *str); +char *fmt_order(u64 value, uint decimals, u64 kb_threshold); + int bstrhextobin(const char *s, byte *b); int bstrbintohex(const byte *b, size_t len, char *buf, size_t size, char delim) ACCESS_READ(1, 2) ACCESS_WRITE(3, 4); From e6a100b31a7637ee739338e4b933367707ec931f Mon Sep 17 00:00:00 2001 From: Maria Matejka Date: Tue, 17 Sep 2024 16:27:54 +0200 Subject: [PATCH 03/15] BMP: simplified update queuing and better memory performance This commit is quite a substantial rework of the underlying layers in BMP TX: - several unnecessary layers of indirection dropped, including most of the original BMP's buffer machinery - all messages are now written directly into one protocol's buffer allocated for the whole time big enough to fit every possible message - output blocks are allocated by pages and immediately returned when used, improving the overall memory footprint - no intermediary allocation is done from the heap altogether - there is a documented and configurable limit on the TX queue size --- doc/bird.sgml | 12 ++ proto/bgp/bgp.h | 2 +- proto/bgp/packets.c | 8 +- proto/bmp/Makefile | 4 +- proto/bmp/bmp.c | 503 +++++++++++++++++++++++++++----------------- proto/bmp/bmp.h | 25 ++- proto/bmp/buffer.c | 65 ------ proto/bmp/buffer.h | 77 ------- proto/bmp/config.Y | 5 + 9 files changed, 355 insertions(+), 346 deletions(-) delete mode 100644 proto/bmp/buffer.c delete mode 100644 proto/bmp/buffer.h diff --git a/doc/bird.sgml b/doc/bird.sgml index d1375caf..b6b77691 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -3808,6 +3808,15 @@ by default and have to be enabled during installation by the configure option routes (in ) and post-policy routes (in regular routing tables). All BGP protocols are monitored automatically. +Configuration (incomplete) +