summaryrefslogtreecommitdiff
path: root/lib/slab_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/slab_test.c')
-rw-r--r--lib/slab_test.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/lib/slab_test.c b/lib/slab_test.c
new file mode 100644
index 00000000..803d0215
--- /dev/null
+++ b/lib/slab_test.c
@@ -0,0 +1,171 @@
+/*
+ * BIRD Library -- Slab Alloc / Dealloc Tests
+ *
+ * (c) 2022 Maria Matejka <mq@jmq.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "lib/resource.h"
+#include "lib/bitops.h"
+
+static const int sizes[] = {
+ 8, 12, 18, 27, 41, 75, 131, 269,
+};
+
+#define TEST_SIZE 1024 * 128
+#define ITEMS(sz) TEST_SIZE / ( (sz) >> u32_log2((sz))/2 )
+
+struct test_request {
+ int size;
+ enum strategy {
+ TEST_NONE,
+ TEST_FORWARDS,
+ TEST_BACKWARDS,
+ TEST_RANDOM,
+ TEST_MIXED,
+ TEST__MAX,
+ } strategy;
+};
+
+const char * const strategy_name[TEST__MAX] = {
+ [TEST_FORWARDS] = "forwards",
+ [TEST_BACKWARDS] = "backwards",
+ [TEST_RANDOM] = "random",
+ [TEST_MIXED] = "mixed",
+};
+
+static inline byte *test_alloc(slab *s, int sz, struct resmem *sliz)
+{
+ byte *out = sl_alloc(s);
+
+ for (int p=0; p < sz; p++)
+ out[p] = p & 0xff;
+
+ struct resmem ns = rmemsize((resource *) s);
+
+ bt_assert(sliz->effective + sz == ns.effective);
+ bt_assert((sliz->overhead - sz - ns.overhead) % page_size == 0);
+
+ *sliz = ns;
+
+ return out;
+}
+
+static inline void test_free(slab *s, byte *block, int sz, struct resmem *sliz)
+{
+ for (int p=0; p < sz; p++)
+ {
+ bt_assert(block[p] == (p & 0xff));
+ block[p]++;
+ }
+
+ sl_free(block);
+
+ struct resmem ns = rmemsize((resource *) s);
+
+ bt_assert(sliz->effective - sz == ns.effective);
+ bt_assert((sliz->overhead + sz - ns.overhead) % page_size == 0);
+
+ *sliz = ns;
+}
+
+static inline struct resmem get_memsize(slab *s)
+{
+ struct resmem sz = rmemsize((resource *) s);
+ bt_assert(sz.effective == 0);
+ return sz;
+}
+
+static int
+t_slab(const void *data)
+{
+ const struct test_request *tr = data;
+ int sz = tr->size;
+
+ slab *s = sl_new(&root_pool, sz);
+ struct resmem sliz = get_memsize(s);
+
+ int n = ITEMS(sz);
+ byte **block = mb_alloc(&root_pool, n * sizeof(*block));
+
+ switch (tr->strategy) {
+ case TEST_FORWARDS:
+ for (int i = 0; i < n; i++)
+ block[i] = test_alloc(s, sz, &sliz);
+
+ for (int i = 0; i < n; i++)
+ test_free(s, block[i], sz, &sliz);
+
+ break;
+
+ case TEST_BACKWARDS:
+ for (int i = 0; i < n; i++)
+ block[i] = test_alloc(s, sz, &sliz);
+
+ for (int i = n - 1; i >= 0; i--)
+ test_free(s, block[i], sz, &sliz);
+
+ break;
+
+ case TEST_RANDOM:
+ for (int i = 0; i < n; i++)
+ block[i] = test_alloc(s, sz, &sliz);
+
+ for (int i = 0; i < n; i++)
+ {
+ int pos = bt_random() % (n - i);
+ test_free(s, block[pos], sz, &sliz);
+ if (pos != n - i - 1)
+ block[pos] = block[n - i - 1];
+ }
+
+ break;
+
+ case TEST_MIXED:
+ {
+ int cur = 0;
+ int pending = n;
+
+ while (cur + pending > 0) {
+ int action = bt_random() % (cur + pending);
+
+ if (action < cur) {
+ test_free(s, block[action], sz, &sliz);
+ if (action != --cur)
+ block[action] = block[cur];
+ } else {
+ block[cur++] = test_alloc(s, sz, &sliz);
+ pending--;
+ }
+ }
+
+ break;
+ }
+
+ default: bug("This shouldn't happen");
+ }
+
+ mb_free(block);
+ return 1;
+}
+int main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ struct test_request tr;
+
+ for (uint i = 0; i < sizeof(sizes) / sizeof(*sizes); i++)
+ for (uint strategy = TEST_FORWARDS; strategy < TEST__MAX; strategy++)
+ {
+ tr = (struct test_request) {
+ .size = sizes[i],
+ .strategy = strategy,
+ };
+ bt_test_suite_arg(t_slab, &tr, "Slab allocator test, size=%d, strategy=%s",
+ tr.size, strategy_name[strategy]);
+ }
+
+ return bt_exit_value();
+}