From 56d5b00e8ca92a9622b3f68cede439fc986040d9 Mon Sep 17 00:00:00 2001 From: Marek Vavrusa <marek@vavrusa.com> Date: Tue, 19 Oct 2010 12:49:40 +0200 Subject: [PATCH] Dynamic array unit tests. --- CuteDNS.files | 1 + src/tests/da_tests.c | 218 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 src/tests/da_tests.c diff --git a/CuteDNS.files b/CuteDNS.files index cb99e3cb6..43dc9854b 100644 --- a/CuteDNS.files +++ b/CuteDNS.files @@ -38,6 +38,7 @@ src/tests/cuckoo-test.c src/tests/cuckoo-test.h src/tests/server_tests.c src/tests/skiplist_tests.c +src/tests/da_tests.c src/tests/tap_unit.h src/tests/template_tests.c src/other/log.h diff --git a/src/tests/da_tests.c b/src/tests/da_tests.c new file mode 100644 index 000000000..273d4b71f --- /dev/null +++ b/src/tests/da_tests.c @@ -0,0 +1,218 @@ +#include "tap_unit.h" +#include "dynamic-array.h" +#include <unistd.h> +#include <urcu.h> + +static int da_tests_count(int argc, char * argv[]); +static int da_tests_run(int argc, char * argv[]); + +/* + * Unit API. + */ +unit_api da_tests_api = { + "Dynamic array", + &da_tests_count, + &da_tests_run +}; + +/* + * Unit implementation. + */ + +static const int DA_TEST_COUNT = 3; +static const int DA_FRAGMENT = 10; +static const int DA_DEF_SIZE = 1000; +static const int DA_OPERATIONS = 1; +enum Operations { + DA_RESERVE = 0, + DA_OCCUPY = 1, + DA_RELEASE = 2, + DA_OPCOUNT = 3 +}; + +static int da_tests_count(int argc, char *argv[]) +{ + return DA_TEST_COUNT; +} + +static int test_da_init(da_array* arr) +{ + return da_initialize(arr, DA_DEF_SIZE, sizeof(uint)) == 0; +} + +static int test_da_random_op(da_array* arr) +{ + srand(time(NULL)); + uint allocated = DA_DEF_SIZE; + uint size = 0; + + for (int i = 0; i < DA_OPERATIONS; ++i) { + int r = rand() % DA_OPCOUNT; + int count = rand() % DA_FRAGMENT + 1; + + // Ensure at least one last reserve + if(i == DA_OPERATIONS - 1) { + r = DA_OCCUPY; + count = rand() % (int)(allocated) + 1; + } + + switch (r) { + + // Perform reserve operation + case DA_RESERVE: + if (da_reserve(arr, count) >= 0 && + size <= allocated) + { + if ((allocated - size) < count) { + allocated *= 2; + } + } + else { + diag("dynamic-array: da_reserve(%p, %d) failed (size %d, alloc'd %d)", arr, count, size, allocated); + return 0; + } + break; + + // Perform occupy operation + case DA_OCCUPY: + if (da_occupy(arr, count) == 0) { + uint* items = (uint *) da_get_items(arr); + for(int j = 0; j < da_get_count(arr); ++j) + items[j] = rand(); + if(size <= allocated && (allocated - size) >= count) + size += count; + else + return 0; + } + else { + diag("dynamic-array: da_occupy(%p, %d) failed (size %d, alloc'd %d)", arr, count, size, allocated); + return 0; + } + break; + + // Perform release operation + case DA_RELEASE: + if(arr->count > 0) { + count = (rand() % DA_FRAGMENT) % arr->count; + da_release(arr, count); + + if(size <= allocated && size >= count) { + size -= count; + } + else { + return 0; + } + } + break; + + default: + break; + } + + // Check allocated / size + if(allocated != arr->allocated || size != arr->count) { + diag("dynamic-array: allocated memory %d (expected %d) size %d (expected %d) mismatch", + arr->allocated, allocated, arr->count, size); + return 0; + } + } + + return 1; +} + +static void do_something(int loops) +{ + int i; + int res = 1; + + static const int LOOPS = 10000; + + for (int j = 1; j <= LOOPS; ++j) { + for (i = 1; i <= loops; ++i) { + res *= i; + } + } +} + +void *test_da_read(void *obj) +{ + rcu_register_thread(); + rcu_read_lock(); + + da_array* arr = (da_array*) obj; + int index = rand() % da_get_count(arr); + + note(" dynamic-array: read thread"); + note(" read thread: saving pointer to %d. item", index); + uint *item = &((uint*) da_get_items(arr))[index]; + note(" read thread: before: pointer: %p item: %u", item, *item); + + do_something(100000); + + note(" read thread after: pointer: %p item: %u", item, *item); + rcu_read_unlock(); + note(" read thread unlocked: pointer: %p item: %u", item, *item); + + do_something(10000); + + note(" read thread: now the item should be deallocated"); + note(" read thread unlocked: pointer: %p item: %u", item, *item); + + rcu_unregister_thread(); + + return NULL; +} + +static int test_da_resize_holding(da_array* arr) +{ + int ret = 1; + rcu_register_thread(); + pthread_t reader; + + // Create thread for reading + if (pthread_create(&reader, NULL, test_da_read, (void *)arr)) { + diag("dynamic-array: failed to create reading thread", __func__); + rcu_unregister_thread(); + return 0; + } + + // Wait some time, so the other thread gets the item for reading + do_something(5000); + + // Force resize + note(" dynamic-array: array resized"); + if(da_reserve(arr, arr->allocated - arr->count + 1) == -1) { + diag("dynamic-array: da_reserve(%p, %d) failed", arr, arr->allocated - arr->count + 1); + ret = 0; + } + + //Wait for the thread to finish + void *pret = NULL; + if (pthread_join(reader, &pret)) { + diag("dynamic-array: failed to join reading thread", __func__); + ret = 0; + } + + rcu_unregister_thread(); + return ret; +} + +static int da_tests_run(int argc, char *argv[]) +{ + // Init + rcu_init(); + da_array array; + + // Test 1: init + ok(test_da_init(&array), "dynamic-array: init"); + + // Test 2: reserve/occupy random operations + ok(test_da_random_op(&array), "dynamic-array: randomized reserve/occupy/release"); + + // Test 3: resizing array while holding an item + ok(test_da_resize_holding(&array), "dynamic-array: resize array while holding an item"); + + // Cleanup + da_destroy(&array); + return 0; +} -- GitLab