@@ -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])
@@ -1,4 +1,5 @@
-ODPDRV_MODULES = drvatomic
+ODPDRV_MODULES = drvatomic \
+ drvshmem
SUBDIRS = $(ODPDRV_MODULES)
new file mode 100644
@@ -0,0 +1 @@
+drvshmem_main
new file mode 100644
@@ -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
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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);
+}
@@ -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\
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.milard@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 -- 2.7.4