diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 449be5384..e9a1324ab 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,7 +19,8 @@ docker-image: stage: prepare # Must match the docker version on the build machine! before_script: - - git submodule update --init --recursive + - git submodule sync --recursive + - git submodule update --recursive --init - docker info script: - docker build -t $DOCKER_REGISTRY/$DOCKER_IMAGE . @@ -78,8 +79,7 @@ unit: dependencies: - build script: - - make tests - - build/release/testsuite + - make run-tests image: $DOCKER_REGISTRY/$DOCKER_IMAGE tags: - docker diff --git a/.gitmodules b/.gitmodules index a61e863eb..79fac9332 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ url = https://github.com/warmcat/libwebsockets [submodule "thirdparty/criterion"] path = thirdparty/criterion - url = https://github.com/stv0g/Criterion + url = https://github.com/Snaipe/Criterion [submodule "thirdparty/libnl"] path = thirdparty/libnl url = https://github.com/thom311/libnl.git diff --git a/include/villas/memory.h b/include/villas/memory.h index d66955727..cf1d7acd5 100644 --- a/include/villas/memory.h +++ b/include/villas/memory.h @@ -8,10 +8,13 @@ */ #include +#include #ifndef _MEMORY_H_ #define _MEMORY_H_ +#define HUGEPAGESIZE (1 << 21) + typedef void *(*memzone_allocator_t)(size_t len); typedef int (*memzone_deallocator_t)(void *ptr, size_t len); diff --git a/include/villas/utils.h b/include/villas/utils.h index 82b7cabb7..8a50b6754 100644 --- a/include/villas/utils.h +++ b/include/villas/utils.h @@ -57,6 +57,12 @@ #define CEIL(x, y) ((x + y - 1) / y) +/** Get nearest up-rounded power of 2 */ +#define LOG2_CEIL(x) (1 << (log2i((x) - 1) + 1)) + +/** Check if the number is a power of 2 */ +#define IS_POW2(x) (((x) != 0) && !((x) & ((x) - 1))) + /** Calculate the number of elements in an array. */ #define ARRAY_LEN(a) ( sizeof (a) / sizeof (a)[0] ) @@ -180,7 +186,7 @@ struct version { }; /** Compare two versions. */ -int version_compare(struct version *a, struct version *b); +int version_cmp(struct version *a, struct version *b); /** Parse a dotted version string. */ int version_parse(const char *s, struct version *v); diff --git a/lib/kernel/kernel.c b/lib/kernel/kernel.c index 6548dbf49..b2c9b94cc 100644 --- a/lib/kernel/kernel.c +++ b/lib/kernel/kernel.c @@ -101,7 +101,7 @@ int kernel_has_version(int maj, int min) if (version_parse(uts.release, ¤t)) return -1; - return version_compare(¤t, &required) < 0; + return version_cmp(¤t, &required) < 0; } int kernel_is_rt() diff --git a/lib/memory.c b/lib/memory.c index df4eccd7e..7525a1c0c 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -65,6 +65,8 @@ static void * memory_hugepage_alloc(size_t len) static int memory_hugepage_free(void *ptr, size_t len) { + len = ALIGN(len, HUGEPAGESIZE); /* ugly see: https://lkml.org/lkml/2015/3/27/171 */ + return munmap(ptr, len); } diff --git a/lib/utils.c b/lib/utils.c index eff72a954..5fba36038 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -35,7 +35,7 @@ int version_parse(const char *s, struct version *v) return sscanf(s, "%u.%u", &v->major, &v->minor) != 2; } -int version_compare(struct version *a, struct version *b) { +int version_cmp(struct version *a, struct version *b) { int major = a->major - b->major; int minor = a->minor - b->minor; diff --git a/tests/Makefile.inc b/tests/Makefile.inc index facbef13f..9bac51525 100644 --- a/tests/Makefile.inc +++ b/tests/Makefile.inc @@ -7,6 +7,10 @@ TEST_LDLIBS = $(LDLIBS) -lcriterion -lvillas -pthread tests: $(BUILDDIR)/testsuite +run-tests: tests + echo 25 > /proc/sys/vm/nr_hugepages + $(BUILDDIR)/testsuite + # Compile $(BUILDDIR)/tests/%.o: tests/%.c | $$(dir $$@) $(CC) $(TEST_CFLAGS) -c $< -o $@ @@ -25,4 +29,4 @@ install-tests: clean-tests: rm -rf $(BUILDDIR)/tests $(BUILDDIR)/testsuite -.PHONY: tests install-tests clean-tests \ No newline at end of file +.PHONY: tests install-tests clean-tests run-tests \ No newline at end of file diff --git a/tests/memory.c b/tests/memory.c new file mode 100644 index 000000000..234e6defd --- /dev/null +++ b/tests/memory.c @@ -0,0 +1,39 @@ +/** Unit tests for memory management + * + * @author Steffen Vogel + * @copyright 2014-2016, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include +#include + +#include + +#include "memory.h" +#include "utils.h" + +TheoryDataPoints(memory, aligned) = { +// DataPoints(size_t, 1, 32, 55, 1 << 10, 1 << 20), + DataPoints(size_t, 1<<12), + DataPoints(size_t, 1, 8, 1 << 12), + DataPoints(const struct memtype *, &memtype_heap, &memtype_hugepage) +}; + +Theory((size_t len, size_t align, const struct memtype *m), memory, aligned) { + int ret; + void *ptr; + + ptr = memory_alloc_aligned(m, len, align); + cr_assert_neq(ptr, NULL, "Failed to allocate memory"); + + //cr_assert(IS_ALIGNED(ptr, align)); + + if (m == &memtype_hugepage) { + cr_assert(IS_ALIGNED(ptr, HUGEPAGESIZE)); + } + + ret = memory_free(m, ptr, len); + cr_assert_eq(ret, 0, "Failed to release memory: ret=%d, ptr=%p, len=%zu: %s", ret, ptr, len, strerror(errno)); +} \ No newline at end of file diff --git a/tests/pool.c b/tests/pool.c new file mode 100644 index 000000000..8654ad6ea --- /dev/null +++ b/tests/pool.c @@ -0,0 +1,68 @@ +/** Unit tests for memory pool + * + * @author Steffen Vogel + * @copyright 2014-2016, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include +#include + +#include + +#include "pool.h" +#include "utils.h" + +struct param { + int thread_count; + int pool_size; + size_t block_size; + const struct memtype *memtype; +}; + +ParameterizedTestParameters(pool, basic) +{ + static struct param params[] = { + { 1, 4096, 150, &memtype_heap }, + { 1, 128, 8, &memtype_hugepage }, + { 1, 4, 8192, &memtype_hugepage }, + { 1, 1 << 13, 4, &memtype_heap } + }; + + return cr_make_param_array(struct param, params, ARRAY_LEN(params)); +} + +ParameterizedTest(struct param *p, pool, basic) +{ + int ret; + struct pool pool; + + void *ptr, *ptrs[p->pool_size]; + + ret = pool_init(&pool, p->pool_size, p->block_size, p->memtype); + cr_assert_eq(ret, 0, "Failed to create pool"); + + ptr = pool_get(&pool); + cr_assert_neq(ptr, NULL); + + memset(ptr, 1, p->block_size); /* check that we dont get a seg fault */ + + int i; + for (i = 1; i < p->pool_size; i++) { + ptrs[i] = pool_get(&pool); + + if (ptrs[i] == NULL) + break; + } + + if (i < p->pool_size) + cr_assert_neq(ptrs[i], NULL); + + ptr = pool_get(&pool); + cr_assert_eq(ptr, NULL); + + ret = pool_destroy(&pool); + cr_assert_eq(ret, 0, "Failed to destroy pool"); + +} \ No newline at end of file diff --git a/tests/timing.c b/tests/timing.c index 82fb8bf6f..89866c07f 100644 --- a/tests/timing.c +++ b/tests/timing.c @@ -7,6 +7,7 @@ *********************************************************************************/ #include +#include #include #include "timing.h" @@ -86,7 +87,10 @@ Test(timing, timerfd_create_rate, .timeout = 20) cr_assert(tfd > 0); - for (int i = 0; i < 10; i++) { + timerfd_wait(tfd); + + int i; + for (i = 0; i < 10; i++) { start = time_now(); timerfd_wait(tfd); @@ -94,9 +98,13 @@ Test(timing, timerfd_create_rate, .timeout = 20) end = time_now(); waited = time_delta(&start, &end); - cr_assert_float_eq(waited, 1.0 / rate, 10e-3, "We slept for %f instead of %f secs in round %d", waited, 1.0 / rate, i); + if (fabs(waited - 1.0 / rate) > 10e-3) + break; } + if (i < 10) + cr_assert_float_eq(waited, 1.0 / rate, 10e-3, "We slept for %f instead of %f secs in round %d", waited, 1.0 / rate, i); + close(tfd); } diff --git a/tests/utils.c b/tests/utils.c new file mode 100644 index 000000000..6999cd70e --- /dev/null +++ b/tests/utils.c @@ -0,0 +1,64 @@ +/** Unit tests for utilities + * + * @author Steffen Vogel + * @copyright 2014-2016, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASnode. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include + +#include "utils.h" + +Test(utils, is_aligned) +{ + /* Positive */ + cr_assert(IS_ALIGNED(1, 1)); + cr_assert(IS_ALIGNED(128, 64)); + + /* Negative */ + cr_assert(!IS_ALIGNED(55, 16)); + cr_assert(!IS_ALIGNED(55, 55)); + cr_assert(!IS_ALIGNED(1128, 256)); +} + +Test(utils, ceil) +{ + cr_assert_eq(CEIL(10, 3), 4); + cr_assert_eq(CEIL(10, 5), 2); + cr_assert_eq(CEIL(4, 3), 2); +} + +Test(utils, is_pow2) +{ + /* Positive */ + cr_assert(IS_POW2(1)); + cr_assert(IS_POW2(2)); + cr_assert(IS_POW2(64)); + + /* Negative */ + cr_assert(!IS_POW2(0)); + cr_assert(!IS_POW2(3)); + cr_assert(!IS_POW2(11111)); + cr_assert(!IS_POW2(-1)); +} + +struct version_param { + const char *v1, *v2; + int result; +}; + +Test(utils, version) +{ + struct version v1, v2, v3, v4; + + version_parse("1.2", &v1); + version_parse("1.3", &v2); + version_parse("55", &v3); + version_parse("66", &v4); + + cr_assert_lt(version_cmp(&v1, &v2), 0); + cr_assert_eq(version_cmp(&v1, &v1), 0); + cr_assert_gt(version_cmp(&v2, &v1), 0); + cr_assert_lt(version_cmp(&v3, &v4), 0); +} \ No newline at end of file diff --git a/thirdparty/criterion b/thirdparty/criterion index 1b687a9f6..101d0e0f3 160000 --- a/thirdparty/criterion +++ b/thirdparty/criterion @@ -1 +1 @@ -Subproject commit 1b687a9f6a0e51c9e9b0a047e1fcd6c94de7a080 +Subproject commit 101d0e0f3a71c414c7d2a7a2a2fa465969b6b667