Adding simple tests for shmem operations performed on the driver (drv) interface. Does not to assume pthread as odpthreads (the barrier is now part of the reserved area, rather than a global which only works for pthreads). Tests simple functionanlity, but regardless of reserve() time (i.e. memory reservation occurs both before and after odpthread creation here).
Signed-off-by: Christophe Milard <christophe.mil...@linaro.org> --- test/common_plat/m4/configure.m4 | 3 +- test/common_plat/validation/drv/Makefile.am | 3 +- .../common_plat/validation/drv/drvshmem/.gitignore | 1 + .../validation/drv/drvshmem/Makefile.am | 10 + .../common_plat/validation/drv/drvshmem/drvshmem.c | 351 +++++++++++++++++++++ .../common_plat/validation/drv/drvshmem/drvshmem.h | 25 ++ .../validation/drv/drvshmem/drvshmem_main.c | 12 + test/linux-generic/Makefile.am | 1 + 8 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 test/common_plat/validation/drv/drvshmem/.gitignore create mode 100644 test/common_plat/validation/drv/drvshmem/Makefile.am create mode 100644 test/common_plat/validation/drv/drvshmem/drvshmem.c create mode 100644 test/common_plat/validation/drv/drvshmem/drvshmem.h create mode 100644 test/common_plat/validation/drv/drvshmem/drvshmem_main.c diff --git a/test/common_plat/m4/configure.m4 b/test/common_plat/m4/configure.m4 index 20c3a3b..1fc350d 100644 --- a/test/common_plat/m4/configure.m4 +++ b/test/common_plat/m4/configure.m4 @@ -32,4 +32,5 @@ AC_CONFIG_FILES([test/common_plat/Makefile test/common_plat/validation/api/timer/Makefile test/common_plat/validation/api/traffic_mngr/Makefile test/common_plat/validation/drv/Makefile - test/common_plat/validation/drv/drvatomic/Makefile]) + test/common_plat/validation/drv/drvatomic/Makefile + test/common_plat/validation/drv/drvshmem/Makefile]) diff --git a/test/common_plat/validation/drv/Makefile.am b/test/common_plat/validation/drv/Makefile.am index eedbad5..bcdb92e 100644 --- a/test/common_plat/validation/drv/Makefile.am +++ b/test/common_plat/validation/drv/Makefile.am @@ -1,4 +1,5 @@ -ODPDRV_MODULES = drvatomic +ODPDRV_MODULES = drvatomic \ + drvshmem SUBDIRS = $(ODPDRV_MODULES) diff --git a/test/common_plat/validation/drv/drvshmem/.gitignore b/test/common_plat/validation/drv/drvshmem/.gitignore new file mode 100644 index 0000000..726dea3 --- /dev/null +++ b/test/common_plat/validation/drv/drvshmem/.gitignore @@ -0,0 +1 @@ +drvshmem_main diff --git a/test/common_plat/validation/drv/drvshmem/Makefile.am b/test/common_plat/validation/drv/drvshmem/Makefile.am new file mode 100644 index 0000000..816a5e6 --- /dev/null +++ b/test/common_plat/validation/drv/drvshmem/Makefile.am @@ -0,0 +1,10 @@ +include ../Makefile.inc + +noinst_LTLIBRARIES = libtestdrvshmem.la +libtestdrvshmem_la_SOURCES = drvshmem.c + +test_PROGRAMS = drvshmem_main$(EXEEXT) +dist_drvshmem_main_SOURCES = drvshmem_main.c +drvshmem_main_LDADD = libtestdrvshmem.la $(LIBCUNIT_COMMON) $(LIBODP) + +EXTRA_DIST = drvshmem.h diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem.c b/test/common_plat/validation/drv/drvshmem/drvshmem.c new file mode 100644 index 0000000..42ad844 --- /dev/null +++ b/test/common_plat/validation/drv/drvshmem/drvshmem.c @@ -0,0 +1,351 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <odp_drv.h> +#include <odp_api.h> +#include <odp_cunit_common.h> +#include "drvshmem.h" +#include <stdlib.h> + +#define ALIGN_SIZE (128) +#define MEM_NAME "test_shmem" +#define TEST_SHARE_FOO (0xf0f0f0f0) +#define TEST_SHARE_BAR (0xf0f0f0f) +#define SMALL_MEM 10 +#define MEDIUM_MEM 4096 +#define BIG_MEM 16777216 + +typedef struct { + odpdrv_barrier_t test_barrier1; + odpdrv_barrier_t test_barrier2; + uint32_t foo; + uint32_t bar; + odpdrv_atomic_u32_t index; + odpdrv_shm_t shm[MAX_WORKERS]; +} shared_test_data_t; + +/* memory stuff expected to fit in a single page */ +typedef struct { + int data[SMALL_MEM]; +} shared_test_data_small_t; + +/* memory stuff expected to fit in a huge page */ +typedef struct { + int data[MEDIUM_MEM]; +} shared_test_data_medium_t; + +/* memory stuff expected to fit in many huge pages */ +typedef struct { + int data[BIG_MEM]; +} shared_test_data_big_t; + +/* + * thread part for the drvshmem_test_basic test + */ +static int run_test_basic_thread(void *arg ODP_UNUSED) +{ + odpdrv_shm_info_t info; + odpdrv_shm_t shm; + shared_test_data_t *shared_test_data; + int thr; + + thr = odp_thread_id(); + printf("Thread %i starts\n", thr); + + shm = odpdrv_shm_lookup_by_name(MEM_NAME); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + shared_test_data = odpdrv_shm_addr(shm); + CU_ASSERT(NULL != shared_test_data); + + odpdrv_barrier_wait(&shared_test_data->test_barrier1); + odpdrv_shm_print_all("(from thread) After lookup for the global shmem"); + CU_ASSERT(TEST_SHARE_FOO == shared_test_data->foo); + CU_ASSERT(TEST_SHARE_BAR == shared_test_data->bar); + CU_ASSERT(0 == odpdrv_shm_info(shm, &info)); + CU_ASSERT(0 == strcmp(MEM_NAME, info.name)); + CU_ASSERT(0 == info.flags); + CU_ASSERT(shared_test_data == info.addr); + CU_ASSERT(sizeof(shared_test_data_t) <= info.size); +#ifdef MAP_HUGETLB + CU_ASSERT(odp_sys_huge_page_size() == info.page_size); +#else + CU_ASSERT(odp_sys_page_size() == info.page_size); +#endif + odpdrv_shm_print_all("(from thread) About to end"); + + fflush(stdout); + return CU_get_number_of_failures(); +} + +/* + * test basic things: shmem creation, info, share, and free + */ +void drvshmem_test_basic(void) +{ + int base; /* memory usage when test starts */ + pthrd_arg thrdarg; + odpdrv_shm_t shm; + shared_test_data_t *shared_test_data; + odp_cpumask_t unused; + + base = odpdrv_shm_print_all("Before drvshmem_test_basic"); + shm = odpdrv_shm_reserve(MEM_NAME, + sizeof(shared_test_data_t), ALIGN_SIZE, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + CU_ASSERT(odpdrv_shm_to_u64(shm) != + odpdrv_shm_to_u64(ODPDRV_SHM_INVALID)); + + CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm)); + CU_ASSERT(ODPDRV_SHM_INVALID == odpdrv_shm_lookup_by_name(MEM_NAME)); + + shm = odpdrv_shm_reserve(MEM_NAME, + sizeof(shared_test_data_t), ALIGN_SIZE, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + + shared_test_data = odpdrv_shm_addr(shm); + CU_ASSERT_FATAL(NULL != shared_test_data); + shared_test_data->foo = TEST_SHARE_FOO; + shared_test_data->bar = TEST_SHARE_BAR; + + CU_ASSERT(odpdrv_shm_free_by_address((char *)shared_test_data - 1) < 0); + + thrdarg.numthrds = odp_cpumask_default_worker(&unused, 0); + + if (thrdarg.numthrds > MAX_WORKERS) + thrdarg.numthrds = MAX_WORKERS; + + odpdrv_barrier_init(&shared_test_data->test_barrier1, thrdarg.numthrds); + odp_cunit_thread_create(run_test_basic_thread, &thrdarg); + CU_ASSERT(odp_cunit_thread_exit(&thrdarg) >= 0); + + CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm)); + CU_ASSERT(odpdrv_shm_print_all("Test completion") == base); +} + +/* + * thread part for the drvshmem_test_reserve_after_fork + */ +static int run_test_reserve_after_fork(void *arg ODP_UNUSED) +{ + odpdrv_shm_t shm; + shared_test_data_t *glob_data; + int thr; + int thr_index; + char *name; + int name_len; + int size; + shared_test_data_small_t *pattern_small; + shared_test_data_medium_t *pattern_medium; + shared_test_data_big_t *pattern_big; + int i; + + thr = odp_thread_id(); + printf("Thread %i starts\n", thr); + + shm = odpdrv_shm_lookup_by_name(MEM_NAME); + glob_data = odpdrv_shm_addr(shm); + + /* + * odp_thread_id are not guaranteed to be consecutive, so we create + * a consecutive ID + */ + thr_index = odpdrv_atomic_fetch_inc_u32(&glob_data->index); + + /* allocate some memory (of different sizes) and fill with pattern */ + name_len = strlen(MEM_NAME) + 20; + name = malloc(name_len); + snprintf(name, name_len, "%s-%09d", MEM_NAME, thr_index); + switch (thr_index % 3) { + case 0: + size = sizeof(shared_test_data_small_t); + shm = odpdrv_shm_reserve(name, size, 0, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + glob_data->shm[thr_index] = shm; + pattern_small = odpdrv_shm_addr(shm); + CU_ASSERT_PTR_NOT_NULL(pattern_small); + for (i = 0; i < SMALL_MEM; i++) + pattern_small->data[i] = i; + break; + case 1: + size = sizeof(shared_test_data_medium_t); + shm = odpdrv_shm_reserve(name, size, 0, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + glob_data->shm[thr_index] = shm; + pattern_medium = odpdrv_shm_addr(shm); + CU_ASSERT_PTR_NOT_NULL(pattern_medium); + for (i = 0; i < MEDIUM_MEM; i++) + pattern_medium->data[i] = (i << 2); + break; + case 2: + size = sizeof(shared_test_data_big_t); + shm = odpdrv_shm_reserve(name, size, 0, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + glob_data->shm[thr_index] = shm; + pattern_big = odpdrv_shm_addr(shm); + CU_ASSERT_PTR_NOT_NULL(pattern_big); + for (i = 0; i < BIG_MEM; i++) + pattern_big->data[i] = (i >> 2); + break; + } + free(name); + + /* print block address */ + printf("In thread: Block index: %d mapped at %lx\n", + thr_index, (long int)odpdrv_shm_addr(shm)); + + odpdrv_barrier_wait(&glob_data->test_barrier1); + odpdrv_barrier_wait(&glob_data->test_barrier2); + + fflush(stdout); + return CU_get_number_of_failures(); +} + +/* + * test sharing memory reserved after odp_thread creation (e.g. fork()): + */ +void drvshmem_test_reserve_after_fork(void) +{ + int base; /* memory usage when test starts */ + pthrd_arg thrdarg; + odpdrv_shm_t shm; + odpdrv_shm_t thr_shm; + shared_test_data_t *glob_data; + odp_cpumask_t unused; + char *name; + int name_len; + int thr_index; + int i; + void *address; + shared_test_data_small_t *pattern_small; + shared_test_data_medium_t *pattern_medium; + shared_test_data_big_t *pattern_big; + + base = odpdrv_shm_print_all("Before drvshmem_test_reserve_after_fork"); + shm = odpdrv_shm_reserve(MEM_NAME, sizeof(shared_test_data_t), 0, 0); + CU_ASSERT(ODPDRV_SHM_INVALID != shm); + glob_data = odpdrv_shm_addr(shm); + CU_ASSERT_PTR_NOT_NULL(glob_data); + + thrdarg.numthrds = odp_cpumask_default_worker(&unused, 0); + if (thrdarg.numthrds > MAX_WORKERS) + thrdarg.numthrds = MAX_WORKERS; + + odpdrv_barrier_init(&glob_data->test_barrier1, thrdarg.numthrds + 1); + odpdrv_barrier_init(&glob_data->test_barrier2, thrdarg.numthrds + 1); + odpdrv_atomic_store_u32(&glob_data->index, 0); + + odp_cunit_thread_create(run_test_reserve_after_fork, &thrdarg); + + /* wait until all threads have made their shm_reserve: */ + odpdrv_barrier_wait(&glob_data->test_barrier1); + CU_ASSERT(odpdrv_shm_print_all("After all thread reserve") + == base + thrdarg.numthrds + 1); + + /* perform a lookup of all memories, by handle or name: */ + name_len = strlen(MEM_NAME) + 20; + name = malloc(name_len); + for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) { + if (thr_index % 2) { + snprintf(name, name_len, "%s-%09d", + MEM_NAME, thr_index); + thr_shm = odpdrv_shm_lookup_by_name(name); + CU_ASSERT(thr_shm == glob_data->shm[thr_index]); + } else { + odpdrv_shm_lookup_by_handle(glob_data->shm[thr_index]); + } + } + + /* check that the patterns are correct: */ + for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) { + switch (thr_index % 3) { + case 0: + pattern_small = + odpdrv_shm_addr(glob_data->shm[thr_index]); + CU_ASSERT_PTR_NOT_NULL(pattern_small); + for (i = 0; i < SMALL_MEM; i++) + CU_ASSERT(pattern_small->data[i] == i); + break; + case 1: + pattern_medium = + odpdrv_shm_addr(glob_data->shm[thr_index]); + CU_ASSERT_PTR_NOT_NULL(pattern_medium); + for (i = 0; i < MEDIUM_MEM; i++) + CU_ASSERT(pattern_medium->data[i] == (i << 2)); + break; + case 2: + pattern_big = + odpdrv_shm_addr(glob_data->shm[thr_index]); + CU_ASSERT_PTR_NOT_NULL(pattern_big); + for (i = 0; i < BIG_MEM; i++) + CU_ASSERT(pattern_big->data[i] == (i >> 2)); + break; + } + } + + /* + * print the mapping address of the blocks + */ + for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) { + address = odpdrv_shm_addr(glob_data->shm[thr_index]); + printf("In main Block index: %d mapped at %lx\n", + thr_index, (long int)address); + } + + CU_ASSERT(odpdrv_shm_print_all("After main lookup of thread shmem") + == base + thrdarg.numthrds + 1); + + /* unblock the threads and let them terminate (no free is done): */ + odpdrv_barrier_wait(&glob_data->test_barrier2); + + /* at the same time, (race),free of all memories, by handle or name: */ + for (thr_index = 0; thr_index < thrdarg.numthrds; thr_index++) { + if (thr_index % 2) { + thr_shm = glob_data->shm[thr_index]; + CU_ASSERT(odpdrv_shm_free_by_handle(thr_shm) == 0); + } else { + snprintf(name, name_len, "%s-%09d", + MEM_NAME, thr_index); + CU_ASSERT(odpdrv_shm_free_by_name(name) == 0); + } + } + free(name); + + /* wait for all thread endings: */ + CU_ASSERT(odp_cunit_thread_exit(&thrdarg) >= 0); + + /* just glob_data should remain: */ + CU_ASSERT(odpdrv_shm_print_all("After all threads end") == base + 1); + + CU_ASSERT(0 == odpdrv_shm_free_by_handle(shm)); + CU_ASSERT(odpdrv_shm_print_all("Test completion") == base); +} + +odp_testinfo_t drvshmem_suite[] = { + ODP_TEST_INFO(drvshmem_test_basic), + ODP_TEST_INFO(drvshmem_test_reserve_after_fork), + ODP_TEST_INFO_NULL, +}; + +odp_suiteinfo_t drvshmem_suites[] = { + {"Shared Memory", NULL, NULL, drvshmem_suite}, + ODP_SUITE_INFO_NULL, +}; + +int drvshmem_main(int argc, char *argv[]) +{ + int ret; + + /* parse common options: */ + if (odp_cunit_parse_options(argc, argv)) + return -1; + + ret = odp_cunit_register(drvshmem_suites); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem.h b/test/common_plat/validation/drv/drvshmem/drvshmem.h new file mode 100644 index 0000000..12d738e --- /dev/null +++ b/test/common_plat/validation/drv/drvshmem/drvshmem.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _ODP_TEST_DRVSHMEM_H_ +#define _ODP_TEST_DRVSHMEM_H_ + +#include <odp_cunit_common.h> + +/* test functions: */ +void drvshmem_test_basic(void); +void drvshmem_test_reserve_after_fork(void); + +/* test arrays: */ +extern odp_testinfo_t drvshmem_suite[]; + +/* test registry: */ +extern odp_suiteinfo_t drvshmem_suites[]; + +/* main test program: */ +int drvshmem_main(int argc, char *argv[]); + +#endif diff --git a/test/common_plat/validation/drv/drvshmem/drvshmem_main.c b/test/common_plat/validation/drv/drvshmem/drvshmem_main.c new file mode 100644 index 0000000..566ccec --- /dev/null +++ b/test/common_plat/validation/drv/drvshmem/drvshmem_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2016, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "drvshmem.h" + +int main(int argc, char *argv[]) +{ + return drvshmem_main(argc, argv); +} diff --git a/test/linux-generic/Makefile.am b/test/linux-generic/Makefile.am index 23b8e03..2b7cbc3 100644 --- a/test/linux-generic/Makefile.am +++ b/test/linux-generic/Makefile.am @@ -35,6 +35,7 @@ TESTS = validation/api/pktio/pktio_run.sh \ $(ALL_API_VALIDATION_DIR)/shmem/shmem_main$(EXEEXT) \ $(ALL_API_VALIDATION_DIR)/system/system_main$(EXEEXT) \ $(ALL_DRV_VALIDATION_DIR)/drvatomic/drvatomic_main$(EXEEXT) \ + $(ALL_DRV_VALIDATION_DIR)/drvshmem/drvshmem_main$(EXEEXT) \ ring/ring_main$(EXEEXT) SUBDIRS += validation/api/pktio\ -- 2.7.4