Message ID | 1463734083-18267-1-git-send-email-yi.he@linaro.org |
---|---|
State | New |
Headers | show |
Linaros copyright has to be 2016 (in some places you have 2014 in other 2015). ringstress.c is new file and looks like it's pure ODP. Adding Intels copyright there is not right. Maxim. On 05/20/16 11:48, Yi He wrote: > Fixes: https://bugs.linaro.org/show_bug.cgi?id=2228 > > Convert ring test program into cunit framework > Improve LCOV coverage for linux-generic/pktio/ring.c > > Signed-off-by: Yi He <yi.he@linaro.org> > --- > platform/linux-generic/test/Makefile.am | 2 +- > platform/linux-generic/test/ring/Makefile.am | 20 +- > platform/linux-generic/test/ring/ring_basic.c | 392 ++++++++++++++++++++ > platform/linux-generic/test/ring/ring_main.c | 12 + > platform/linux-generic/test/ring/ring_stress.c | 270 ++++++++++++++ > platform/linux-generic/test/ring/ring_suites.c | 70 ++++ > platform/linux-generic/test/ring/ring_suites.h | 33 ++ > platform/linux-generic/test/ring/ringtest.c | 493 ------------------------- > 8 files changed, 787 insertions(+), 505 deletions(-) > create mode 100644 platform/linux-generic/test/ring/ring_basic.c > create mode 100644 platform/linux-generic/test/ring/ring_main.c > create mode 100644 platform/linux-generic/test/ring/ring_stress.c > create mode 100644 platform/linux-generic/test/ring/ring_suites.c > create mode 100644 platform/linux-generic/test/ring/ring_suites.h > delete mode 100644 platform/linux-generic/test/ring/ringtest.c > > diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am > index f74185d..2d58c57 100644 > --- a/platform/linux-generic/test/Makefile.am > +++ b/platform/linux-generic/test/Makefile.am > @@ -8,7 +8,7 @@ ODP_MODULES = pktio \ > if test_vald > TESTS = pktio/pktio_run.sh \ > pktio/pktio_run_tap.sh \ > - ring/ringtest$(EXEEXT) \ > + ring/ring_main$(EXEEXT) \ > shmem/shmem_linux \ > ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ > ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ > diff --git a/platform/linux-generic/test/ring/Makefile.am b/platform/linux-generic/test/ring/Makefile.am > index 5a949d0..c086584 100644 > --- a/platform/linux-generic/test/ring/Makefile.am > +++ b/platform/linux-generic/test/ring/Makefile.am > @@ -1,16 +1,14 @@ > -include $(top_srcdir)/test/validation/Makefile.inc > +include ../Makefile.inc > > -AM_CFLAGS += -I$(srcdir)/common > -AM_CFLAGS += -I$(top_srcdir)/test/validation/common > -AM_LDFLAGS += -static > +noinst_LTLIBRARIES = libtestring.la > +libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c > +libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP) > > -COMPILE_ONLY = > +test_PROGRAMS = ring_main$(EXEEXT) > +dist_ring_main_SOURCES = ring_main.c > > -TESTSCRIPTS = > +ring_main_LDFLAGS = $(AM_LDFLAGS) > +ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP) > > -EXECUTABLES = ringtest$(EXEEXT) > +noinst_HEADERS = ring_suites.h > > -test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) > - > -ringtest_SOURCES = ringtest.c > -ringtest_LDADD = $(LIBCUNIT_COMMON) $(LIBODP) > diff --git a/platform/linux-generic/test/ring/ring_basic.c b/platform/linux-generic/test/ring/ring_basic.c > new file mode 100644 > index 0000000..20d9786 > --- /dev/null > +++ b/platform/linux-generic/test/ring/ring_basic.c > @@ -0,0 +1,392 @@ > +/* Copyright (c) 2015, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/*- > + * BSD LICENSE > + * > + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in > + * the documentation and/or other materials provided with the > + * distribution. > + * * Neither the name of Intel Corporation nor the names of its > + * contributors may be used to endorse or promote products derived > + * from this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > + > +/** > + * @file > + * > + * ODP ring basic test > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > + > +#include <test_debug.h> > +#include <odp_cunit_common.h> > +#include <odp_packet_io_ring_internal.h> > + > +#include "ring_suites.h" > + > +/* labor functions declaration */ > +static void __do_basic_burst(_ring_t *r); > +static void __do_basic_bulk(_ring_t *r); > +static void __do_basic_watermark(_ring_t *r); > + > +/* dummy object pointers for enqueue and dequeue testing */ > +static void **test_enq_data; > +static void **test_deq_data; > + > +/* create two rings: one for single thread usage scenario > + * and another for multiple thread usage scenario. > + * st - single thread usage scenario > + * mt - multiple thread usage scenario > + */ > +static const char *st_ring_name = "ST basic ring"; > +static const char *mt_ring_name = "MT basic ring"; > +static _ring_t *st_ring, *mt_ring; > + > +int ring_test_basic_start(void) > +{ > + int i = 0; > + > + /* alloc dummy object pointers for enqueue testing */ > + test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *)); > + if (NULL == test_enq_data) { > + LOG_ERR("failed to allocate basic test enqeue data\n"); > + return -1; > + } > + > + for (i = 0; i < RING_SIZE * 2; i++) > + test_enq_data[i] = (void *)(unsigned long)i; > + > + /* alloc dummy object pointers for dequeue testing */ > + test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *)); > + if (NULL == test_deq_data) { > + LOG_ERR("failed to allocate basic test dequeue data\n"); > + free(test_enq_data); test_enq_data = NULL; > + return -1; > + } > + > + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > + return 0; > +} > + > +int ring_test_basic_end(void) > +{ > + free(test_enq_data); > + free(test_deq_data); > + return 0; > +} > + > +/* basic test cases */ > +void ring_test_basic_create(void) > +{ > + /* prove illegal size shall fail */ > + st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0); > + CU_ASSERT(NULL == st_ring); > + CU_ASSERT(EINVAL == __odp_errno); > + > + /* create ring for single thread usage scenario */ > + st_ring = _ring_create(st_ring_name, RING_SIZE, > + _RING_F_SP_ENQ | _RING_F_SC_DEQ); > + > + CU_ASSERT(NULL != st_ring); > + CU_ASSERT(_ring_lookup(st_ring_name) == st_ring); > + > + /* create ring for multiple thread usage scenario */ > + mt_ring = _ring_create(mt_ring_name, RING_SIZE, > + 0 /* not used, alignement > + taken care inside function: todo */); > + > + CU_ASSERT(NULL != mt_ring); > + CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring); > +} > + > +void ring_test_basic_burst(void) > +{ > + /* two rounds to cover both single > + * thread and multiple thread APIs > + */ > + __do_basic_burst(st_ring); > + __do_basic_burst(mt_ring); > +} > + > +void ring_test_basic_bulk(void) > +{ > + __do_basic_bulk(st_ring); > + __do_basic_bulk(mt_ring); > +} > + > +void ring_test_basic_watermark(void) > +{ > + __do_basic_watermark(st_ring); > + __do_basic_watermark(mt_ring); > +} > + > +/* labor functions definition */ > +static void __do_basic_burst(_ring_t *r) > +{ > + int result = 0; > + unsigned int count = 0; > + void * const *source = test_enq_data; > + void * const *dest = test_deq_data; > + void **enq = NULL, **deq = NULL; > + > + enq = test_enq_data; deq = test_deq_data; > + > + /* ring is empty */ > + CU_ASSERT(1 == _ring_empty(r)); > + > + /* enqueue 1 object */ > + result = _ring_enqueue_burst(r, enq, 1); > + enq += 1; > + CU_ASSERT(1 == (result & _RING_SZ_MASK)); > + > + /* enqueue 2 objects */ > + result = _ring_enqueue_burst(r, enq, 2); > + enq += 2; > + CU_ASSERT(2 == (result & _RING_SZ_MASK)); > + > + /* enqueue HALF_BULK objects */ > + result = _ring_enqueue_burst(r, enq, HALF_BULK); > + enq += HALF_BULK; > + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); > + > + /* ring is neither empty nor full */ > + CU_ASSERT(0 == _ring_full(r)); > + CU_ASSERT(0 == _ring_empty(r)); > + > + /* _ring_count() equals enqueued */ > + count = (1 + 2 + HALF_BULK); > + CU_ASSERT(count == _ring_count(r)); > + /* _ring_free_count() equals rooms left */ > + count = (RING_SIZE - 1) - count; > + CU_ASSERT(count == _ring_free_count(r)); > + > + /* exceed the size, enquene as many as possible */ > + result = _ring_enqueue_burst(r, enq, HALF_BULK); > + enq += count; > + CU_ASSERT(count == (result & _RING_SZ_MASK)); > + CU_ASSERT(1 == _ring_full(r)); > + > + /* dequeue 1 object */ > + result = _ring_dequeue_burst(r, deq, 1); > + deq += 1; > + CU_ASSERT(1 == (result & _RING_SZ_MASK)); > + > + /* dequeue 2 objects */ > + result = _ring_dequeue_burst(r, deq, 2); > + deq += 2; > + CU_ASSERT(2 == (result & _RING_SZ_MASK)); > + > + /* dequeue HALF_BULK objects */ > + result = _ring_dequeue_burst(r, deq, HALF_BULK); > + deq += HALF_BULK; > + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); > + > + /* _ring_free_count() equals dequeued */ > + count = (1 + 2 + HALF_BULK); > + CU_ASSERT(count == _ring_free_count(r)); > + /* _ring_count() equals remained left */ > + count = (RING_SIZE - 1) - count; > + CU_ASSERT(count == _ring_count(r)); > + > + /* underrun the size, dequeue as many as possible */ > + result = _ring_dequeue_burst(r, deq, HALF_BULK); > + deq += count; > + CU_ASSERT(count == (result & _RING_SZ_MASK)); > + CU_ASSERT(1 == _ring_empty(r)); > + > + /* check data */ > + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > + > + /* reset dequeue data */ > + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > +} > + > +/* incomplete ring API set: strange! > + * complement _ring_enqueue/dequeue_bulk to improve coverage > + */ > +static inline int __ring_enqueue_bulk( > + _ring_t *r, void * const *objects, unsigned bulk) > +{ > + if (r->prod.sp_enqueue) > + return _ring_sp_enqueue_bulk(r, objects, bulk); > + else > + return _ring_mp_enqueue_bulk(r, objects, bulk); > +} > + > +static inline int __ring_dequeue_bulk( > + _ring_t *r, void **objects, unsigned bulk) > +{ > + if (r->cons.sc_dequeue) > + return _ring_sc_dequeue_bulk(r, objects, bulk); > + else > + return _ring_mc_dequeue_bulk(r, objects, bulk); > +} > + > +static void __do_basic_bulk(_ring_t *r) > +{ > + int result = 0; > + unsigned int count = 0; > + void * const *source = test_enq_data; > + void * const *dest = test_deq_data; > + void **enq = NULL, **deq = NULL; > + > + enq = test_enq_data; deq = test_deq_data; > + > + /* ring is empty */ > + CU_ASSERT(1 == _ring_empty(r)); > + > + /* enqueue 1 object */ > + result = __ring_enqueue_bulk(r, enq, 1); > + enq += 1; > + CU_ASSERT(0 == result); > + > + /* enqueue 2 objects */ > + result = __ring_enqueue_bulk(r, enq, 2); > + enq += 2; > + CU_ASSERT(0 == result); > + > + /* enqueue HALF_BULK objects */ > + result = __ring_enqueue_bulk(r, enq, HALF_BULK); > + enq += HALF_BULK; > + CU_ASSERT(0 == result); > + > + /* ring is neither empty nor full */ > + CU_ASSERT(0 == _ring_full(r)); > + CU_ASSERT(0 == _ring_empty(r)); > + > + /* _ring_count() equals enqueued */ > + count = (1 + 2 + HALF_BULK); > + CU_ASSERT(count == _ring_count(r)); > + /* _ring_free_count() equals rooms left */ > + count = (RING_SIZE - 1) - count; > + CU_ASSERT(count == _ring_free_count(r)); > + > + /* exceed the size, enquene shall fail with -ENOBUFS */ > + result = __ring_enqueue_bulk(r, enq, HALF_BULK); > + CU_ASSERT(-ENOBUFS == result); > + > + /* fullful the ring */ > + result = __ring_enqueue_bulk(r, enq, count); > + enq += count; > + CU_ASSERT(0 == result); > + CU_ASSERT(1 == _ring_full(r)); > + > + /* dequeue 1 object */ > + result = __ring_dequeue_bulk(r, deq, 1); > + deq += 1; > + CU_ASSERT(0 == result); > + > + /* dequeue 2 objects */ > + result = __ring_dequeue_bulk(r, deq, 2); > + deq += 2; > + CU_ASSERT(0 == result); > + > + /* dequeue HALF_BULK objects */ > + result = __ring_dequeue_bulk(r, deq, HALF_BULK); > + deq += HALF_BULK; > + CU_ASSERT(0 == result); > + > + /* _ring_free_count() equals dequeued */ > + count = (1 + 2 + HALF_BULK); > + CU_ASSERT(count == _ring_free_count(r)); > + /* _ring_count() equals remained left */ > + count = (RING_SIZE - 1) - count; > + CU_ASSERT(count == _ring_count(r)); > + > + /* underrun the size, dequeue shall fail with -ENOENT */ > + result = __ring_dequeue_bulk(r, deq, HALF_BULK); > + CU_ASSERT(-ENOENT == result); > + > + /* empty the queue */ > + result = __ring_dequeue_bulk(r, deq, count); > + deq += count; > + CU_ASSERT(0 == result); > + CU_ASSERT(1 == _ring_empty(r)); > + > + /* check data */ > + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > + > + /* reset dequeue data */ > + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > +} > + > +void __do_basic_watermark(_ring_t *r) > +{ > + int result = 0; > + void * const *source = test_enq_data; > + void * const *dest = test_deq_data; > + void **enq = NULL, **deq = NULL; > + > + enq = test_enq_data; deq = test_deq_data; > + > + /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */ > + const unsigned watermark = PIECE_BULK; > + const unsigned bulk = (watermark / 4) * 3; > + > + /* watermark cannot exceed ring size */ > + result = _ring_set_water_mark(r, ILLEGAL_SIZE); > + CU_ASSERT(-EINVAL == result); > + > + /* set watermark */ > + result = _ring_set_water_mark(r, watermark); > + CU_ASSERT(0 == result); > + > + /* 1st enqueue shall succeed */ > + result = __ring_enqueue_bulk(r, enq, bulk); > + enq += bulk; > + CU_ASSERT(0 == result); > + > + /* 2nd enqueue shall succeed but return -EDQUOT */ > + result = __ring_enqueue_bulk(r, enq, bulk); > + enq += bulk; > + CU_ASSERT(-EDQUOT == result); > + > + /* dequeue 1st bulk */ > + result = __ring_dequeue_bulk(r, deq, bulk); > + deq += bulk; > + CU_ASSERT(0 == result); > + > + /* dequeue 2nd bulk */ > + result = __ring_dequeue_bulk(r, deq, bulk); > + deq += bulk; > + CU_ASSERT(0 == result); > + > + /* check data */ > + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > + > + /* reset watermark */ > + result = _ring_set_water_mark(r, 0); > + CU_ASSERT(0 == result); > + > + /* reset dequeue data */ > + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > +} > diff --git a/platform/linux-generic/test/ring/ring_main.c b/platform/linux-generic/test/ring/ring_main.c > new file mode 100644 > index 0000000..e465113 > --- /dev/null > +++ b/platform/linux-generic/test/ring/ring_main.c > @@ -0,0 +1,12 @@ > +/* Copyright (c) 2015, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include "ring_suites.h" > + > +int main(void) > +{ > + return ring_suites_main(); > +} > diff --git a/platform/linux-generic/test/ring/ring_stress.c b/platform/linux-generic/test/ring/ring_stress.c > new file mode 100644 > index 0000000..a4753e9 > --- /dev/null > +++ b/platform/linux-generic/test/ring/ring_stress.c > @@ -0,0 +1,270 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +/*- > + * BSD LICENSE > + * > + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * > + * * Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * * Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in > + * the documentation and/or other materials provided with the > + * distribution. > + * * Neither the name of Intel Corporation nor the names of its > + * contributors may be used to endorse or promote products derived > + * from this software without specific prior written permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + */ > + > +/** > + * @file > + * > + * ODP ring stress test > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > + > +#include <odp_api.h> > +#include <odp/helper/linux.h> > +#include <odp_packet_io_ring_internal.h> > +#include <test_debug.h> > +#include <odp_cunit_common.h> > + > +#include "ring_suites.h" > + > +/* > + * Since cunit framework cannot work with multi-threading, ask workers > + * to save their results for delayed assertion after thread collection. > + */ > +static int worker_results[MAX_WORKERS]; > + > +/* > + * Note : make sure that both enqueue and dequeue > + * operation starts at same time so to avoid data corruption > + * Its because atomic lock will protect only indexes, but if order of > + * read or write operation incorrect then data mismatch will happen > + * So its resposibility of application develop to take care of order of > + * data read or write. > + */ > +typedef enum { > + STRESS_1_1_PRODUCER_CONSUMER, > + STRESS_1_N_PRODUCER_CONSUMER, > + STRESS_N_1_PRODUCER_CONSUMER, > + STRESS_N_M_PRODUCER_CONSUMER > +} stress_case_t; > + > +/* worker function declarations */ > +static void *stress_worker(void *_data); > + > +/* global name for later look up in workers' context */ > +static const char *ring_name = "stress ring"; > + > +int ring_test_stress_start(void) > +{ > + /* multiple thread usage scenario only */ > + _ring_t *r_stress = _ring_create(ring_name, RING_SIZE, > + 0 /* not used, alignement > + taken care inside function: todo */); > + if (r_stress == NULL) { > + LOG_ERR("create ring failed for stress.\n"); > + return -1; > + } > + > + return 0; > +} > + > +void ring_test_stress_1_1_producer_consumer(void) > +{ > + int i = 0; > + odp_cpumask_t cpus; > + pthrd_arg worker_param; > + > + /* reset results for delayed assertion */ > + memset(worker_results, 0, sizeof(worker_results)); > + > + /* request 2 threads to run 1:1 stress */ > + worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2); > + worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER; > + > + /* not failure, insufficient resource */ > + if (worker_param.numthrds < 2) { > + LOG_ERR("insufficient cpu for 1:1 " > + "producer/consumer stress.\n"); > + return; > + } > + > + /* kick the workers */ > + odp_cunit_thread_create(stress_worker, &worker_param); > + > + /* collect the results */ > + odp_cunit_thread_exit(&worker_param); > + > + /* delayed assertion due to cunit limitation */ > + for (i = 0; i < worker_param.numthrds; i++) > + CU_ASSERT(0 == worker_results[i]); > +} > + > +void ring_test_stress_N_M_producer_consumer(void) > +{ > + int i = 0; > + odp_cpumask_t cpus; > + pthrd_arg worker_param; > + > + /* reset results for delayed assertion */ > + memset(worker_results, 0, sizeof(worker_results)); > + > + /* request MAX_WORKERS threads to run N:M stress */ > + worker_param.numthrds = > + odp_cpumask_default_worker(&cpus, MAX_WORKERS); > + worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER; > + > + /* not failure, insufficient resource */ > + if (worker_param.numthrds < 3) { > + LOG_ERR("insufficient cpu for N:M " > + "producer/consumer stress.\n"); > + return; > + } > + > + /* kick the workers */ > + odp_cunit_thread_create(stress_worker, &worker_param); > + > + /* collect the results */ > + odp_cunit_thread_exit(&worker_param); > + > + /* delayed assertion due to cunit limitation */ > + for (i = 0; i < worker_param.numthrds; i++) > + CU_ASSERT(0 == worker_results[i]); > +} > + > +void ring_test_stress_1_N_producer_consumer(void) > +{ > +} > + > +void ring_test_stress_N_1_producer_consumer(void) > +{ > +} > + > +void ring_test_stress_ring_list_dump(void) > +{ > + /* improve code coverage */ > + _ring_list_dump(); > +} > + > +/* worker function for multiple producer instances */ > +static int do_producer(_ring_t *r) > +{ > + int i, result = 0; > + void **enq = NULL; > + > + /* allocate dummy object pointers for enqueue */ > + enq = malloc(PIECE_BULK * 2 * sizeof(void *)); > + if (NULL == enq) { > + LOG_ERR("insufficient memory for producer enqueue.\n"); > + return 0; /* not failure, skip for insufficient memory */ > + } > + > + /* data pattern to be evaluated later in consumer */ > + for (i = 0; i < PIECE_BULK; i++) > + enq[i] = (void *)(unsigned long)i; > + > + do { > + result = _ring_mp_enqueue_bulk(r, enq, PIECE_BULK); > + if (0 == result) { > + free(enq); > + return 0; > + } > + } while (1); > +} > + > +/* worker function for multiple consumer instances */ > +static int do_consumer(_ring_t *r) > +{ > + int i, result = 0; > + void **deq = NULL; > + const char *message = "test OK!"; > + const char *mismatch = "data mismatch..lockless enq/deq failed."; > + > + /* allocate dummy object pointers for dequeue */ > + deq = malloc(PIECE_BULK * 2 * sizeof(void *)); > + if (NULL == deq) { > + LOG_ERR("insufficient memory for consumer dequeue.\n"); > + return 0; /* not failure, skip for insufficient memory */ > + } > + > + do { > + result = _ring_mc_dequeue_bulk(r, deq, PIECE_BULK); > + if (0 == result) { > + /* evaluate the data pattern */ > + for (i = 0; i < PIECE_BULK; i++) { > + if (deq[i] != (void *)(unsigned long)i) { > + result = -1; > + message = mismatch; > + break; > + } > + } > + > + free(deq); > + LOG_ERR("%s\n", message); > + return result; > + } > + } while (1); > +} > + > +static void *stress_worker(void *_data) > +{ > + pthrd_arg *worker_param = (pthrd_arg *)_data; > + _ring_t *r_stress = NULL; > + > + int worker_id = odp_thread_id(); > + /* save the worker result for delayed assertion */ > + int *result = &worker_results[(worker_id % worker_param->numthrds)]; > + > + /* verify ring lookup in worker context */ > + r_stress = _ring_lookup(ring_name); > + if (NULL == r_stress) { > + LOG_ERR("ring lookup %s not found\n", ring_name); > + *result = -1; > + return NULL; > + } > + > + switch (worker_param->testcase) { > + case STRESS_1_1_PRODUCER_CONSUMER: > + case STRESS_N_M_PRODUCER_CONSUMER: > + /* interleaved producer/consumer */ > + if (0 == (worker_id % 2)) > + *result = do_producer(r_stress); > + else if (1 == (worker_id % 2)) > + *result = do_consumer(r_stress); > + break; > + case STRESS_1_N_PRODUCER_CONSUMER: > + case STRESS_N_1_PRODUCER_CONSUMER: > + default: > + LOG_ERR("invalid or not-implemented stress type (%d)\n", > + worker_param->testcase); > + break; > + } > + return NULL; > +} > diff --git a/platform/linux-generic/test/ring/ring_suites.c b/platform/linux-generic/test/ring/ring_suites.c > new file mode 100644 > index 0000000..b310843 > --- /dev/null > +++ b/platform/linux-generic/test/ring/ring_suites.c > @@ -0,0 +1,70 @@ > +/* Copyright (c) 2015, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include <stdlib.h> > +#include <stdio.h> > +#include <string.h> > + > +#include <odp_api.h> > +#include <test_debug.h> > +#include <odp_cunit_common.h> > +#include <odp_packet_io_ring_internal.h> > + > +#include "ring_suites.h" > + > +static int ring_suites_init(odp_instance_t *inst) > +{ > + if (0 != odp_init_global(inst, NULL, NULL)) { > + LOG_ERR("error: odp_init_global() failed.\n"); > + return -1; > + } > + if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) { > + LOG_ERR("error: odp_init_local() failed.\n"); > + return -1; > + } > + > + _ring_tailq_init(); > + return 0; > +} > + > +static odp_testinfo_t ring_suite_basic[] = { > + ODP_TEST_INFO(ring_test_basic_create), > + ODP_TEST_INFO(ring_test_basic_burst), > + ODP_TEST_INFO(ring_test_basic_bulk), > + ODP_TEST_INFO(ring_test_basic_watermark), > + ODP_TEST_INFO_NULL, > +}; > + > +static odp_testinfo_t ring_suite_stress[] = { > + ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer), > + ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer), > + ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer), > + ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer), > + ODP_TEST_INFO(ring_test_stress_ring_list_dump), > + ODP_TEST_INFO_NULL, > +}; > + > +static odp_suiteinfo_t ring_suites[] = { > + {"ring basic", ring_test_basic_start, > + ring_test_basic_end, ring_suite_basic}, > + {"ring stress", ring_test_stress_start, > + NULL, ring_suite_stress}, > + ODP_SUITE_INFO_NULL > +}; > + > +int ring_suites_main(void) > +{ > + int ret; > + > + odp_cunit_register_global_init(ring_suites_init); > + > + ret = odp_cunit_register(ring_suites); > + > + if (ret == 0) > + ret = odp_cunit_run(); > + > + return ret; > +} > diff --git a/platform/linux-generic/test/ring/ring_suites.h b/platform/linux-generic/test/ring/ring_suites.h > new file mode 100644 > index 0000000..e26b6e8 > --- /dev/null > +++ b/platform/linux-generic/test/ring/ring_suites.h > @@ -0,0 +1,33 @@ > +/* Copyright (c) 2015, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#define RING_SIZE 4096 > +#define PIECE_BULK 32 > + > +#define HALF_BULK (RING_SIZE >> 1) > +#define ILLEGAL_SIZE (RING_SIZE | 0x3) > + > +/* test suite start and stop */ > +int ring_test_basic_start(void); > +int ring_test_basic_end(void); > + > +/* basic test cases */ > +void ring_test_basic_create(void); > +void ring_test_basic_burst(void); > +void ring_test_basic_bulk(void); > +void ring_test_basic_watermark(void); > + > +/* test suite start and stop */ > +int ring_test_stress_start(void); > + > +/* stress test cases */ > +void ring_test_stress_1_1_producer_consumer(void); > +void ring_test_stress_1_N_producer_consumer(void); > +void ring_test_stress_N_1_producer_consumer(void); > +void ring_test_stress_N_M_producer_consumer(void); > +void ring_test_stress_ring_list_dump(void); > + > +int ring_suites_main(void); > diff --git a/platform/linux-generic/test/ring/ringtest.c b/platform/linux-generic/test/ring/ringtest.c > deleted file mode 100644 > index ac0aa61..0000000 > --- a/platform/linux-generic/test/ring/ringtest.c > +++ /dev/null > @@ -1,493 +0,0 @@ > -/* Copyright (c) 2014, Linaro Limited > - * All rights reserved. > - * > - * SPDX-License-Identifier: BSD-3-Clause > - */ > - > -/*- > - * BSD LICENSE > - * > - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > - * All rights reserved. > - * > - * Redistribution and use in source and binary forms, with or without > - * modification, are permitted provided that the following conditions > - * are met: > - * > - * * Redistributions of source code must retain the above copyright > - * notice, this list of conditions and the following disclaimer. > - * * Redistributions in binary form must reproduce the above copyright > - * notice, this list of conditions and the following disclaimer in > - * the documentation and/or other materials provided with the > - * distribution. > - * * Neither the name of Intel Corporation nor the names of its > - * contributors may be used to endorse or promote products derived > - * from this software without specific prior written permission. > - * > - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS > - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT > - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, > - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY > - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > - */ > - > -/** > - * @file > - * > - * ODP test ring > - */ > - > -#include <stdlib.h> > -#include <stdio.h> > -#include <string.h> > - > -#include <odp_api.h> > -#include <odp/helper/linux.h> > -#include <odp_packet_io_ring_internal.h> > -#include <test_debug.h> > -#include <odp_cunit_common.h> > - > -#define RING_SIZE 4096 > -#define MAX_BULK 32 > - > -enum { > - ODP_RING_TEST_BASIC, > - ODP_RING_TEST_STRESS, > -}; > - > -/* local struct for ring_thread argument */ > -typedef struct { > - pthrd_arg thrdarg; > - int stress_type; > -} ring_arg_t; > - > -static int test_ring_basic(_ring_t *r) > -{ > - void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = NULL; > - int ret; > - unsigned i, num_elems; > - > - /* alloc dummy object pointers */ > - src = malloc(RING_SIZE * 2 * sizeof(void *)); > - if (src == NULL) { > - LOG_ERR("failed to allocate test ring src memory\n"); > - goto fail; > - } > - for (i = 0; i < RING_SIZE * 2; i++) > - src[i] = (void *)(unsigned long)i; > - > - cur_src = src; > - > - /* alloc some room for copied objects */ > - dst = malloc(RING_SIZE * 2 * sizeof(void *)); > - if (dst == NULL) { > - LOG_ERR("failed to allocate test ring dst memory\n"); > - goto fail; > - } > - > - memset(dst, 0, RING_SIZE * 2 * sizeof(void *)); > - cur_dst = dst; > - > - printf("Test SP & SC basic functions\n"); > - printf("enqueue 1 obj\n"); > - ret = _ring_sp_enqueue_burst(r, cur_src, 1); > - cur_src += 1; > - if ((ret & _RING_SZ_MASK) != 1) { > - LOG_ERR("sp_enq for 1 obj failed\n"); > - goto fail; > - } > - > - printf("enqueue 2 objs\n"); > - ret = _ring_sp_enqueue_burst(r, cur_src, 2); > - cur_src += 2; > - if ((ret & _RING_SZ_MASK) != 2) { > - LOG_ERR("sp_enq for 2 obj failed\n"); > - goto fail; > - } > - > - printf("enqueue MAX_BULK objs\n"); > - ret = _ring_sp_enqueue_burst(r, cur_src, MAX_BULK); > - if ((ret & _RING_SZ_MASK) != MAX_BULK) { > - LOG_ERR("sp_enq for %d obj failed\n", MAX_BULK); > - goto fail; > - } > - > - printf("dequeue 1 obj\n"); > - ret = _ring_sc_dequeue_burst(r, cur_dst, 1); > - cur_dst += 1; > - if ((ret & _RING_SZ_MASK) != 1) { > - LOG_ERR("sc_deq for 1 obj failed\n"); > - goto fail; > - } > - > - printf("dequeue 2 objs\n"); > - ret = _ring_sc_dequeue_burst(r, cur_dst, 2); > - cur_dst += 2; > - if ((ret & _RING_SZ_MASK) != 2) { > - LOG_ERR("sc_deq for 2 obj failed\n"); > - goto fail; > - } > - > - printf("dequeue MAX_BULK objs\n"); > - ret = _ring_sc_dequeue_burst(r, cur_dst, MAX_BULK); > - cur_dst += MAX_BULK; > - if ((ret & _RING_SZ_MASK) != MAX_BULK) { > - LOG_ERR("sc_deq for %d obj failed\n", MAX_BULK); > - goto fail; > - } > - > - /* check data */ > - if (memcmp(src, dst, cur_dst - dst)) { > - LOG_ERR("data after dequeue is not the same\n"); > - goto fail; > - } > - > - cur_src = src; > - cur_dst = dst; > - > - printf("Test MP & MC basic functions\n"); > - > - printf("enqueue 1 obj\n"); > - ret = _ring_mp_enqueue_bulk(r, cur_src, 1); > - cur_src += 1; > - if (ret != 0) { > - LOG_ERR("mp_enq for 1 obj failed\n"); > - goto fail; > - } > - printf("enqueue 2 objs\n"); > - ret = _ring_mp_enqueue_bulk(r, cur_src, 2); > - cur_src += 2; > - if (ret != 0) { > - LOG_ERR("mp_enq for 2 obj failed\n"); > - goto fail; > - } > - printf("enqueue MAX_BULK objs\n"); > - ret = _ring_mp_enqueue_bulk(r, cur_src, MAX_BULK); > - if (ret != 0) { > - LOG_ERR("mp_enq for %d obj failed\n", MAX_BULK); > - goto fail; > - } > - printf("dequeue 1 obj\n"); > - ret = _ring_mc_dequeue_bulk(r, cur_dst, 1); > - cur_dst += 1; > - if (ret != 0) { > - LOG_ERR("mc_deq for 1 obj failed\n"); > - goto fail; > - } > - printf("dequeue 2 objs\n"); > - ret = _ring_mc_dequeue_bulk(r, cur_dst, 2); > - cur_dst += 2; > - if (ret != 0) { > - LOG_ERR("mc_deq for 2 obj failed\n"); > - goto fail; > - } > - printf("dequeue MAX_BULK objs\n"); > - ret = _ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK); > - cur_dst += MAX_BULK; > - if (ret != 0) { > - LOG_ERR("mc_deq for %d obj failed\n", MAX_BULK); > - goto fail; > - } > - /* check data */ > - if (memcmp(src, dst, cur_dst - dst)) { > - LOG_ERR("data after dequeue is not the same\n"); > - goto fail; > - } > - > - printf("test watermark and default bulk enqueue / dequeue\n"); > - _ring_set_water_mark(r, 20); > - num_elems = 16; > - > - cur_src = src; > - cur_dst = dst; > - > - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); > - cur_src += num_elems; > - if (ret != 0) { > - LOG_ERR("Cannot enqueue\n"); > - goto fail; > - } > - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); > - if (ret != -EDQUOT) { > - LOG_ERR("Watermark not exceeded\n"); > - goto fail; > - } > - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); > - cur_dst += num_elems; > - if (ret != 0) { > - LOG_ERR("Cannot dequeue\n"); > - goto fail; > - } > - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); > - cur_dst += num_elems; > - if (ret != 0) { > - LOG_ERR("Cannot dequeue2\n"); > - goto fail; > - } > - > - /* check data */ > - if (memcmp(src, dst, cur_dst - dst)) { > - LOG_ERR("data after dequeue is not the same\n"); > - goto fail; > - } > - > - printf("basic enqueu, dequeue test for ring <%s>@%p passed\n", > - r->name, r); > - > - free(src); > - free(dst); > - return 0; > - > -fail: > - free(src); > - free(dst); > - return -1; > -} > - > -/* global shared ring used for stress testing */ > -static _ring_t *r_stress; > - > -/* Stress func for Multi producer only */ > -static int producer_fn(void) > -{ > - unsigned i; > - > - void **src = NULL; > - > - /* alloc dummy object pointers */ > - src = malloc(MAX_BULK * 2 * sizeof(void *)); > - if (src == NULL) { > - LOG_ERR("failed to allocate producer memory.\n"); > - return -1; > - } > - for (i = 0; i < MAX_BULK; i++) > - src[i] = (void *)(unsigned long)i; > - > - do { > - i = _ring_mp_enqueue_bulk(r_stress, src, MAX_BULK); > - if (i == 0) { > - free(src); > - return 0; > - } > - } while (1); > -} > - > -/* Stress func for Multi consumer only */ > -static int consumer_fn(void) > -{ > - unsigned i; > - void **src = NULL; > - > - /* alloc dummy object pointers */ > - src = malloc(MAX_BULK * 2 * sizeof(void *)); > - if (src == NULL) { > - LOG_ERR("failed to allocate consumer memory.\n"); > - return -1; > - } > - > - do { > - i = _ring_mc_dequeue_bulk(r_stress, src, MAX_BULK); > - if (i == 0) { > - for (i = 0; i < MAX_BULK; i++) { > - if (src[i] != (void *)(unsigned long)i) { > - free(src); > - printf("data mismatch.. lockless ops fail\n"); > - return -1; > - } > - } > - free(src); > - printf("\n Test OK !\n"); > - return 0; > - } > - } while (1); > -} > - > -/* > - * Note : make sure that both enqueue and dequeue > - * operation starts at same time so to avoid data corruption > - * Its because atomic lock will protect only indexes, but if order of > - * read or write operation incorrect then data mismatch will happen > - * So its resposibility of application develop to take care of order of > - * data read or write. > -*/ > -typedef enum { > - one_enq_one_deq, /* One thread to enqueue one to > - dequeu at same time */ > - one_enq_rest_deq, /* one thread to enq rest to > - dequeue at same time */ > - one_deq_rest_enq, /* one to deq and rest enq at very same time */ > - multi_enq_multi_deq /* multiple enq,deq */ > -} stress_type_t; > - > -static void test_ring_stress(stress_type_t type) > -{ > - int thr; > - > - thr = odp_thread_id(); > - > - switch (type) { > - case one_enq_one_deq: > - if (thr == 1) > - producer_fn(); > - if (thr == 2) > - consumer_fn(); > - break; > - case multi_enq_multi_deq: > - if (thr % 2 == 0) > - producer_fn(); > - else > - consumer_fn(); > - break; > - case one_deq_rest_enq: > - case one_enq_rest_deq:/*TBD*/ > - default: > - LOG_ERR("Invalid stress type or test case yet not supported\n"); > - } > -} > - > -static void *test_ring(void *arg) > -{ > - ring_arg_t *parg = (ring_arg_t *)arg; > - int thr; > - char ring_name[_RING_NAMESIZE]; > - _ring_t *r; > - int result = 0; > - > - thr = odp_thread_id(); > - > - printf("Thread %i starts\n", thr); > - > - switch (parg->thrdarg.testcase) { > - case ODP_RING_TEST_BASIC: > - snprintf(ring_name, sizeof(ring_name), "test_ring_%i", thr); > - > - r = _ring_create(ring_name, RING_SIZE, > - 0 /* not used, alignement > - taken care inside func : todo */); > - if (r == NULL) { > - LOG_ERR("ring create failed\n"); > - result = -1; > - break; > - } > - /* lookup ring from its name */ > - if (_ring_lookup(ring_name) != r) { > - LOG_ERR("ring lookup failed\n"); > - result = -1; > - break; > - } > - > - /* basic operations */ > - if (test_ring_basic(r) < 0) { > - LOG_ERR("ring basic enqueue/dequeu ops failed\n"); > - result = -1; > - } > - > - if (result) > - _ring_list_dump(); > - > - break; > - > - case ODP_RING_TEST_STRESS: > - test_ring_stress(parg->stress_type); > - > - if (result) > - _ring_list_dump(); > - break; > - > - default: > - LOG_ERR("Invalid test case [%d]\n", parg->thrdarg.testcase); > - result = -1; > - break; > - } > - > - LOG_DBG("result = %d\n", result); > - if (result == 0) > - printf("test_ring Result:pass\n"); > - else > - printf("test_ring Result:fail\n"); > - > - fflush(stdout); > - > - return parg; > -} > - > -int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED) > -{ > - ring_arg_t rarg; > - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; > - odp_cpumask_t cpu_mask; > - int num_workers; > - char ring_name[_RING_NAMESIZE]; > - odp_instance_t instance; > - odph_linux_thr_params_t thr_params; > - > - if (odp_init_global(&instance, NULL, NULL)) { > - LOG_ERR("Error: ODP global init failed.\n"); > - exit(EXIT_FAILURE); > - } > - > - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { > - LOG_ERR("Error: ODP local init failed.\n"); > - exit(EXIT_FAILURE); > - } > - > - _ring_tailq_init(); > - > - num_workers = odp_cpumask_default_worker(&cpu_mask, MAX_WORKERS); > - rarg.thrdarg.numthrds = rarg.thrdarg.numthrds; > - > - rarg.thrdarg.testcase = ODP_RING_TEST_BASIC; > - > - memset(&thr_params, 0, sizeof(thr_params)); > - thr_params.start = test_ring; > - thr_params.arg = &rarg; > - thr_params.thr_type = ODP_THREAD_WORKER; > - thr_params.instance = instance; > - > - printf("starting stess test type : %d..\n", rarg.stress_type); > - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); > - odph_linux_pthread_join(thread_tbl, num_workers); > - > - rarg.thrdarg.testcase = ODP_RING_TEST_STRESS; > - rarg.stress_type = one_enq_one_deq; > - > - printf("starting stess test type : %d..\n", rarg.stress_type); > - snprintf(ring_name, sizeof(ring_name), "test_ring_stress"); > - r_stress = _ring_create(ring_name, RING_SIZE, > - 0/* not used, alignement > - taken care inside func : todo */); > - if (r_stress == NULL) { > - LOG_ERR("ring create failed\n"); > - goto fail; > - } > - /* lookup ring from its name */ > - if (_ring_lookup(ring_name) != r_stress) { > - LOG_ERR("ring lookup failed\n"); > - goto fail; > - } > - > - thr_params.start = test_ring; > - thr_params.arg = &rarg; > - > - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); > - odph_linux_pthread_join(thread_tbl, num_workers); > - > -fail: > - if (odp_term_local()) { > - LOG_ERR("Error: ODP local term failed.\n"); > - exit(EXIT_FAILURE); > - } > - > - if (odp_term_global(instance)) { > - LOG_ERR("Error: ODP global term failed.\n"); > - exit(EXIT_FAILURE); > - } > - > - return 0; > -}
I concur with Maxim on the copyrights but other than that: Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org> Note that I'm unable to get this test to fail, so this may also be a fix to the issue discussed in https://lists.linaro.org/pipermail/lng-odp/2016-May/023518.html Might need to resolve conflicts between this patch and Christophe's changes (I haven't tested to see what conflicts may exist). On Fri, May 20, 2016 at 7:59 AM, Maxim Uvarov <maxim.uvarov@linaro.org> wrote: > Linaros copyright has to be 2016 (in some places you have 2014 in other > 2015). > > ringstress.c is new file and looks like it's pure ODP. Adding Intels > copyright there is not right. > > Maxim. > > > On 05/20/16 11:48, Yi He wrote: > >> Fixes: https://bugs.linaro.org/show_bug.cgi?id=2228 >> >> Convert ring test program into cunit framework >> Improve LCOV coverage for linux-generic/pktio/ring.c >> >> Signed-off-by: Yi He <yi.he@linaro.org> >> --- >> platform/linux-generic/test/Makefile.am | 2 +- >> platform/linux-generic/test/ring/Makefile.am | 20 +- >> platform/linux-generic/test/ring/ring_basic.c | 392 >> ++++++++++++++++++++ >> platform/linux-generic/test/ring/ring_main.c | 12 + >> platform/linux-generic/test/ring/ring_stress.c | 270 ++++++++++++++ >> platform/linux-generic/test/ring/ring_suites.c | 70 ++++ >> platform/linux-generic/test/ring/ring_suites.h | 33 ++ >> platform/linux-generic/test/ring/ringtest.c | 493 >> ------------------------- >> 8 files changed, 787 insertions(+), 505 deletions(-) >> create mode 100644 platform/linux-generic/test/ring/ring_basic.c >> create mode 100644 platform/linux-generic/test/ring/ring_main.c >> create mode 100644 platform/linux-generic/test/ring/ring_stress.c >> create mode 100644 platform/linux-generic/test/ring/ring_suites.c >> create mode 100644 platform/linux-generic/test/ring/ring_suites.h >> delete mode 100644 platform/linux-generic/test/ring/ringtest.c >> >> diff --git a/platform/linux-generic/test/Makefile.am >> b/platform/linux-generic/test/Makefile.am >> index f74185d..2d58c57 100644 >> --- a/platform/linux-generic/test/Makefile.am >> +++ b/platform/linux-generic/test/Makefile.am >> @@ -8,7 +8,7 @@ ODP_MODULES = pktio \ >> if test_vald >> TESTS = pktio/pktio_run.sh \ >> pktio/pktio_run_tap.sh \ >> - ring/ringtest$(EXEEXT) \ >> + ring/ring_main$(EXEEXT) \ >> shmem/shmem_linux \ >> ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ >> ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ >> diff --git a/platform/linux-generic/test/ring/Makefile.am >> b/platform/linux-generic/test/ring/Makefile.am >> index 5a949d0..c086584 100644 >> --- a/platform/linux-generic/test/ring/Makefile.am >> +++ b/platform/linux-generic/test/ring/Makefile.am >> @@ -1,16 +1,14 @@ >> -include $(top_srcdir)/test/validation/Makefile.inc >> +include ../Makefile.inc >> -AM_CFLAGS += -I$(srcdir)/common >> -AM_CFLAGS += -I$(top_srcdir)/test/validation/common >> -AM_LDFLAGS += -static >> +noinst_LTLIBRARIES = libtestring.la >> +libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c >> +libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP) >> -COMPILE_ONLY = >> +test_PROGRAMS = ring_main$(EXEEXT) >> +dist_ring_main_SOURCES = ring_main.c >> -TESTSCRIPTS = >> +ring_main_LDFLAGS = $(AM_LDFLAGS) >> +ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP) >> -EXECUTABLES = ringtest$(EXEEXT) >> +noinst_HEADERS = ring_suites.h >> -test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) >> - >> -ringtest_SOURCES = ringtest.c >> -ringtest_LDADD = $(LIBCUNIT_COMMON) $(LIBODP) >> diff --git a/platform/linux-generic/test/ring/ring_basic.c >> b/platform/linux-generic/test/ring/ring_basic.c >> new file mode 100644 >> index 0000000..20d9786 >> --- /dev/null >> +++ b/platform/linux-generic/test/ring/ring_basic.c >> @@ -0,0 +1,392 @@ >> +/* Copyright (c) 2015, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +/*- >> + * BSD LICENSE >> + * >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> + * All rights reserved. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions >> + * are met: >> + * >> + * * Redistributions of source code must retain the above copyright >> + * notice, this list of conditions and the following disclaimer. >> + * * Redistributions in binary form must reproduce the above >> copyright >> + * notice, this list of conditions and the following disclaimer in >> + * the documentation and/or other materials provided with the >> + * distribution. >> + * * Neither the name of Intel Corporation nor the names of its >> + * contributors may be used to endorse or promote products derived >> + * from this software without specific prior written permission. >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> FOR >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> INCIDENTAL, >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> USE, >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> ANY >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> USE >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >> + */ >> + >> +/** >> + * @file >> + * >> + * ODP ring basic test >> + */ >> + >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <string.h> >> + >> +#include <test_debug.h> >> +#include <odp_cunit_common.h> >> +#include <odp_packet_io_ring_internal.h> >> + >> +#include "ring_suites.h" >> + >> +/* labor functions declaration */ >> +static void __do_basic_burst(_ring_t *r); >> +static void __do_basic_bulk(_ring_t *r); >> +static void __do_basic_watermark(_ring_t *r); >> + >> +/* dummy object pointers for enqueue and dequeue testing */ >> +static void **test_enq_data; >> +static void **test_deq_data; >> + >> +/* create two rings: one for single thread usage scenario >> + * and another for multiple thread usage scenario. >> + * st - single thread usage scenario >> + * mt - multiple thread usage scenario >> + */ >> +static const char *st_ring_name = "ST basic ring"; >> +static const char *mt_ring_name = "MT basic ring"; >> +static _ring_t *st_ring, *mt_ring; >> + >> +int ring_test_basic_start(void) >> +{ >> + int i = 0; >> + >> + /* alloc dummy object pointers for enqueue testing */ >> + test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *)); >> + if (NULL == test_enq_data) { >> + LOG_ERR("failed to allocate basic test enqeue data\n"); >> + return -1; >> + } >> + >> + for (i = 0; i < RING_SIZE * 2; i++) >> + test_enq_data[i] = (void *)(unsigned long)i; >> + >> + /* alloc dummy object pointers for dequeue testing */ >> + test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *)); >> + if (NULL == test_deq_data) { >> + LOG_ERR("failed to allocate basic test dequeue data\n"); >> + free(test_enq_data); test_enq_data = NULL; >> + return -1; >> + } >> + >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> + return 0; >> +} >> + >> +int ring_test_basic_end(void) >> +{ >> + free(test_enq_data); >> + free(test_deq_data); >> + return 0; >> +} >> + >> +/* basic test cases */ >> +void ring_test_basic_create(void) >> +{ >> + /* prove illegal size shall fail */ >> + st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0); >> + CU_ASSERT(NULL == st_ring); >> + CU_ASSERT(EINVAL == __odp_errno); >> + >> + /* create ring for single thread usage scenario */ >> + st_ring = _ring_create(st_ring_name, RING_SIZE, >> + _RING_F_SP_ENQ | _RING_F_SC_DEQ); >> + >> + CU_ASSERT(NULL != st_ring); >> + CU_ASSERT(_ring_lookup(st_ring_name) == st_ring); >> + >> + /* create ring for multiple thread usage scenario */ >> + mt_ring = _ring_create(mt_ring_name, RING_SIZE, >> + 0 /* not used, alignement >> + taken care inside function: todo */); >> + >> + CU_ASSERT(NULL != mt_ring); >> + CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring); >> +} >> + >> +void ring_test_basic_burst(void) >> +{ >> + /* two rounds to cover both single >> + * thread and multiple thread APIs >> + */ >> + __do_basic_burst(st_ring); >> + __do_basic_burst(mt_ring); >> +} >> + >> +void ring_test_basic_bulk(void) >> +{ >> + __do_basic_bulk(st_ring); >> + __do_basic_bulk(mt_ring); >> +} >> + >> +void ring_test_basic_watermark(void) >> +{ >> + __do_basic_watermark(st_ring); >> + __do_basic_watermark(mt_ring); >> +} >> + >> +/* labor functions definition */ >> +static void __do_basic_burst(_ring_t *r) >> +{ >> + int result = 0; >> + unsigned int count = 0; >> + void * const *source = test_enq_data; >> + void * const *dest = test_deq_data; >> + void **enq = NULL, **deq = NULL; >> + >> + enq = test_enq_data; deq = test_deq_data; >> + >> + /* ring is empty */ >> + CU_ASSERT(1 == _ring_empty(r)); >> + >> + /* enqueue 1 object */ >> + result = _ring_enqueue_burst(r, enq, 1); >> + enq += 1; >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); >> + >> + /* enqueue 2 objects */ >> + result = _ring_enqueue_burst(r, enq, 2); >> + enq += 2; >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); >> + >> + /* enqueue HALF_BULK objects */ >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); >> + enq += HALF_BULK; >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); >> + >> + /* ring is neither empty nor full */ >> + CU_ASSERT(0 == _ring_full(r)); >> + CU_ASSERT(0 == _ring_empty(r)); >> + >> + /* _ring_count() equals enqueued */ >> + count = (1 + 2 + HALF_BULK); >> + CU_ASSERT(count == _ring_count(r)); >> + /* _ring_free_count() equals rooms left */ >> + count = (RING_SIZE - 1) - count; >> + CU_ASSERT(count == _ring_free_count(r)); >> + >> + /* exceed the size, enquene as many as possible */ >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); >> + enq += count; >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); >> + CU_ASSERT(1 == _ring_full(r)); >> + >> + /* dequeue 1 object */ >> + result = _ring_dequeue_burst(r, deq, 1); >> + deq += 1; >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); >> + >> + /* dequeue 2 objects */ >> + result = _ring_dequeue_burst(r, deq, 2); >> + deq += 2; >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); >> + >> + /* dequeue HALF_BULK objects */ >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); >> + deq += HALF_BULK; >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); >> + >> + /* _ring_free_count() equals dequeued */ >> + count = (1 + 2 + HALF_BULK); >> + CU_ASSERT(count == _ring_free_count(r)); >> + /* _ring_count() equals remained left */ >> + count = (RING_SIZE - 1) - count; >> + CU_ASSERT(count == _ring_count(r)); >> + >> + /* underrun the size, dequeue as many as possible */ >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); >> + deq += count; >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); >> + CU_ASSERT(1 == _ring_empty(r)); >> + >> + /* check data */ >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> + >> + /* reset dequeue data */ >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> +} >> + >> +/* incomplete ring API set: strange! >> + * complement _ring_enqueue/dequeue_bulk to improve coverage >> + */ >> +static inline int __ring_enqueue_bulk( >> + _ring_t *r, void * const *objects, unsigned bulk) >> +{ >> + if (r->prod.sp_enqueue) >> + return _ring_sp_enqueue_bulk(r, objects, bulk); >> + else >> + return _ring_mp_enqueue_bulk(r, objects, bulk); >> +} >> + >> +static inline int __ring_dequeue_bulk( >> + _ring_t *r, void **objects, unsigned bulk) >> +{ >> + if (r->cons.sc_dequeue) >> + return _ring_sc_dequeue_bulk(r, objects, bulk); >> + else >> + return _ring_mc_dequeue_bulk(r, objects, bulk); >> +} >> + >> +static void __do_basic_bulk(_ring_t *r) >> +{ >> + int result = 0; >> + unsigned int count = 0; >> + void * const *source = test_enq_data; >> + void * const *dest = test_deq_data; >> + void **enq = NULL, **deq = NULL; >> + >> + enq = test_enq_data; deq = test_deq_data; >> + >> + /* ring is empty */ >> + CU_ASSERT(1 == _ring_empty(r)); >> + >> + /* enqueue 1 object */ >> + result = __ring_enqueue_bulk(r, enq, 1); >> + enq += 1; >> + CU_ASSERT(0 == result); >> + >> + /* enqueue 2 objects */ >> + result = __ring_enqueue_bulk(r, enq, 2); >> + enq += 2; >> + CU_ASSERT(0 == result); >> + >> + /* enqueue HALF_BULK objects */ >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); >> + enq += HALF_BULK; >> + CU_ASSERT(0 == result); >> + >> + /* ring is neither empty nor full */ >> + CU_ASSERT(0 == _ring_full(r)); >> + CU_ASSERT(0 == _ring_empty(r)); >> + >> + /* _ring_count() equals enqueued */ >> + count = (1 + 2 + HALF_BULK); >> + CU_ASSERT(count == _ring_count(r)); >> + /* _ring_free_count() equals rooms left */ >> + count = (RING_SIZE - 1) - count; >> + CU_ASSERT(count == _ring_free_count(r)); >> + >> + /* exceed the size, enquene shall fail with -ENOBUFS */ >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); >> + CU_ASSERT(-ENOBUFS == result); >> + >> + /* fullful the ring */ >> + result = __ring_enqueue_bulk(r, enq, count); >> + enq += count; >> + CU_ASSERT(0 == result); >> + CU_ASSERT(1 == _ring_full(r)); >> + >> + /* dequeue 1 object */ >> + result = __ring_dequeue_bulk(r, deq, 1); >> + deq += 1; >> + CU_ASSERT(0 == result); >> + >> + /* dequeue 2 objects */ >> + result = __ring_dequeue_bulk(r, deq, 2); >> + deq += 2; >> + CU_ASSERT(0 == result); >> + >> + /* dequeue HALF_BULK objects */ >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); >> + deq += HALF_BULK; >> + CU_ASSERT(0 == result); >> + >> + /* _ring_free_count() equals dequeued */ >> + count = (1 + 2 + HALF_BULK); >> + CU_ASSERT(count == _ring_free_count(r)); >> + /* _ring_count() equals remained left */ >> + count = (RING_SIZE - 1) - count; >> + CU_ASSERT(count == _ring_count(r)); >> + >> + /* underrun the size, dequeue shall fail with -ENOENT */ >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); >> + CU_ASSERT(-ENOENT == result); >> + >> + /* empty the queue */ >> + result = __ring_dequeue_bulk(r, deq, count); >> + deq += count; >> + CU_ASSERT(0 == result); >> + CU_ASSERT(1 == _ring_empty(r)); >> + >> + /* check data */ >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> + >> + /* reset dequeue data */ >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> +} >> + >> +void __do_basic_watermark(_ring_t *r) >> +{ >> + int result = 0; >> + void * const *source = test_enq_data; >> + void * const *dest = test_deq_data; >> + void **enq = NULL, **deq = NULL; >> + >> + enq = test_enq_data; deq = test_deq_data; >> + >> + /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */ >> + const unsigned watermark = PIECE_BULK; >> + const unsigned bulk = (watermark / 4) * 3; >> + >> + /* watermark cannot exceed ring size */ >> + result = _ring_set_water_mark(r, ILLEGAL_SIZE); >> + CU_ASSERT(-EINVAL == result); >> + >> + /* set watermark */ >> + result = _ring_set_water_mark(r, watermark); >> + CU_ASSERT(0 == result); >> + >> + /* 1st enqueue shall succeed */ >> + result = __ring_enqueue_bulk(r, enq, bulk); >> + enq += bulk; >> + CU_ASSERT(0 == result); >> + >> + /* 2nd enqueue shall succeed but return -EDQUOT */ >> + result = __ring_enqueue_bulk(r, enq, bulk); >> + enq += bulk; >> + CU_ASSERT(-EDQUOT == result); >> + >> + /* dequeue 1st bulk */ >> + result = __ring_dequeue_bulk(r, deq, bulk); >> + deq += bulk; >> + CU_ASSERT(0 == result); >> + >> + /* dequeue 2nd bulk */ >> + result = __ring_dequeue_bulk(r, deq, bulk); >> + deq += bulk; >> + CU_ASSERT(0 == result); >> + >> + /* check data */ >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> + >> + /* reset watermark */ >> + result = _ring_set_water_mark(r, 0); >> + CU_ASSERT(0 == result); >> + >> + /* reset dequeue data */ >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> +} >> diff --git a/platform/linux-generic/test/ring/ring_main.c >> b/platform/linux-generic/test/ring/ring_main.c >> new file mode 100644 >> index 0000000..e465113 >> --- /dev/null >> +++ b/platform/linux-generic/test/ring/ring_main.c >> @@ -0,0 +1,12 @@ >> +/* Copyright (c) 2015, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +#include "ring_suites.h" >> + >> +int main(void) >> +{ >> + return ring_suites_main(); >> +} >> diff --git a/platform/linux-generic/test/ring/ring_stress.c >> b/platform/linux-generic/test/ring/ring_stress.c >> new file mode 100644 >> index 0000000..a4753e9 >> --- /dev/null >> +++ b/platform/linux-generic/test/ring/ring_stress.c >> @@ -0,0 +1,270 @@ >> +/* Copyright (c) 2014, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +/*- >> + * BSD LICENSE >> + * >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> + * All rights reserved. >> + * >> + * Redistribution and use in source and binary forms, with or without >> + * modification, are permitted provided that the following conditions >> + * are met: >> + * >> + * * Redistributions of source code must retain the above copyright >> + * notice, this list of conditions and the following disclaimer. >> + * * Redistributions in binary form must reproduce the above >> copyright >> + * notice, this list of conditions and the following disclaimer in >> + * the documentation and/or other materials provided with the >> + * distribution. >> + * * Neither the name of Intel Corporation nor the names of its >> + * contributors may be used to endorse or promote products derived >> + * from this software without specific prior written permission. >> + * >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> FOR >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> INCIDENTAL, >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> USE, >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> ANY >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> USE >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >> + */ >> + >> +/** >> + * @file >> + * >> + * ODP ring stress test >> + */ >> + >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <string.h> >> + >> +#include <odp_api.h> >> +#include <odp/helper/linux.h> >> +#include <odp_packet_io_ring_internal.h> >> +#include <test_debug.h> >> +#include <odp_cunit_common.h> >> + >> +#include "ring_suites.h" >> + >> +/* >> + * Since cunit framework cannot work with multi-threading, ask workers >> + * to save their results for delayed assertion after thread collection. >> + */ >> +static int worker_results[MAX_WORKERS]; >> + >> +/* >> + * Note : make sure that both enqueue and dequeue >> + * operation starts at same time so to avoid data corruption >> + * Its because atomic lock will protect only indexes, but if order of >> + * read or write operation incorrect then data mismatch will happen >> + * So its resposibility of application develop to take care of order of >> + * data read or write. >> + */ >> +typedef enum { >> + STRESS_1_1_PRODUCER_CONSUMER, >> + STRESS_1_N_PRODUCER_CONSUMER, >> + STRESS_N_1_PRODUCER_CONSUMER, >> + STRESS_N_M_PRODUCER_CONSUMER >> +} stress_case_t; >> + >> +/* worker function declarations */ >> +static void *stress_worker(void *_data); >> + >> +/* global name for later look up in workers' context */ >> +static const char *ring_name = "stress ring"; >> + >> +int ring_test_stress_start(void) >> +{ >> + /* multiple thread usage scenario only */ >> + _ring_t *r_stress = _ring_create(ring_name, RING_SIZE, >> + 0 /* not used, alignement >> + taken care inside function: todo */); >> + if (r_stress == NULL) { >> + LOG_ERR("create ring failed for stress.\n"); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +void ring_test_stress_1_1_producer_consumer(void) >> +{ >> + int i = 0; >> + odp_cpumask_t cpus; >> + pthrd_arg worker_param; >> + >> + /* reset results for delayed assertion */ >> + memset(worker_results, 0, sizeof(worker_results)); >> + >> + /* request 2 threads to run 1:1 stress */ >> + worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2); >> + worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER; >> + >> + /* not failure, insufficient resource */ >> + if (worker_param.numthrds < 2) { >> + LOG_ERR("insufficient cpu for 1:1 " >> + "producer/consumer stress.\n"); >> + return; >> + } >> + >> + /* kick the workers */ >> + odp_cunit_thread_create(stress_worker, &worker_param); >> + >> + /* collect the results */ >> + odp_cunit_thread_exit(&worker_param); >> + >> + /* delayed assertion due to cunit limitation */ >> + for (i = 0; i < worker_param.numthrds; i++) >> + CU_ASSERT(0 == worker_results[i]); >> +} >> + >> +void ring_test_stress_N_M_producer_consumer(void) >> +{ >> + int i = 0; >> + odp_cpumask_t cpus; >> + pthrd_arg worker_param; >> + >> + /* reset results for delayed assertion */ >> + memset(worker_results, 0, sizeof(worker_results)); >> + >> + /* request MAX_WORKERS threads to run N:M stress */ >> + worker_param.numthrds = >> + odp_cpumask_default_worker(&cpus, MAX_WORKERS); >> + worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER; >> + >> + /* not failure, insufficient resource */ >> + if (worker_param.numthrds < 3) { >> + LOG_ERR("insufficient cpu for N:M " >> + "producer/consumer stress.\n"); >> + return; >> + } >> + >> + /* kick the workers */ >> + odp_cunit_thread_create(stress_worker, &worker_param); >> + >> + /* collect the results */ >> + odp_cunit_thread_exit(&worker_param); >> + >> + /* delayed assertion due to cunit limitation */ >> + for (i = 0; i < worker_param.numthrds; i++) >> + CU_ASSERT(0 == worker_results[i]); >> +} >> + >> +void ring_test_stress_1_N_producer_consumer(void) >> +{ >> +} >> + >> +void ring_test_stress_N_1_producer_consumer(void) >> +{ >> +} >> + >> +void ring_test_stress_ring_list_dump(void) >> +{ >> + /* improve code coverage */ >> + _ring_list_dump(); >> +} >> + >> +/* worker function for multiple producer instances */ >> +static int do_producer(_ring_t *r) >> +{ >> + int i, result = 0; >> + void **enq = NULL; >> + >> + /* allocate dummy object pointers for enqueue */ >> + enq = malloc(PIECE_BULK * 2 * sizeof(void *)); >> + if (NULL == enq) { >> + LOG_ERR("insufficient memory for producer enqueue.\n"); >> + return 0; /* not failure, skip for insufficient memory */ >> + } >> + >> + /* data pattern to be evaluated later in consumer */ >> + for (i = 0; i < PIECE_BULK; i++) >> + enq[i] = (void *)(unsigned long)i; >> + >> + do { >> + result = _ring_mp_enqueue_bulk(r, enq, PIECE_BULK); >> + if (0 == result) { >> + free(enq); >> + return 0; >> + } >> + } while (1); >> +} >> + >> +/* worker function for multiple consumer instances */ >> +static int do_consumer(_ring_t *r) >> +{ >> + int i, result = 0; >> + void **deq = NULL; >> + const char *message = "test OK!"; >> + const char *mismatch = "data mismatch..lockless enq/deq failed."; >> + >> + /* allocate dummy object pointers for dequeue */ >> + deq = malloc(PIECE_BULK * 2 * sizeof(void *)); >> + if (NULL == deq) { >> + LOG_ERR("insufficient memory for consumer dequeue.\n"); >> + return 0; /* not failure, skip for insufficient memory */ >> + } >> + >> + do { >> + result = _ring_mc_dequeue_bulk(r, deq, PIECE_BULK); >> + if (0 == result) { >> + /* evaluate the data pattern */ >> + for (i = 0; i < PIECE_BULK; i++) { >> + if (deq[i] != (void *)(unsigned long)i) { >> + result = -1; >> + message = mismatch; >> + break; >> + } >> + } >> + >> + free(deq); >> + LOG_ERR("%s\n", message); >> + return result; >> + } >> + } while (1); >> +} >> + >> +static void *stress_worker(void *_data) >> +{ >> + pthrd_arg *worker_param = (pthrd_arg *)_data; >> + _ring_t *r_stress = NULL; >> + >> + int worker_id = odp_thread_id(); >> + /* save the worker result for delayed assertion */ >> + int *result = &worker_results[(worker_id % >> worker_param->numthrds)]; >> + >> + /* verify ring lookup in worker context */ >> + r_stress = _ring_lookup(ring_name); >> + if (NULL == r_stress) { >> + LOG_ERR("ring lookup %s not found\n", ring_name); >> + *result = -1; >> + return NULL; >> + } >> + >> + switch (worker_param->testcase) { >> + case STRESS_1_1_PRODUCER_CONSUMER: >> + case STRESS_N_M_PRODUCER_CONSUMER: >> + /* interleaved producer/consumer */ >> + if (0 == (worker_id % 2)) >> + *result = do_producer(r_stress); >> + else if (1 == (worker_id % 2)) >> + *result = do_consumer(r_stress); >> + break; >> + case STRESS_1_N_PRODUCER_CONSUMER: >> + case STRESS_N_1_PRODUCER_CONSUMER: >> + default: >> + LOG_ERR("invalid or not-implemented stress type (%d)\n", >> + worker_param->testcase); >> + break; >> + } >> + return NULL; >> +} >> diff --git a/platform/linux-generic/test/ring/ring_suites.c >> b/platform/linux-generic/test/ring/ring_suites.c >> new file mode 100644 >> index 0000000..b310843 >> --- /dev/null >> +++ b/platform/linux-generic/test/ring/ring_suites.c >> @@ -0,0 +1,70 @@ >> +/* Copyright (c) 2015, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +#include <stdlib.h> >> +#include <stdio.h> >> +#include <string.h> >> + >> +#include <odp_api.h> >> +#include <test_debug.h> >> +#include <odp_cunit_common.h> >> +#include <odp_packet_io_ring_internal.h> >> + >> +#include "ring_suites.h" >> + >> +static int ring_suites_init(odp_instance_t *inst) >> +{ >> + if (0 != odp_init_global(inst, NULL, NULL)) { >> + LOG_ERR("error: odp_init_global() failed.\n"); >> + return -1; >> + } >> + if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) { >> + LOG_ERR("error: odp_init_local() failed.\n"); >> + return -1; >> + } >> + >> + _ring_tailq_init(); >> + return 0; >> +} >> + >> +static odp_testinfo_t ring_suite_basic[] = { >> + ODP_TEST_INFO(ring_test_basic_create), >> + ODP_TEST_INFO(ring_test_basic_burst), >> + ODP_TEST_INFO(ring_test_basic_bulk), >> + ODP_TEST_INFO(ring_test_basic_watermark), >> + ODP_TEST_INFO_NULL, >> +}; >> + >> +static odp_testinfo_t ring_suite_stress[] = { >> + ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer), >> + ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer), >> + ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer), >> + ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer), >> + ODP_TEST_INFO(ring_test_stress_ring_list_dump), >> + ODP_TEST_INFO_NULL, >> +}; >> + >> +static odp_suiteinfo_t ring_suites[] = { >> + {"ring basic", ring_test_basic_start, >> + ring_test_basic_end, ring_suite_basic}, >> + {"ring stress", ring_test_stress_start, >> + NULL, ring_suite_stress}, >> + ODP_SUITE_INFO_NULL >> +}; >> + >> +int ring_suites_main(void) >> +{ >> + int ret; >> + >> + odp_cunit_register_global_init(ring_suites_init); >> + >> + ret = odp_cunit_register(ring_suites); >> + >> + if (ret == 0) >> + ret = odp_cunit_run(); >> + >> + return ret; >> +} >> diff --git a/platform/linux-generic/test/ring/ring_suites.h >> b/platform/linux-generic/test/ring/ring_suites.h >> new file mode 100644 >> index 0000000..e26b6e8 >> --- /dev/null >> +++ b/platform/linux-generic/test/ring/ring_suites.h >> @@ -0,0 +1,33 @@ >> +/* Copyright (c) 2015, Linaro Limited >> + * All rights reserved. >> + * >> + * SPDX-License-Identifier: BSD-3-Clause >> + */ >> + >> +#define RING_SIZE 4096 >> +#define PIECE_BULK 32 >> + >> +#define HALF_BULK (RING_SIZE >> 1) >> +#define ILLEGAL_SIZE (RING_SIZE | 0x3) >> + >> +/* test suite start and stop */ >> +int ring_test_basic_start(void); >> +int ring_test_basic_end(void); >> + >> +/* basic test cases */ >> +void ring_test_basic_create(void); >> +void ring_test_basic_burst(void); >> +void ring_test_basic_bulk(void); >> +void ring_test_basic_watermark(void); >> + >> +/* test suite start and stop */ >> +int ring_test_stress_start(void); >> + >> +/* stress test cases */ >> +void ring_test_stress_1_1_producer_consumer(void); >> +void ring_test_stress_1_N_producer_consumer(void); >> +void ring_test_stress_N_1_producer_consumer(void); >> +void ring_test_stress_N_M_producer_consumer(void); >> +void ring_test_stress_ring_list_dump(void); >> + >> +int ring_suites_main(void); >> diff --git a/platform/linux-generic/test/ring/ringtest.c >> b/platform/linux-generic/test/ring/ringtest.c >> deleted file mode 100644 >> index ac0aa61..0000000 >> --- a/platform/linux-generic/test/ring/ringtest.c >> +++ /dev/null >> @@ -1,493 +0,0 @@ >> -/* Copyright (c) 2014, Linaro Limited >> - * All rights reserved. >> - * >> - * SPDX-License-Identifier: BSD-3-Clause >> - */ >> - >> -/*- >> - * BSD LICENSE >> - * >> - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> - * All rights reserved. >> - * >> - * Redistribution and use in source and binary forms, with or without >> - * modification, are permitted provided that the following conditions >> - * are met: >> - * >> - * * Redistributions of source code must retain the above copyright >> - * notice, this list of conditions and the following disclaimer. >> - * * Redistributions in binary form must reproduce the above >> copyright >> - * notice, this list of conditions and the following disclaimer in >> - * the documentation and/or other materials provided with the >> - * distribution. >> - * * Neither the name of Intel Corporation nor the names of its >> - * contributors may be used to endorse or promote products derived >> - * from this software without specific prior written permission. >> - * >> - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >> - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> FOR >> - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >> - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> INCIDENTAL, >> - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> USE, >> - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> ANY >> - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >> - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> USE >> - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >> - */ >> - >> -/** >> - * @file >> - * >> - * ODP test ring >> - */ >> - >> -#include <stdlib.h> >> -#include <stdio.h> >> -#include <string.h> >> - >> -#include <odp_api.h> >> -#include <odp/helper/linux.h> >> -#include <odp_packet_io_ring_internal.h> >> -#include <test_debug.h> >> -#include <odp_cunit_common.h> >> - >> -#define RING_SIZE 4096 >> -#define MAX_BULK 32 >> - >> -enum { >> - ODP_RING_TEST_BASIC, >> - ODP_RING_TEST_STRESS, >> -}; >> - >> -/* local struct for ring_thread argument */ >> -typedef struct { >> - pthrd_arg thrdarg; >> - int stress_type; >> -} ring_arg_t; >> - >> -static int test_ring_basic(_ring_t *r) >> -{ >> - void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = >> NULL; >> - int ret; >> - unsigned i, num_elems; >> - >> - /* alloc dummy object pointers */ >> - src = malloc(RING_SIZE * 2 * sizeof(void *)); >> - if (src == NULL) { >> - LOG_ERR("failed to allocate test ring src memory\n"); >> - goto fail; >> - } >> - for (i = 0; i < RING_SIZE * 2; i++) >> - src[i] = (void *)(unsigned long)i; >> - >> - cur_src = src; >> - >> - /* alloc some room for copied objects */ >> - dst = malloc(RING_SIZE * 2 * sizeof(void *)); >> - if (dst == NULL) { >> - LOG_ERR("failed to allocate test ring dst memory\n"); >> - goto fail; >> - } >> - >> - memset(dst, 0, RING_SIZE * 2 * sizeof(void *)); >> - cur_dst = dst; >> - >> - printf("Test SP & SC basic functions\n"); >> - printf("enqueue 1 obj\n"); >> - ret = _ring_sp_enqueue_burst(r, cur_src, 1); >> - cur_src += 1; >> - if ((ret & _RING_SZ_MASK) != 1) { >> - LOG_ERR("sp_enq for 1 obj failed\n"); >> - goto fail; >> - } >> - >> - printf("enqueue 2 objs\n"); >> - ret = _ring_sp_enqueue_burst(r, cur_src, 2); >> - cur_src += 2; >> - if ((ret & _RING_SZ_MASK) != 2) { >> - LOG_ERR("sp_enq for 2 obj failed\n"); >> - goto fail; >> - } >> - >> - printf("enqueue MAX_BULK objs\n"); >> - ret = _ring_sp_enqueue_burst(r, cur_src, MAX_BULK); >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { >> - LOG_ERR("sp_enq for %d obj failed\n", MAX_BULK); >> - goto fail; >> - } >> - >> - printf("dequeue 1 obj\n"); >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 1); >> - cur_dst += 1; >> - if ((ret & _RING_SZ_MASK) != 1) { >> - LOG_ERR("sc_deq for 1 obj failed\n"); >> - goto fail; >> - } >> - >> - printf("dequeue 2 objs\n"); >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 2); >> - cur_dst += 2; >> - if ((ret & _RING_SZ_MASK) != 2) { >> - LOG_ERR("sc_deq for 2 obj failed\n"); >> - goto fail; >> - } >> - >> - printf("dequeue MAX_BULK objs\n"); >> - ret = _ring_sc_dequeue_burst(r, cur_dst, MAX_BULK); >> - cur_dst += MAX_BULK; >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { >> - LOG_ERR("sc_deq for %d obj failed\n", MAX_BULK); >> - goto fail; >> - } >> - >> - /* check data */ >> - if (memcmp(src, dst, cur_dst - dst)) { >> - LOG_ERR("data after dequeue is not the same\n"); >> - goto fail; >> - } >> - >> - cur_src = src; >> - cur_dst = dst; >> - >> - printf("Test MP & MC basic functions\n"); >> - >> - printf("enqueue 1 obj\n"); >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 1); >> - cur_src += 1; >> - if (ret != 0) { >> - LOG_ERR("mp_enq for 1 obj failed\n"); >> - goto fail; >> - } >> - printf("enqueue 2 objs\n"); >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 2); >> - cur_src += 2; >> - if (ret != 0) { >> - LOG_ERR("mp_enq for 2 obj failed\n"); >> - goto fail; >> - } >> - printf("enqueue MAX_BULK objs\n"); >> - ret = _ring_mp_enqueue_bulk(r, cur_src, MAX_BULK); >> - if (ret != 0) { >> - LOG_ERR("mp_enq for %d obj failed\n", MAX_BULK); >> - goto fail; >> - } >> - printf("dequeue 1 obj\n"); >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 1); >> - cur_dst += 1; >> - if (ret != 0) { >> - LOG_ERR("mc_deq for 1 obj failed\n"); >> - goto fail; >> - } >> - printf("dequeue 2 objs\n"); >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 2); >> - cur_dst += 2; >> - if (ret != 0) { >> - LOG_ERR("mc_deq for 2 obj failed\n"); >> - goto fail; >> - } >> - printf("dequeue MAX_BULK objs\n"); >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK); >> - cur_dst += MAX_BULK; >> - if (ret != 0) { >> - LOG_ERR("mc_deq for %d obj failed\n", MAX_BULK); >> - goto fail; >> - } >> - /* check data */ >> - if (memcmp(src, dst, cur_dst - dst)) { >> - LOG_ERR("data after dequeue is not the same\n"); >> - goto fail; >> - } >> - >> - printf("test watermark and default bulk enqueue / dequeue\n"); >> - _ring_set_water_mark(r, 20); >> - num_elems = 16; >> - >> - cur_src = src; >> - cur_dst = dst; >> - >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); >> - cur_src += num_elems; >> - if (ret != 0) { >> - LOG_ERR("Cannot enqueue\n"); >> - goto fail; >> - } >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); >> - if (ret != -EDQUOT) { >> - LOG_ERR("Watermark not exceeded\n"); >> - goto fail; >> - } >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); >> - cur_dst += num_elems; >> - if (ret != 0) { >> - LOG_ERR("Cannot dequeue\n"); >> - goto fail; >> - } >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); >> - cur_dst += num_elems; >> - if (ret != 0) { >> - LOG_ERR("Cannot dequeue2\n"); >> - goto fail; >> - } >> - >> - /* check data */ >> - if (memcmp(src, dst, cur_dst - dst)) { >> - LOG_ERR("data after dequeue is not the same\n"); >> - goto fail; >> - } >> - >> - printf("basic enqueu, dequeue test for ring <%s>@%p passed\n", >> - r->name, r); >> - >> - free(src); >> - free(dst); >> - return 0; >> - >> -fail: >> - free(src); >> - free(dst); >> - return -1; >> -} >> - >> -/* global shared ring used for stress testing */ >> -static _ring_t *r_stress; >> - >> -/* Stress func for Multi producer only */ >> -static int producer_fn(void) >> -{ >> - unsigned i; >> - >> - void **src = NULL; >> - >> - /* alloc dummy object pointers */ >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); >> - if (src == NULL) { >> - LOG_ERR("failed to allocate producer memory.\n"); >> - return -1; >> - } >> - for (i = 0; i < MAX_BULK; i++) >> - src[i] = (void *)(unsigned long)i; >> - >> - do { >> - i = _ring_mp_enqueue_bulk(r_stress, src, MAX_BULK); >> - if (i == 0) { >> - free(src); >> - return 0; >> - } >> - } while (1); >> -} >> - >> -/* Stress func for Multi consumer only */ >> -static int consumer_fn(void) >> -{ >> - unsigned i; >> - void **src = NULL; >> - >> - /* alloc dummy object pointers */ >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); >> - if (src == NULL) { >> - LOG_ERR("failed to allocate consumer memory.\n"); >> - return -1; >> - } >> - >> - do { >> - i = _ring_mc_dequeue_bulk(r_stress, src, MAX_BULK); >> - if (i == 0) { >> - for (i = 0; i < MAX_BULK; i++) { >> - if (src[i] != (void *)(unsigned long)i) { >> - free(src); >> - printf("data mismatch.. lockless >> ops fail\n"); >> - return -1; >> - } >> - } >> - free(src); >> - printf("\n Test OK !\n"); >> - return 0; >> - } >> - } while (1); >> -} >> - >> -/* >> - * Note : make sure that both enqueue and dequeue >> - * operation starts at same time so to avoid data corruption >> - * Its because atomic lock will protect only indexes, but if order of >> - * read or write operation incorrect then data mismatch will happen >> - * So its resposibility of application develop to take care of order of >> - * data read or write. >> -*/ >> -typedef enum { >> - one_enq_one_deq, /* One thread to enqueue one to >> - dequeu at same time */ >> - one_enq_rest_deq, /* one thread to enq rest to >> - dequeue at same time */ >> - one_deq_rest_enq, /* one to deq and rest enq at very same >> time */ >> - multi_enq_multi_deq /* multiple enq,deq */ >> -} stress_type_t; >> - >> -static void test_ring_stress(stress_type_t type) >> -{ >> - int thr; >> - >> - thr = odp_thread_id(); >> - >> - switch (type) { >> - case one_enq_one_deq: >> - if (thr == 1) >> - producer_fn(); >> - if (thr == 2) >> - consumer_fn(); >> - break; >> - case multi_enq_multi_deq: >> - if (thr % 2 == 0) >> - producer_fn(); >> - else >> - consumer_fn(); >> - break; >> - case one_deq_rest_enq: >> - case one_enq_rest_deq:/*TBD*/ >> - default: >> - LOG_ERR("Invalid stress type or test case yet not >> supported\n"); >> - } >> -} >> - >> -static void *test_ring(void *arg) >> -{ >> - ring_arg_t *parg = (ring_arg_t *)arg; >> - int thr; >> - char ring_name[_RING_NAMESIZE]; >> - _ring_t *r; >> - int result = 0; >> - >> - thr = odp_thread_id(); >> - >> - printf("Thread %i starts\n", thr); >> - >> - switch (parg->thrdarg.testcase) { >> - case ODP_RING_TEST_BASIC: >> - snprintf(ring_name, sizeof(ring_name), "test_ring_%i", >> thr); >> - >> - r = _ring_create(ring_name, RING_SIZE, >> - 0 /* not used, alignement >> - taken care inside func : todo */); >> - if (r == NULL) { >> - LOG_ERR("ring create failed\n"); >> - result = -1; >> - break; >> - } >> - /* lookup ring from its name */ >> - if (_ring_lookup(ring_name) != r) { >> - LOG_ERR("ring lookup failed\n"); >> - result = -1; >> - break; >> - } >> - >> - /* basic operations */ >> - if (test_ring_basic(r) < 0) { >> - LOG_ERR("ring basic enqueue/dequeu ops failed\n"); >> - result = -1; >> - } >> - >> - if (result) >> - _ring_list_dump(); >> - >> - break; >> - >> - case ODP_RING_TEST_STRESS: >> - test_ring_stress(parg->stress_type); >> - >> - if (result) >> - _ring_list_dump(); >> - break; >> - >> - default: >> - LOG_ERR("Invalid test case [%d]\n", >> parg->thrdarg.testcase); >> - result = -1; >> - break; >> - } >> - >> - LOG_DBG("result = %d\n", result); >> - if (result == 0) >> - printf("test_ring Result:pass\n"); >> - else >> - printf("test_ring Result:fail\n"); >> - >> - fflush(stdout); >> - >> - return parg; >> -} >> - >> -int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED) >> -{ >> - ring_arg_t rarg; >> - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; >> - odp_cpumask_t cpu_mask; >> - int num_workers; >> - char ring_name[_RING_NAMESIZE]; >> - odp_instance_t instance; >> - odph_linux_thr_params_t thr_params; >> - >> - if (odp_init_global(&instance, NULL, NULL)) { >> - LOG_ERR("Error: ODP global init failed.\n"); >> - exit(EXIT_FAILURE); >> - } >> - >> - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { >> - LOG_ERR("Error: ODP local init failed.\n"); >> - exit(EXIT_FAILURE); >> - } >> - >> - _ring_tailq_init(); >> - >> - num_workers = odp_cpumask_default_worker(&cpu_mask, MAX_WORKERS); >> - rarg.thrdarg.numthrds = rarg.thrdarg.numthrds; >> - >> - rarg.thrdarg.testcase = ODP_RING_TEST_BASIC; >> - >> - memset(&thr_params, 0, sizeof(thr_params)); >> - thr_params.start = test_ring; >> - thr_params.arg = &rarg; >> - thr_params.thr_type = ODP_THREAD_WORKER; >> - thr_params.instance = instance; >> - >> - printf("starting stess test type : %d..\n", rarg.stress_type); >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); >> - odph_linux_pthread_join(thread_tbl, num_workers); >> - >> - rarg.thrdarg.testcase = ODP_RING_TEST_STRESS; >> - rarg.stress_type = one_enq_one_deq; >> - >> - printf("starting stess test type : %d..\n", rarg.stress_type); >> - snprintf(ring_name, sizeof(ring_name), "test_ring_stress"); >> - r_stress = _ring_create(ring_name, RING_SIZE, >> - 0/* not used, alignement >> - taken care inside func : todo */); >> - if (r_stress == NULL) { >> - LOG_ERR("ring create failed\n"); >> - goto fail; >> - } >> - /* lookup ring from its name */ >> - if (_ring_lookup(ring_name) != r_stress) { >> - LOG_ERR("ring lookup failed\n"); >> - goto fail; >> - } >> - >> - thr_params.start = test_ring; >> - thr_params.arg = &rarg; >> - >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); >> - odph_linux_pthread_join(thread_tbl, num_workers); >> - >> -fail: >> - if (odp_term_local()) { >> - LOG_ERR("Error: ODP local term failed.\n"); >> - exit(EXIT_FAILURE); >> - } >> - >> - if (odp_term_global(instance)) { >> - LOG_ERR("Error: ODP global term failed.\n"); >> - exit(EXIT_FAILURE); >> - } >> - >> - return 0; >> -} >> > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > https://lists.linaro.org/mailman/listinfo/lng-odp >
Thanks Maxim and Bill, I'll update copyright to 2016 and remove Intel's copyright, just one question before I send the v3 patch: - I saw Christophe's patches series, shall I update mine based on his (with command line parameter parsing). - Or wait until his patch series merged into master/next branch and then write a new separate patch to add command line parameters parsing. Best Regards, Yi On 22 May 2016 at 23:52, Bill Fischofer <bill.fischofer@linaro.org> wrote: > I concur with Maxim on the copyrights but other than that: > > Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org> > > Note that I'm unable to get this test to fail, so this may also be a fix to > the issue discussed in > https://lists.linaro.org/pipermail/lng-odp/2016-May/023518.html > > Might need to resolve conflicts between this patch and Christophe's changes > (I haven't tested to see what conflicts may exist). > > On Fri, May 20, 2016 at 7:59 AM, Maxim Uvarov <maxim.uvarov@linaro.org> > wrote: > > > Linaros copyright has to be 2016 (in some places you have 2014 in other > > 2015). > > > > ringstress.c is new file and looks like it's pure ODP. Adding Intels > > copyright there is not right. > > > > Maxim. > > > > > > On 05/20/16 11:48, Yi He wrote: > > > >> Fixes: https://bugs.linaro.org/show_bug.cgi?id=2228 > >> > >> Convert ring test program into cunit framework > >> Improve LCOV coverage for linux-generic/pktio/ring.c > >> > >> Signed-off-by: Yi He <yi.he@linaro.org> > >> --- > >> platform/linux-generic/test/Makefile.am | 2 +- > >> platform/linux-generic/test/ring/Makefile.am | 20 +- > >> platform/linux-generic/test/ring/ring_basic.c | 392 > >> ++++++++++++++++++++ > >> platform/linux-generic/test/ring/ring_main.c | 12 + > >> platform/linux-generic/test/ring/ring_stress.c | 270 ++++++++++++++ > >> platform/linux-generic/test/ring/ring_suites.c | 70 ++++ > >> platform/linux-generic/test/ring/ring_suites.h | 33 ++ > >> platform/linux-generic/test/ring/ringtest.c | 493 > >> ------------------------- > >> 8 files changed, 787 insertions(+), 505 deletions(-) > >> create mode 100644 platform/linux-generic/test/ring/ring_basic.c > >> create mode 100644 platform/linux-generic/test/ring/ring_main.c > >> create mode 100644 platform/linux-generic/test/ring/ring_stress.c > >> create mode 100644 platform/linux-generic/test/ring/ring_suites.c > >> create mode 100644 platform/linux-generic/test/ring/ring_suites.h > >> delete mode 100644 platform/linux-generic/test/ring/ringtest.c > >> > >> diff --git a/platform/linux-generic/test/Makefile.am > >> b/platform/linux-generic/test/Makefile.am > >> index f74185d..2d58c57 100644 > >> --- a/platform/linux-generic/test/Makefile.am > >> +++ b/platform/linux-generic/test/Makefile.am > >> @@ -8,7 +8,7 @@ ODP_MODULES = pktio \ > >> if test_vald > >> TESTS = pktio/pktio_run.sh \ > >> pktio/pktio_run_tap.sh \ > >> - ring/ringtest$(EXEEXT) \ > >> + ring/ring_main$(EXEEXT) \ > >> shmem/shmem_linux \ > >> ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ > >> ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ > >> diff --git a/platform/linux-generic/test/ring/Makefile.am > >> b/platform/linux-generic/test/ring/Makefile.am > >> index 5a949d0..c086584 100644 > >> --- a/platform/linux-generic/test/ring/Makefile.am > >> +++ b/platform/linux-generic/test/ring/Makefile.am > >> @@ -1,16 +1,14 @@ > >> -include $(top_srcdir)/test/validation/Makefile.inc > >> +include ../Makefile.inc > >> -AM_CFLAGS += -I$(srcdir)/common > >> -AM_CFLAGS += -I$(top_srcdir)/test/validation/common > >> -AM_LDFLAGS += -static > >> +noinst_LTLIBRARIES = libtestring.la > >> +libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c > >> +libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP) > >> -COMPILE_ONLY = > >> +test_PROGRAMS = ring_main$(EXEEXT) > >> +dist_ring_main_SOURCES = ring_main.c > >> -TESTSCRIPTS = > >> +ring_main_LDFLAGS = $(AM_LDFLAGS) > >> +ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP) > >> -EXECUTABLES = ringtest$(EXEEXT) > >> +noinst_HEADERS = ring_suites.h > >> -test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) > >> - > >> -ringtest_SOURCES = ringtest.c > >> -ringtest_LDADD = $(LIBCUNIT_COMMON) $(LIBODP) > >> diff --git a/platform/linux-generic/test/ring/ring_basic.c > >> b/platform/linux-generic/test/ring/ring_basic.c > >> new file mode 100644 > >> index 0000000..20d9786 > >> --- /dev/null > >> +++ b/platform/linux-generic/test/ring/ring_basic.c > >> @@ -0,0 +1,392 @@ > >> +/* Copyright (c) 2015, Linaro Limited > >> + * All rights reserved. > >> + * > >> + * SPDX-License-Identifier: BSD-3-Clause > >> + */ > >> + > >> +/*- > >> + * BSD LICENSE > >> + * > >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > >> + * All rights reserved. > >> + * > >> + * Redistribution and use in source and binary forms, with or without > >> + * modification, are permitted provided that the following conditions > >> + * are met: > >> + * > >> + * * Redistributions of source code must retain the above copyright > >> + * notice, this list of conditions and the following disclaimer. > >> + * * Redistributions in binary form must reproduce the above > >> copyright > >> + * notice, this list of conditions and the following disclaimer > in > >> + * the documentation and/or other materials provided with the > >> + * distribution. > >> + * * Neither the name of Intel Corporation nor the names of its > >> + * contributors may be used to endorse or promote products > derived > >> + * from this software without specific prior written permission. > >> + * > >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS > >> FOR > >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > >> INCIDENTAL, > >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > >> USE, > >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON > >> ANY > >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR > TORT > >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > >> USE > >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > >> + */ > >> + > >> +/** > >> + * @file > >> + * > >> + * ODP ring basic test > >> + */ > >> + > >> +#include <stdlib.h> > >> +#include <stdio.h> > >> +#include <string.h> > >> + > >> +#include <test_debug.h> > >> +#include <odp_cunit_common.h> > >> +#include <odp_packet_io_ring_internal.h> > >> + > >> +#include "ring_suites.h" > >> + > >> +/* labor functions declaration */ > >> +static void __do_basic_burst(_ring_t *r); > >> +static void __do_basic_bulk(_ring_t *r); > >> +static void __do_basic_watermark(_ring_t *r); > >> + > >> +/* dummy object pointers for enqueue and dequeue testing */ > >> +static void **test_enq_data; > >> +static void **test_deq_data; > >> + > >> +/* create two rings: one for single thread usage scenario > >> + * and another for multiple thread usage scenario. > >> + * st - single thread usage scenario > >> + * mt - multiple thread usage scenario > >> + */ > >> +static const char *st_ring_name = "ST basic ring"; > >> +static const char *mt_ring_name = "MT basic ring"; > >> +static _ring_t *st_ring, *mt_ring; > >> + > >> +int ring_test_basic_start(void) > >> +{ > >> + int i = 0; > >> + > >> + /* alloc dummy object pointers for enqueue testing */ > >> + test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *)); > >> + if (NULL == test_enq_data) { > >> + LOG_ERR("failed to allocate basic test enqeue data\n"); > >> + return -1; > >> + } > >> + > >> + for (i = 0; i < RING_SIZE * 2; i++) > >> + test_enq_data[i] = (void *)(unsigned long)i; > >> + > >> + /* alloc dummy object pointers for dequeue testing */ > >> + test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *)); > >> + if (NULL == test_deq_data) { > >> + LOG_ERR("failed to allocate basic test dequeue data\n"); > >> + free(test_enq_data); test_enq_data = NULL; > >> + return -1; > >> + } > >> + > >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > >> + return 0; > >> +} > >> + > >> +int ring_test_basic_end(void) > >> +{ > >> + free(test_enq_data); > >> + free(test_deq_data); > >> + return 0; > >> +} > >> + > >> +/* basic test cases */ > >> +void ring_test_basic_create(void) > >> +{ > >> + /* prove illegal size shall fail */ > >> + st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0); > >> + CU_ASSERT(NULL == st_ring); > >> + CU_ASSERT(EINVAL == __odp_errno); > >> + > >> + /* create ring for single thread usage scenario */ > >> + st_ring = _ring_create(st_ring_name, RING_SIZE, > >> + _RING_F_SP_ENQ | _RING_F_SC_DEQ); > >> + > >> + CU_ASSERT(NULL != st_ring); > >> + CU_ASSERT(_ring_lookup(st_ring_name) == st_ring); > >> + > >> + /* create ring for multiple thread usage scenario */ > >> + mt_ring = _ring_create(mt_ring_name, RING_SIZE, > >> + 0 /* not used, alignement > >> + taken care inside function: todo */); > >> + > >> + CU_ASSERT(NULL != mt_ring); > >> + CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring); > >> +} > >> + > >> +void ring_test_basic_burst(void) > >> +{ > >> + /* two rounds to cover both single > >> + * thread and multiple thread APIs > >> + */ > >> + __do_basic_burst(st_ring); > >> + __do_basic_burst(mt_ring); > >> +} > >> + > >> +void ring_test_basic_bulk(void) > >> +{ > >> + __do_basic_bulk(st_ring); > >> + __do_basic_bulk(mt_ring); > >> +} > >> + > >> +void ring_test_basic_watermark(void) > >> +{ > >> + __do_basic_watermark(st_ring); > >> + __do_basic_watermark(mt_ring); > >> +} > >> + > >> +/* labor functions definition */ > >> +static void __do_basic_burst(_ring_t *r) > >> +{ > >> + int result = 0; > >> + unsigned int count = 0; > >> + void * const *source = test_enq_data; > >> + void * const *dest = test_deq_data; > >> + void **enq = NULL, **deq = NULL; > >> + > >> + enq = test_enq_data; deq = test_deq_data; > >> + > >> + /* ring is empty */ > >> + CU_ASSERT(1 == _ring_empty(r)); > >> + > >> + /* enqueue 1 object */ > >> + result = _ring_enqueue_burst(r, enq, 1); > >> + enq += 1; > >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); > >> + > >> + /* enqueue 2 objects */ > >> + result = _ring_enqueue_burst(r, enq, 2); > >> + enq += 2; > >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); > >> + > >> + /* enqueue HALF_BULK objects */ > >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); > >> + enq += HALF_BULK; > >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); > >> + > >> + /* ring is neither empty nor full */ > >> + CU_ASSERT(0 == _ring_full(r)); > >> + CU_ASSERT(0 == _ring_empty(r)); > >> + > >> + /* _ring_count() equals enqueued */ > >> + count = (1 + 2 + HALF_BULK); > >> + CU_ASSERT(count == _ring_count(r)); > >> + /* _ring_free_count() equals rooms left */ > >> + count = (RING_SIZE - 1) - count; > >> + CU_ASSERT(count == _ring_free_count(r)); > >> + > >> + /* exceed the size, enquene as many as possible */ > >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); > >> + enq += count; > >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); > >> + CU_ASSERT(1 == _ring_full(r)); > >> + > >> + /* dequeue 1 object */ > >> + result = _ring_dequeue_burst(r, deq, 1); > >> + deq += 1; > >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); > >> + > >> + /* dequeue 2 objects */ > >> + result = _ring_dequeue_burst(r, deq, 2); > >> + deq += 2; > >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); > >> + > >> + /* dequeue HALF_BULK objects */ > >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); > >> + deq += HALF_BULK; > >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); > >> + > >> + /* _ring_free_count() equals dequeued */ > >> + count = (1 + 2 + HALF_BULK); > >> + CU_ASSERT(count == _ring_free_count(r)); > >> + /* _ring_count() equals remained left */ > >> + count = (RING_SIZE - 1) - count; > >> + CU_ASSERT(count == _ring_count(r)); > >> + > >> + /* underrun the size, dequeue as many as possible */ > >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); > >> + deq += count; > >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); > >> + CU_ASSERT(1 == _ring_empty(r)); > >> + > >> + /* check data */ > >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > >> + > >> + /* reset dequeue data */ > >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > >> +} > >> + > >> +/* incomplete ring API set: strange! > >> + * complement _ring_enqueue/dequeue_bulk to improve coverage > >> + */ > >> +static inline int __ring_enqueue_bulk( > >> + _ring_t *r, void * const *objects, unsigned bulk) > >> +{ > >> + if (r->prod.sp_enqueue) > >> + return _ring_sp_enqueue_bulk(r, objects, bulk); > >> + else > >> + return _ring_mp_enqueue_bulk(r, objects, bulk); > >> +} > >> + > >> +static inline int __ring_dequeue_bulk( > >> + _ring_t *r, void **objects, unsigned bulk) > >> +{ > >> + if (r->cons.sc_dequeue) > >> + return _ring_sc_dequeue_bulk(r, objects, bulk); > >> + else > >> + return _ring_mc_dequeue_bulk(r, objects, bulk); > >> +} > >> + > >> +static void __do_basic_bulk(_ring_t *r) > >> +{ > >> + int result = 0; > >> + unsigned int count = 0; > >> + void * const *source = test_enq_data; > >> + void * const *dest = test_deq_data; > >> + void **enq = NULL, **deq = NULL; > >> + > >> + enq = test_enq_data; deq = test_deq_data; > >> + > >> + /* ring is empty */ > >> + CU_ASSERT(1 == _ring_empty(r)); > >> + > >> + /* enqueue 1 object */ > >> + result = __ring_enqueue_bulk(r, enq, 1); > >> + enq += 1; > >> + CU_ASSERT(0 == result); > >> + > >> + /* enqueue 2 objects */ > >> + result = __ring_enqueue_bulk(r, enq, 2); > >> + enq += 2; > >> + CU_ASSERT(0 == result); > >> + > >> + /* enqueue HALF_BULK objects */ > >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); > >> + enq += HALF_BULK; > >> + CU_ASSERT(0 == result); > >> + > >> + /* ring is neither empty nor full */ > >> + CU_ASSERT(0 == _ring_full(r)); > >> + CU_ASSERT(0 == _ring_empty(r)); > >> + > >> + /* _ring_count() equals enqueued */ > >> + count = (1 + 2 + HALF_BULK); > >> + CU_ASSERT(count == _ring_count(r)); > >> + /* _ring_free_count() equals rooms left */ > >> + count = (RING_SIZE - 1) - count; > >> + CU_ASSERT(count == _ring_free_count(r)); > >> + > >> + /* exceed the size, enquene shall fail with -ENOBUFS */ > >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); > >> + CU_ASSERT(-ENOBUFS == result); > >> + > >> + /* fullful the ring */ > >> + result = __ring_enqueue_bulk(r, enq, count); > >> + enq += count; > >> + CU_ASSERT(0 == result); > >> + CU_ASSERT(1 == _ring_full(r)); > >> + > >> + /* dequeue 1 object */ > >> + result = __ring_dequeue_bulk(r, deq, 1); > >> + deq += 1; > >> + CU_ASSERT(0 == result); > >> + > >> + /* dequeue 2 objects */ > >> + result = __ring_dequeue_bulk(r, deq, 2); > >> + deq += 2; > >> + CU_ASSERT(0 == result); > >> + > >> + /* dequeue HALF_BULK objects */ > >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); > >> + deq += HALF_BULK; > >> + CU_ASSERT(0 == result); > >> + > >> + /* _ring_free_count() equals dequeued */ > >> + count = (1 + 2 + HALF_BULK); > >> + CU_ASSERT(count == _ring_free_count(r)); > >> + /* _ring_count() equals remained left */ > >> + count = (RING_SIZE - 1) - count; > >> + CU_ASSERT(count == _ring_count(r)); > >> + > >> + /* underrun the size, dequeue shall fail with -ENOENT */ > >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); > >> + CU_ASSERT(-ENOENT == result); > >> + > >> + /* empty the queue */ > >> + result = __ring_dequeue_bulk(r, deq, count); > >> + deq += count; > >> + CU_ASSERT(0 == result); > >> + CU_ASSERT(1 == _ring_empty(r)); > >> + > >> + /* check data */ > >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > >> + > >> + /* reset dequeue data */ > >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > >> +} > >> + > >> +void __do_basic_watermark(_ring_t *r) > >> +{ > >> + int result = 0; > >> + void * const *source = test_enq_data; > >> + void * const *dest = test_deq_data; > >> + void **enq = NULL, **deq = NULL; > >> + > >> + enq = test_enq_data; deq = test_deq_data; > >> + > >> + /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */ > >> + const unsigned watermark = PIECE_BULK; > >> + const unsigned bulk = (watermark / 4) * 3; > >> + > >> + /* watermark cannot exceed ring size */ > >> + result = _ring_set_water_mark(r, ILLEGAL_SIZE); > >> + CU_ASSERT(-EINVAL == result); > >> + > >> + /* set watermark */ > >> + result = _ring_set_water_mark(r, watermark); > >> + CU_ASSERT(0 == result); > >> + > >> + /* 1st enqueue shall succeed */ > >> + result = __ring_enqueue_bulk(r, enq, bulk); > >> + enq += bulk; > >> + CU_ASSERT(0 == result); > >> + > >> + /* 2nd enqueue shall succeed but return -EDQUOT */ > >> + result = __ring_enqueue_bulk(r, enq, bulk); > >> + enq += bulk; > >> + CU_ASSERT(-EDQUOT == result); > >> + > >> + /* dequeue 1st bulk */ > >> + result = __ring_dequeue_bulk(r, deq, bulk); > >> + deq += bulk; > >> + CU_ASSERT(0 == result); > >> + > >> + /* dequeue 2nd bulk */ > >> + result = __ring_dequeue_bulk(r, deq, bulk); > >> + deq += bulk; > >> + CU_ASSERT(0 == result); > >> + > >> + /* check data */ > >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); > >> + > >> + /* reset watermark */ > >> + result = _ring_set_water_mark(r, 0); > >> + CU_ASSERT(0 == result); > >> + > >> + /* reset dequeue data */ > >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); > >> +} > >> diff --git a/platform/linux-generic/test/ring/ring_main.c > >> b/platform/linux-generic/test/ring/ring_main.c > >> new file mode 100644 > >> index 0000000..e465113 > >> --- /dev/null > >> +++ b/platform/linux-generic/test/ring/ring_main.c > >> @@ -0,0 +1,12 @@ > >> +/* Copyright (c) 2015, Linaro Limited > >> + * All rights reserved. > >> + * > >> + * SPDX-License-Identifier: BSD-3-Clause > >> + */ > >> + > >> +#include "ring_suites.h" > >> + > >> +int main(void) > >> +{ > >> + return ring_suites_main(); > >> +} > >> diff --git a/platform/linux-generic/test/ring/ring_stress.c > >> b/platform/linux-generic/test/ring/ring_stress.c > >> new file mode 100644 > >> index 0000000..a4753e9 > >> --- /dev/null > >> +++ b/platform/linux-generic/test/ring/ring_stress.c > >> @@ -0,0 +1,270 @@ > >> +/* Copyright (c) 2014, Linaro Limited > >> + * All rights reserved. > >> + * > >> + * SPDX-License-Identifier: BSD-3-Clause > >> + */ > >> + > >> +/*- > >> + * BSD LICENSE > >> + * > >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > >> + * All rights reserved. > >> + * > >> + * Redistribution and use in source and binary forms, with or without > >> + * modification, are permitted provided that the following conditions > >> + * are met: > >> + * > >> + * * Redistributions of source code must retain the above copyright > >> + * notice, this list of conditions and the following disclaimer. > >> + * * Redistributions in binary form must reproduce the above > >> copyright > >> + * notice, this list of conditions and the following disclaimer > in > >> + * the documentation and/or other materials provided with the > >> + * distribution. > >> + * * Neither the name of Intel Corporation nor the names of its > >> + * contributors may be used to endorse or promote products > derived > >> + * from this software without specific prior written permission. > >> + * > >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS > >> FOR > >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > >> INCIDENTAL, > >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > >> USE, > >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON > >> ANY > >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR > TORT > >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > >> USE > >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > >> + */ > >> + > >> +/** > >> + * @file > >> + * > >> + * ODP ring stress test > >> + */ > >> + > >> +#include <stdlib.h> > >> +#include <stdio.h> > >> +#include <string.h> > >> + > >> +#include <odp_api.h> > >> +#include <odp/helper/linux.h> > >> +#include <odp_packet_io_ring_internal.h> > >> +#include <test_debug.h> > >> +#include <odp_cunit_common.h> > >> + > >> +#include "ring_suites.h" > >> + > >> +/* > >> + * Since cunit framework cannot work with multi-threading, ask workers > >> + * to save their results for delayed assertion after thread collection. > >> + */ > >> +static int worker_results[MAX_WORKERS]; > >> + > >> +/* > >> + * Note : make sure that both enqueue and dequeue > >> + * operation starts at same time so to avoid data corruption > >> + * Its because atomic lock will protect only indexes, but if order of > >> + * read or write operation incorrect then data mismatch will happen > >> + * So its resposibility of application develop to take care of order of > >> + * data read or write. > >> + */ > >> +typedef enum { > >> + STRESS_1_1_PRODUCER_CONSUMER, > >> + STRESS_1_N_PRODUCER_CONSUMER, > >> + STRESS_N_1_PRODUCER_CONSUMER, > >> + STRESS_N_M_PRODUCER_CONSUMER > >> +} stress_case_t; > >> + > >> +/* worker function declarations */ > >> +static void *stress_worker(void *_data); > >> + > >> +/* global name for later look up in workers' context */ > >> +static const char *ring_name = "stress ring"; > >> + > >> +int ring_test_stress_start(void) > >> +{ > >> + /* multiple thread usage scenario only */ > >> + _ring_t *r_stress = _ring_create(ring_name, RING_SIZE, > >> + 0 /* not used, alignement > >> + taken care inside function: todo */); > >> + if (r_stress == NULL) { > >> + LOG_ERR("create ring failed for stress.\n"); > >> + return -1; > >> + } > >> + > >> + return 0; > >> +} > >> + > >> +void ring_test_stress_1_1_producer_consumer(void) > >> +{ > >> + int i = 0; > >> + odp_cpumask_t cpus; > >> + pthrd_arg worker_param; > >> + > >> + /* reset results for delayed assertion */ > >> + memset(worker_results, 0, sizeof(worker_results)); > >> + > >> + /* request 2 threads to run 1:1 stress */ > >> + worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2); > >> + worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER; > >> + > >> + /* not failure, insufficient resource */ > >> + if (worker_param.numthrds < 2) { > >> + LOG_ERR("insufficient cpu for 1:1 " > >> + "producer/consumer stress.\n"); > >> + return; > >> + } > >> + > >> + /* kick the workers */ > >> + odp_cunit_thread_create(stress_worker, &worker_param); > >> + > >> + /* collect the results */ > >> + odp_cunit_thread_exit(&worker_param); > >> + > >> + /* delayed assertion due to cunit limitation */ > >> + for (i = 0; i < worker_param.numthrds; i++) > >> + CU_ASSERT(0 == worker_results[i]); > >> +} > >> + > >> +void ring_test_stress_N_M_producer_consumer(void) > >> +{ > >> + int i = 0; > >> + odp_cpumask_t cpus; > >> + pthrd_arg worker_param; > >> + > >> + /* reset results for delayed assertion */ > >> + memset(worker_results, 0, sizeof(worker_results)); > >> + > >> + /* request MAX_WORKERS threads to run N:M stress */ > >> + worker_param.numthrds = > >> + odp_cpumask_default_worker(&cpus, MAX_WORKERS); > >> + worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER; > >> + > >> + /* not failure, insufficient resource */ > >> + if (worker_param.numthrds < 3) { > >> + LOG_ERR("insufficient cpu for N:M " > >> + "producer/consumer stress.\n"); > >> + return; > >> + } > >> + > >> + /* kick the workers */ > >> + odp_cunit_thread_create(stress_worker, &worker_param); > >> + > >> + /* collect the results */ > >> + odp_cunit_thread_exit(&worker_param); > >> + > >> + /* delayed assertion due to cunit limitation */ > >> + for (i = 0; i < worker_param.numthrds; i++) > >> + CU_ASSERT(0 == worker_results[i]); > >> +} > >> + > >> +void ring_test_stress_1_N_producer_consumer(void) > >> +{ > >> +} > >> + > >> +void ring_test_stress_N_1_producer_consumer(void) > >> +{ > >> +} > >> + > >> +void ring_test_stress_ring_list_dump(void) > >> +{ > >> + /* improve code coverage */ > >> + _ring_list_dump(); > >> +} > >> + > >> +/* worker function for multiple producer instances */ > >> +static int do_producer(_ring_t *r) > >> +{ > >> + int i, result = 0; > >> + void **enq = NULL; > >> + > >> + /* allocate dummy object pointers for enqueue */ > >> + enq = malloc(PIECE_BULK * 2 * sizeof(void *)); > >> + if (NULL == enq) { > >> + LOG_ERR("insufficient memory for producer enqueue.\n"); > >> + return 0; /* not failure, skip for insufficient memory > */ > >> + } > >> + > >> + /* data pattern to be evaluated later in consumer */ > >> + for (i = 0; i < PIECE_BULK; i++) > >> + enq[i] = (void *)(unsigned long)i; > >> + > >> + do { > >> + result = _ring_mp_enqueue_bulk(r, enq, PIECE_BULK); > >> + if (0 == result) { > >> + free(enq); > >> + return 0; > >> + } > >> + } while (1); > >> +} > >> + > >> +/* worker function for multiple consumer instances */ > >> +static int do_consumer(_ring_t *r) > >> +{ > >> + int i, result = 0; > >> + void **deq = NULL; > >> + const char *message = "test OK!"; > >> + const char *mismatch = "data mismatch..lockless enq/deq > failed."; > >> + > >> + /* allocate dummy object pointers for dequeue */ > >> + deq = malloc(PIECE_BULK * 2 * sizeof(void *)); > >> + if (NULL == deq) { > >> + LOG_ERR("insufficient memory for consumer dequeue.\n"); > >> + return 0; /* not failure, skip for insufficient memory > */ > >> + } > >> + > >> + do { > >> + result = _ring_mc_dequeue_bulk(r, deq, PIECE_BULK); > >> + if (0 == result) { > >> + /* evaluate the data pattern */ > >> + for (i = 0; i < PIECE_BULK; i++) { > >> + if (deq[i] != (void *)(unsigned long)i) > { > >> + result = -1; > >> + message = mismatch; > >> + break; > >> + } > >> + } > >> + > >> + free(deq); > >> + LOG_ERR("%s\n", message); > >> + return result; > >> + } > >> + } while (1); > >> +} > >> + > >> +static void *stress_worker(void *_data) > >> +{ > >> + pthrd_arg *worker_param = (pthrd_arg *)_data; > >> + _ring_t *r_stress = NULL; > >> + > >> + int worker_id = odp_thread_id(); > >> + /* save the worker result for delayed assertion */ > >> + int *result = &worker_results[(worker_id % > >> worker_param->numthrds)]; > >> + > >> + /* verify ring lookup in worker context */ > >> + r_stress = _ring_lookup(ring_name); > >> + if (NULL == r_stress) { > >> + LOG_ERR("ring lookup %s not found\n", ring_name); > >> + *result = -1; > >> + return NULL; > >> + } > >> + > >> + switch (worker_param->testcase) { > >> + case STRESS_1_1_PRODUCER_CONSUMER: > >> + case STRESS_N_M_PRODUCER_CONSUMER: > >> + /* interleaved producer/consumer */ > >> + if (0 == (worker_id % 2)) > >> + *result = do_producer(r_stress); > >> + else if (1 == (worker_id % 2)) > >> + *result = do_consumer(r_stress); > >> + break; > >> + case STRESS_1_N_PRODUCER_CONSUMER: > >> + case STRESS_N_1_PRODUCER_CONSUMER: > >> + default: > >> + LOG_ERR("invalid or not-implemented stress type (%d)\n", > >> + worker_param->testcase); > >> + break; > >> + } > >> + return NULL; > >> +} > >> diff --git a/platform/linux-generic/test/ring/ring_suites.c > >> b/platform/linux-generic/test/ring/ring_suites.c > >> new file mode 100644 > >> index 0000000..b310843 > >> --- /dev/null > >> +++ b/platform/linux-generic/test/ring/ring_suites.c > >> @@ -0,0 +1,70 @@ > >> +/* Copyright (c) 2015, Linaro Limited > >> + * All rights reserved. > >> + * > >> + * SPDX-License-Identifier: BSD-3-Clause > >> + */ > >> + > >> +#include <stdlib.h> > >> +#include <stdio.h> > >> +#include <string.h> > >> + > >> +#include <odp_api.h> > >> +#include <test_debug.h> > >> +#include <odp_cunit_common.h> > >> +#include <odp_packet_io_ring_internal.h> > >> + > >> +#include "ring_suites.h" > >> + > >> +static int ring_suites_init(odp_instance_t *inst) > >> +{ > >> + if (0 != odp_init_global(inst, NULL, NULL)) { > >> + LOG_ERR("error: odp_init_global() failed.\n"); > >> + return -1; > >> + } > >> + if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) { > >> + LOG_ERR("error: odp_init_local() failed.\n"); > >> + return -1; > >> + } > >> + > >> + _ring_tailq_init(); > >> + return 0; > >> +} > >> + > >> +static odp_testinfo_t ring_suite_basic[] = { > >> + ODP_TEST_INFO(ring_test_basic_create), > >> + ODP_TEST_INFO(ring_test_basic_burst), > >> + ODP_TEST_INFO(ring_test_basic_bulk), > >> + ODP_TEST_INFO(ring_test_basic_watermark), > >> + ODP_TEST_INFO_NULL, > >> +}; > >> + > >> +static odp_testinfo_t ring_suite_stress[] = { > >> + ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer), > >> + ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer), > >> + ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer), > >> + ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer), > >> + ODP_TEST_INFO(ring_test_stress_ring_list_dump), > >> + ODP_TEST_INFO_NULL, > >> +}; > >> + > >> +static odp_suiteinfo_t ring_suites[] = { > >> + {"ring basic", ring_test_basic_start, > >> + ring_test_basic_end, ring_suite_basic}, > >> + {"ring stress", ring_test_stress_start, > >> + NULL, ring_suite_stress}, > >> + ODP_SUITE_INFO_NULL > >> +}; > >> + > >> +int ring_suites_main(void) > >> +{ > >> + int ret; > >> + > >> + odp_cunit_register_global_init(ring_suites_init); > >> + > >> + ret = odp_cunit_register(ring_suites); > >> + > >> + if (ret == 0) > >> + ret = odp_cunit_run(); > >> + > >> + return ret; > >> +} > >> diff --git a/platform/linux-generic/test/ring/ring_suites.h > >> b/platform/linux-generic/test/ring/ring_suites.h > >> new file mode 100644 > >> index 0000000..e26b6e8 > >> --- /dev/null > >> +++ b/platform/linux-generic/test/ring/ring_suites.h > >> @@ -0,0 +1,33 @@ > >> +/* Copyright (c) 2015, Linaro Limited > >> + * All rights reserved. > >> + * > >> + * SPDX-License-Identifier: BSD-3-Clause > >> + */ > >> + > >> +#define RING_SIZE 4096 > >> +#define PIECE_BULK 32 > >> + > >> +#define HALF_BULK (RING_SIZE >> 1) > >> +#define ILLEGAL_SIZE (RING_SIZE | 0x3) > >> + > >> +/* test suite start and stop */ > >> +int ring_test_basic_start(void); > >> +int ring_test_basic_end(void); > >> + > >> +/* basic test cases */ > >> +void ring_test_basic_create(void); > >> +void ring_test_basic_burst(void); > >> +void ring_test_basic_bulk(void); > >> +void ring_test_basic_watermark(void); > >> + > >> +/* test suite start and stop */ > >> +int ring_test_stress_start(void); > >> + > >> +/* stress test cases */ > >> +void ring_test_stress_1_1_producer_consumer(void); > >> +void ring_test_stress_1_N_producer_consumer(void); > >> +void ring_test_stress_N_1_producer_consumer(void); > >> +void ring_test_stress_N_M_producer_consumer(void); > >> +void ring_test_stress_ring_list_dump(void); > >> + > >> +int ring_suites_main(void); > >> diff --git a/platform/linux-generic/test/ring/ringtest.c > >> b/platform/linux-generic/test/ring/ringtest.c > >> deleted file mode 100644 > >> index ac0aa61..0000000 > >> --- a/platform/linux-generic/test/ring/ringtest.c > >> +++ /dev/null > >> @@ -1,493 +0,0 @@ > >> -/* Copyright (c) 2014, Linaro Limited > >> - * All rights reserved. > >> - * > >> - * SPDX-License-Identifier: BSD-3-Clause > >> - */ > >> - > >> -/*- > >> - * BSD LICENSE > >> - * > >> - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. > >> - * All rights reserved. > >> - * > >> - * Redistribution and use in source and binary forms, with or without > >> - * modification, are permitted provided that the following conditions > >> - * are met: > >> - * > >> - * * Redistributions of source code must retain the above copyright > >> - * notice, this list of conditions and the following disclaimer. > >> - * * Redistributions in binary form must reproduce the above > >> copyright > >> - * notice, this list of conditions and the following disclaimer > in > >> - * the documentation and/or other materials provided with the > >> - * distribution. > >> - * * Neither the name of Intel Corporation nor the names of its > >> - * contributors may be used to endorse or promote products > derived > >> - * from this software without specific prior written permission. > >> - * > >> - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > CONTRIBUTORS > >> - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT > >> - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS > >> FOR > >> - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE > COPYRIGHT > >> - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, > >> INCIDENTAL, > >> - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > >> - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > >> USE, > >> - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON > >> ANY > >> - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR > TORT > >> - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE > >> USE > >> - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH > DAMAGE. > >> - */ > >> - > >> -/** > >> - * @file > >> - * > >> - * ODP test ring > >> - */ > >> - > >> -#include <stdlib.h> > >> -#include <stdio.h> > >> -#include <string.h> > >> - > >> -#include <odp_api.h> > >> -#include <odp/helper/linux.h> > >> -#include <odp_packet_io_ring_internal.h> > >> -#include <test_debug.h> > >> -#include <odp_cunit_common.h> > >> - > >> -#define RING_SIZE 4096 > >> -#define MAX_BULK 32 > >> - > >> -enum { > >> - ODP_RING_TEST_BASIC, > >> - ODP_RING_TEST_STRESS, > >> -}; > >> - > >> -/* local struct for ring_thread argument */ > >> -typedef struct { > >> - pthrd_arg thrdarg; > >> - int stress_type; > >> -} ring_arg_t; > >> - > >> -static int test_ring_basic(_ring_t *r) > >> -{ > >> - void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = > >> NULL; > >> - int ret; > >> - unsigned i, num_elems; > >> - > >> - /* alloc dummy object pointers */ > >> - src = malloc(RING_SIZE * 2 * sizeof(void *)); > >> - if (src == NULL) { > >> - LOG_ERR("failed to allocate test ring src memory\n"); > >> - goto fail; > >> - } > >> - for (i = 0; i < RING_SIZE * 2; i++) > >> - src[i] = (void *)(unsigned long)i; > >> - > >> - cur_src = src; > >> - > >> - /* alloc some room for copied objects */ > >> - dst = malloc(RING_SIZE * 2 * sizeof(void *)); > >> - if (dst == NULL) { > >> - LOG_ERR("failed to allocate test ring dst memory\n"); > >> - goto fail; > >> - } > >> - > >> - memset(dst, 0, RING_SIZE * 2 * sizeof(void *)); > >> - cur_dst = dst; > >> - > >> - printf("Test SP & SC basic functions\n"); > >> - printf("enqueue 1 obj\n"); > >> - ret = _ring_sp_enqueue_burst(r, cur_src, 1); > >> - cur_src += 1; > >> - if ((ret & _RING_SZ_MASK) != 1) { > >> - LOG_ERR("sp_enq for 1 obj failed\n"); > >> - goto fail; > >> - } > >> - > >> - printf("enqueue 2 objs\n"); > >> - ret = _ring_sp_enqueue_burst(r, cur_src, 2); > >> - cur_src += 2; > >> - if ((ret & _RING_SZ_MASK) != 2) { > >> - LOG_ERR("sp_enq for 2 obj failed\n"); > >> - goto fail; > >> - } > >> - > >> - printf("enqueue MAX_BULK objs\n"); > >> - ret = _ring_sp_enqueue_burst(r, cur_src, MAX_BULK); > >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { > >> - LOG_ERR("sp_enq for %d obj failed\n", MAX_BULK); > >> - goto fail; > >> - } > >> - > >> - printf("dequeue 1 obj\n"); > >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 1); > >> - cur_dst += 1; > >> - if ((ret & _RING_SZ_MASK) != 1) { > >> - LOG_ERR("sc_deq for 1 obj failed\n"); > >> - goto fail; > >> - } > >> - > >> - printf("dequeue 2 objs\n"); > >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 2); > >> - cur_dst += 2; > >> - if ((ret & _RING_SZ_MASK) != 2) { > >> - LOG_ERR("sc_deq for 2 obj failed\n"); > >> - goto fail; > >> - } > >> - > >> - printf("dequeue MAX_BULK objs\n"); > >> - ret = _ring_sc_dequeue_burst(r, cur_dst, MAX_BULK); > >> - cur_dst += MAX_BULK; > >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { > >> - LOG_ERR("sc_deq for %d obj failed\n", MAX_BULK); > >> - goto fail; > >> - } > >> - > >> - /* check data */ > >> - if (memcmp(src, dst, cur_dst - dst)) { > >> - LOG_ERR("data after dequeue is not the same\n"); > >> - goto fail; > >> - } > >> - > >> - cur_src = src; > >> - cur_dst = dst; > >> - > >> - printf("Test MP & MC basic functions\n"); > >> - > >> - printf("enqueue 1 obj\n"); > >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 1); > >> - cur_src += 1; > >> - if (ret != 0) { > >> - LOG_ERR("mp_enq for 1 obj failed\n"); > >> - goto fail; > >> - } > >> - printf("enqueue 2 objs\n"); > >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 2); > >> - cur_src += 2; > >> - if (ret != 0) { > >> - LOG_ERR("mp_enq for 2 obj failed\n"); > >> - goto fail; > >> - } > >> - printf("enqueue MAX_BULK objs\n"); > >> - ret = _ring_mp_enqueue_bulk(r, cur_src, MAX_BULK); > >> - if (ret != 0) { > >> - LOG_ERR("mp_enq for %d obj failed\n", MAX_BULK); > >> - goto fail; > >> - } > >> - printf("dequeue 1 obj\n"); > >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 1); > >> - cur_dst += 1; > >> - if (ret != 0) { > >> - LOG_ERR("mc_deq for 1 obj failed\n"); > >> - goto fail; > >> - } > >> - printf("dequeue 2 objs\n"); > >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 2); > >> - cur_dst += 2; > >> - if (ret != 0) { > >> - LOG_ERR("mc_deq for 2 obj failed\n"); > >> - goto fail; > >> - } > >> - printf("dequeue MAX_BULK objs\n"); > >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK); > >> - cur_dst += MAX_BULK; > >> - if (ret != 0) { > >> - LOG_ERR("mc_deq for %d obj failed\n", MAX_BULK); > >> - goto fail; > >> - } > >> - /* check data */ > >> - if (memcmp(src, dst, cur_dst - dst)) { > >> - LOG_ERR("data after dequeue is not the same\n"); > >> - goto fail; > >> - } > >> - > >> - printf("test watermark and default bulk enqueue / dequeue\n"); > >> - _ring_set_water_mark(r, 20); > >> - num_elems = 16; > >> - > >> - cur_src = src; > >> - cur_dst = dst; > >> - > >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); > >> - cur_src += num_elems; > >> - if (ret != 0) { > >> - LOG_ERR("Cannot enqueue\n"); > >> - goto fail; > >> - } > >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); > >> - if (ret != -EDQUOT) { > >> - LOG_ERR("Watermark not exceeded\n"); > >> - goto fail; > >> - } > >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); > >> - cur_dst += num_elems; > >> - if (ret != 0) { > >> - LOG_ERR("Cannot dequeue\n"); > >> - goto fail; > >> - } > >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); > >> - cur_dst += num_elems; > >> - if (ret != 0) { > >> - LOG_ERR("Cannot dequeue2\n"); > >> - goto fail; > >> - } > >> - > >> - /* check data */ > >> - if (memcmp(src, dst, cur_dst - dst)) { > >> - LOG_ERR("data after dequeue is not the same\n"); > >> - goto fail; > >> - } > >> - > >> - printf("basic enqueu, dequeue test for ring <%s>@%p passed\n", > >> - r->name, r); > >> - > >> - free(src); > >> - free(dst); > >> - return 0; > >> - > >> -fail: > >> - free(src); > >> - free(dst); > >> - return -1; > >> -} > >> - > >> -/* global shared ring used for stress testing */ > >> -static _ring_t *r_stress; > >> - > >> -/* Stress func for Multi producer only */ > >> -static int producer_fn(void) > >> -{ > >> - unsigned i; > >> - > >> - void **src = NULL; > >> - > >> - /* alloc dummy object pointers */ > >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); > >> - if (src == NULL) { > >> - LOG_ERR("failed to allocate producer memory.\n"); > >> - return -1; > >> - } > >> - for (i = 0; i < MAX_BULK; i++) > >> - src[i] = (void *)(unsigned long)i; > >> - > >> - do { > >> - i = _ring_mp_enqueue_bulk(r_stress, src, MAX_BULK); > >> - if (i == 0) { > >> - free(src); > >> - return 0; > >> - } > >> - } while (1); > >> -} > >> - > >> -/* Stress func for Multi consumer only */ > >> -static int consumer_fn(void) > >> -{ > >> - unsigned i; > >> - void **src = NULL; > >> - > >> - /* alloc dummy object pointers */ > >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); > >> - if (src == NULL) { > >> - LOG_ERR("failed to allocate consumer memory.\n"); > >> - return -1; > >> - } > >> - > >> - do { > >> - i = _ring_mc_dequeue_bulk(r_stress, src, MAX_BULK); > >> - if (i == 0) { > >> - for (i = 0; i < MAX_BULK; i++) { > >> - if (src[i] != (void *)(unsigned long)i) > { > >> - free(src); > >> - printf("data mismatch.. lockless > >> ops fail\n"); > >> - return -1; > >> - } > >> - } > >> - free(src); > >> - printf("\n Test OK !\n"); > >> - return 0; > >> - } > >> - } while (1); > >> -} > >> - > >> -/* > >> - * Note : make sure that both enqueue and dequeue > >> - * operation starts at same time so to avoid data corruption > >> - * Its because atomic lock will protect only indexes, but if order of > >> - * read or write operation incorrect then data mismatch will happen > >> - * So its resposibility of application develop to take care of order of > >> - * data read or write. > >> -*/ > >> -typedef enum { > >> - one_enq_one_deq, /* One thread to enqueue one to > >> - dequeu at same time */ > >> - one_enq_rest_deq, /* one thread to enq rest to > >> - dequeue at same time */ > >> - one_deq_rest_enq, /* one to deq and rest enq at very same > >> time */ > >> - multi_enq_multi_deq /* multiple enq,deq */ > >> -} stress_type_t; > >> - > >> -static void test_ring_stress(stress_type_t type) > >> -{ > >> - int thr; > >> - > >> - thr = odp_thread_id(); > >> - > >> - switch (type) { > >> - case one_enq_one_deq: > >> - if (thr == 1) > >> - producer_fn(); > >> - if (thr == 2) > >> - consumer_fn(); > >> - break; > >> - case multi_enq_multi_deq: > >> - if (thr % 2 == 0) > >> - producer_fn(); > >> - else > >> - consumer_fn(); > >> - break; > >> - case one_deq_rest_enq: > >> - case one_enq_rest_deq:/*TBD*/ > >> - default: > >> - LOG_ERR("Invalid stress type or test case yet not > >> supported\n"); > >> - } > >> -} > >> - > >> -static void *test_ring(void *arg) > >> -{ > >> - ring_arg_t *parg = (ring_arg_t *)arg; > >> - int thr; > >> - char ring_name[_RING_NAMESIZE]; > >> - _ring_t *r; > >> - int result = 0; > >> - > >> - thr = odp_thread_id(); > >> - > >> - printf("Thread %i starts\n", thr); > >> - > >> - switch (parg->thrdarg.testcase) { > >> - case ODP_RING_TEST_BASIC: > >> - snprintf(ring_name, sizeof(ring_name), "test_ring_%i", > >> thr); > >> - > >> - r = _ring_create(ring_name, RING_SIZE, > >> - 0 /* not used, alignement > >> - taken care inside func : todo */); > >> - if (r == NULL) { > >> - LOG_ERR("ring create failed\n"); > >> - result = -1; > >> - break; > >> - } > >> - /* lookup ring from its name */ > >> - if (_ring_lookup(ring_name) != r) { > >> - LOG_ERR("ring lookup failed\n"); > >> - result = -1; > >> - break; > >> - } > >> - > >> - /* basic operations */ > >> - if (test_ring_basic(r) < 0) { > >> - LOG_ERR("ring basic enqueue/dequeu ops > failed\n"); > >> - result = -1; > >> - } > >> - > >> - if (result) > >> - _ring_list_dump(); > >> - > >> - break; > >> - > >> - case ODP_RING_TEST_STRESS: > >> - test_ring_stress(parg->stress_type); > >> - > >> - if (result) > >> - _ring_list_dump(); > >> - break; > >> - > >> - default: > >> - LOG_ERR("Invalid test case [%d]\n", > >> parg->thrdarg.testcase); > >> - result = -1; > >> - break; > >> - } > >> - > >> - LOG_DBG("result = %d\n", result); > >> - if (result == 0) > >> - printf("test_ring Result:pass\n"); > >> - else > >> - printf("test_ring Result:fail\n"); > >> - > >> - fflush(stdout); > >> - > >> - return parg; > >> -} > >> - > >> -int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED) > >> -{ > >> - ring_arg_t rarg; > >> - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; > >> - odp_cpumask_t cpu_mask; > >> - int num_workers; > >> - char ring_name[_RING_NAMESIZE]; > >> - odp_instance_t instance; > >> - odph_linux_thr_params_t thr_params; > >> - > >> - if (odp_init_global(&instance, NULL, NULL)) { > >> - LOG_ERR("Error: ODP global init failed.\n"); > >> - exit(EXIT_FAILURE); > >> - } > >> - > >> - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { > >> - LOG_ERR("Error: ODP local init failed.\n"); > >> - exit(EXIT_FAILURE); > >> - } > >> - > >> - _ring_tailq_init(); > >> - > >> - num_workers = odp_cpumask_default_worker(&cpu_mask, > MAX_WORKERS); > >> - rarg.thrdarg.numthrds = rarg.thrdarg.numthrds; > >> - > >> - rarg.thrdarg.testcase = ODP_RING_TEST_BASIC; > >> - > >> - memset(&thr_params, 0, sizeof(thr_params)); > >> - thr_params.start = test_ring; > >> - thr_params.arg = &rarg; > >> - thr_params.thr_type = ODP_THREAD_WORKER; > >> - thr_params.instance = instance; > >> - > >> - printf("starting stess test type : %d..\n", rarg.stress_type); > >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, > &thr_params); > >> - odph_linux_pthread_join(thread_tbl, num_workers); > >> - > >> - rarg.thrdarg.testcase = ODP_RING_TEST_STRESS; > >> - rarg.stress_type = one_enq_one_deq; > >> - > >> - printf("starting stess test type : %d..\n", rarg.stress_type); > >> - snprintf(ring_name, sizeof(ring_name), "test_ring_stress"); > >> - r_stress = _ring_create(ring_name, RING_SIZE, > >> - 0/* not used, alignement > >> - taken care inside func : todo */); > >> - if (r_stress == NULL) { > >> - LOG_ERR("ring create failed\n"); > >> - goto fail; > >> - } > >> - /* lookup ring from its name */ > >> - if (_ring_lookup(ring_name) != r_stress) { > >> - LOG_ERR("ring lookup failed\n"); > >> - goto fail; > >> - } > >> - > >> - thr_params.start = test_ring; > >> - thr_params.arg = &rarg; > >> - > >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, > &thr_params); > >> - odph_linux_pthread_join(thread_tbl, num_workers); > >> - > >> -fail: > >> - if (odp_term_local()) { > >> - LOG_ERR("Error: ODP local term failed.\n"); > >> - exit(EXIT_FAILURE); > >> - } > >> - > >> - if (odp_term_global(instance)) { > >> - LOG_ERR("Error: ODP global term failed.\n"); > >> - exit(EXIT_FAILURE); > >> - } > >> - > >> - return 0; > >> -} > >> > > > > _______________________________________________ > > lng-odp mailing list > > lng-odp@lists.linaro.org > > https://lists.linaro.org/mailman/listinfo/lng-odp > > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > https://lists.linaro.org/mailman/listinfo/lng-odp >
Christophe's patch should be merged very soon so I'd base your revision on that. Bill On Sunday, May 22, 2016, Yi He <yi.he@linaro.org> wrote: > Thanks Maxim and Bill, I'll update copyright to 2016 and remove Intel's > copyright, just one question before I send the v3 patch: > > - I saw Christophe's patches series, shall I update mine based on his > (with command line parameter parsing). > - Or wait until his patch series merged into master/next branch and > then write a new separate patch to add command line parameters parsing. > > Best Regards, Yi > > > On 22 May 2016 at 23:52, Bill Fischofer <bill.fischofer@linaro.org > <javascript:_e(%7B%7D,'cvml','bill.fischofer@linaro.org');>> wrote: > >> I concur with Maxim on the copyrights but other than that: >> >> Reviewed-and-tested-by: Bill Fischofer <bill.fischofer@linaro.org >> <javascript:_e(%7B%7D,'cvml','bill.fischofer@linaro.org');>> >> >> Note that I'm unable to get this test to fail, so this may also be a fix >> to >> the issue discussed in >> https://lists.linaro.org/pipermail/lng-odp/2016-May/023518.html >> >> Might need to resolve conflicts between this patch and Christophe's >> changes >> (I haven't tested to see what conflicts may exist). >> >> On Fri, May 20, 2016 at 7:59 AM, Maxim Uvarov <maxim.uvarov@linaro.org >> <javascript:_e(%7B%7D,'cvml','maxim.uvarov@linaro.org');>> >> wrote: >> >> > Linaros copyright has to be 2016 (in some places you have 2014 in other >> > 2015). >> > >> > ringstress.c is new file and looks like it's pure ODP. Adding Intels >> > copyright there is not right. >> > >> > Maxim. >> > >> > >> > On 05/20/16 11:48, Yi He wrote: >> > >> >> Fixes: https://bugs.linaro.org/show_bug.cgi?id=2228 >> >> >> >> Convert ring test program into cunit framework >> >> Improve LCOV coverage for linux-generic/pktio/ring.c >> >> >> >> Signed-off-by: Yi He <yi.he@linaro.org >> <javascript:_e(%7B%7D,'cvml','yi.he@linaro.org');>> >> >> --- >> >> platform/linux-generic/test/Makefile.am | 2 +- >> >> platform/linux-generic/test/ring/Makefile.am | 20 +- >> >> platform/linux-generic/test/ring/ring_basic.c | 392 >> >> ++++++++++++++++++++ >> >> platform/linux-generic/test/ring/ring_main.c | 12 + >> >> platform/linux-generic/test/ring/ring_stress.c | 270 ++++++++++++++ >> >> platform/linux-generic/test/ring/ring_suites.c | 70 ++++ >> >> platform/linux-generic/test/ring/ring_suites.h | 33 ++ >> >> platform/linux-generic/test/ring/ringtest.c | 493 >> >> ------------------------- >> >> 8 files changed, 787 insertions(+), 505 deletions(-) >> >> create mode 100644 platform/linux-generic/test/ring/ring_basic.c >> >> create mode 100644 platform/linux-generic/test/ring/ring_main.c >> >> create mode 100644 platform/linux-generic/test/ring/ring_stress.c >> >> create mode 100644 platform/linux-generic/test/ring/ring_suites.c >> >> create mode 100644 platform/linux-generic/test/ring/ring_suites.h >> >> delete mode 100644 platform/linux-generic/test/ring/ringtest.c >> >> >> >> diff --git a/platform/linux-generic/test/Makefile.am >> >> b/platform/linux-generic/test/Makefile.am >> >> index f74185d..2d58c57 100644 >> >> --- a/platform/linux-generic/test/Makefile.am >> >> +++ b/platform/linux-generic/test/Makefile.am >> >> @@ -8,7 +8,7 @@ ODP_MODULES = pktio \ >> >> if test_vald >> >> TESTS = pktio/pktio_run.sh \ >> >> pktio/pktio_run_tap.sh \ >> >> - ring/ringtest$(EXEEXT) \ >> >> + ring/ring_main$(EXEEXT) \ >> >> shmem/shmem_linux \ >> >> ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ >> >> ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ >> >> diff --git a/platform/linux-generic/test/ring/Makefile.am >> >> b/platform/linux-generic/test/ring/Makefile.am >> >> index 5a949d0..c086584 100644 >> >> --- a/platform/linux-generic/test/ring/Makefile.am >> >> +++ b/platform/linux-generic/test/ring/Makefile.am >> >> @@ -1,16 +1,14 @@ >> >> -include $(top_srcdir)/test/validation/Makefile.inc >> >> +include ../Makefile.inc >> >> -AM_CFLAGS += -I$(srcdir)/common >> >> -AM_CFLAGS += -I$(top_srcdir)/test/validation/common >> >> -AM_LDFLAGS += -static >> >> +noinst_LTLIBRARIES = libtestring.la >> >> +libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c >> >> +libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP) >> >> -COMPILE_ONLY = >> >> +test_PROGRAMS = ring_main$(EXEEXT) >> >> +dist_ring_main_SOURCES = ring_main.c >> >> -TESTSCRIPTS = >> >> +ring_main_LDFLAGS = $(AM_LDFLAGS) >> >> +ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP) >> >> -EXECUTABLES = ringtest$(EXEEXT) >> >> +noinst_HEADERS = ring_suites.h >> >> -test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) >> >> - >> >> -ringtest_SOURCES = ringtest.c >> >> -ringtest_LDADD = $(LIBCUNIT_COMMON) $(LIBODP) >> >> diff --git a/platform/linux-generic/test/ring/ring_basic.c >> >> b/platform/linux-generic/test/ring/ring_basic.c >> >> new file mode 100644 >> >> index 0000000..20d9786 >> >> --- /dev/null >> >> +++ b/platform/linux-generic/test/ring/ring_basic.c >> >> @@ -0,0 +1,392 @@ >> >> +/* Copyright (c) 2015, Linaro Limited >> >> + * All rights reserved. >> >> + * >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> + */ >> >> + >> >> +/*- >> >> + * BSD LICENSE >> >> + * >> >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> >> + * All rights reserved. >> >> + * >> >> + * Redistribution and use in source and binary forms, with or >> without >> >> + * modification, are permitted provided that the following >> conditions >> >> + * are met: >> >> + * >> >> + * * Redistributions of source code must retain the above >> copyright >> >> + * notice, this list of conditions and the following disclaimer. >> >> + * * Redistributions in binary form must reproduce the above >> >> copyright >> >> + * notice, this list of conditions and the following disclaimer >> in >> >> + * the documentation and/or other materials provided with the >> >> + * distribution. >> >> + * * Neither the name of Intel Corporation nor the names of its >> >> + * contributors may be used to endorse or promote products >> derived >> >> + * from this software without specific prior written permission. >> >> + * >> >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND >> CONTRIBUTORS >> >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> >> FOR >> >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE >> COPYRIGHT >> >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> >> INCIDENTAL, >> >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> >> USE, >> >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> >> ANY >> >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> TORT >> >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> >> USE >> >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH >> DAMAGE. >> >> + */ >> >> + >> >> +/** >> >> + * @file >> >> + * >> >> + * ODP ring basic test >> >> + */ >> >> + >> >> +#include <stdlib.h> >> >> +#include <stdio.h> >> >> +#include <string.h> >> >> + >> >> +#include <test_debug.h> >> >> +#include <odp_cunit_common.h> >> >> +#include <odp_packet_io_ring_internal.h> >> >> + >> >> +#include "ring_suites.h" >> >> + >> >> +/* labor functions declaration */ >> >> +static void __do_basic_burst(_ring_t *r); >> >> +static void __do_basic_bulk(_ring_t *r); >> >> +static void __do_basic_watermark(_ring_t *r); >> >> + >> >> +/* dummy object pointers for enqueue and dequeue testing */ >> >> +static void **test_enq_data; >> >> +static void **test_deq_data; >> >> + >> >> +/* create two rings: one for single thread usage scenario >> >> + * and another for multiple thread usage scenario. >> >> + * st - single thread usage scenario >> >> + * mt - multiple thread usage scenario >> >> + */ >> >> +static const char *st_ring_name = "ST basic ring"; >> >> +static const char *mt_ring_name = "MT basic ring"; >> >> +static _ring_t *st_ring, *mt_ring; >> >> + >> >> +int ring_test_basic_start(void) >> >> +{ >> >> + int i = 0; >> >> + >> >> + /* alloc dummy object pointers for enqueue testing */ >> >> + test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *)); >> >> + if (NULL == test_enq_data) { >> >> + LOG_ERR("failed to allocate basic test enqeue data\n"); >> >> + return -1; >> >> + } >> >> + >> >> + for (i = 0; i < RING_SIZE * 2; i++) >> >> + test_enq_data[i] = (void *)(unsigned long)i; >> >> + >> >> + /* alloc dummy object pointers for dequeue testing */ >> >> + test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *)); >> >> + if (NULL == test_deq_data) { >> >> + LOG_ERR("failed to allocate basic test dequeue >> data\n"); >> >> + free(test_enq_data); test_enq_data = NULL; >> >> + return -1; >> >> + } >> >> + >> >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> >> + return 0; >> >> +} >> >> + >> >> +int ring_test_basic_end(void) >> >> +{ >> >> + free(test_enq_data); >> >> + free(test_deq_data); >> >> + return 0; >> >> +} >> >> + >> >> +/* basic test cases */ >> >> +void ring_test_basic_create(void) >> >> +{ >> >> + /* prove illegal size shall fail */ >> >> + st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0); >> >> + CU_ASSERT(NULL == st_ring); >> >> + CU_ASSERT(EINVAL == __odp_errno); >> >> + >> >> + /* create ring for single thread usage scenario */ >> >> + st_ring = _ring_create(st_ring_name, RING_SIZE, >> >> + _RING_F_SP_ENQ | _RING_F_SC_DEQ); >> >> + >> >> + CU_ASSERT(NULL != st_ring); >> >> + CU_ASSERT(_ring_lookup(st_ring_name) == st_ring); >> >> + >> >> + /* create ring for multiple thread usage scenario */ >> >> + mt_ring = _ring_create(mt_ring_name, RING_SIZE, >> >> + 0 /* not used, alignement >> >> + taken care inside function: todo */); >> >> + >> >> + CU_ASSERT(NULL != mt_ring); >> >> + CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring); >> >> +} >> >> + >> >> +void ring_test_basic_burst(void) >> >> +{ >> >> + /* two rounds to cover both single >> >> + * thread and multiple thread APIs >> >> + */ >> >> + __do_basic_burst(st_ring); >> >> + __do_basic_burst(mt_ring); >> >> +} >> >> + >> >> +void ring_test_basic_bulk(void) >> >> +{ >> >> + __do_basic_bulk(st_ring); >> >> + __do_basic_bulk(mt_ring); >> >> +} >> >> + >> >> +void ring_test_basic_watermark(void) >> >> +{ >> >> + __do_basic_watermark(st_ring); >> >> + __do_basic_watermark(mt_ring); >> >> +} >> >> + >> >> +/* labor functions definition */ >> >> +static void __do_basic_burst(_ring_t *r) >> >> +{ >> >> + int result = 0; >> >> + unsigned int count = 0; >> >> + void * const *source = test_enq_data; >> >> + void * const *dest = test_deq_data; >> >> + void **enq = NULL, **deq = NULL; >> >> + >> >> + enq = test_enq_data; deq = test_deq_data; >> >> + >> >> + /* ring is empty */ >> >> + CU_ASSERT(1 == _ring_empty(r)); >> >> + >> >> + /* enqueue 1 object */ >> >> + result = _ring_enqueue_burst(r, enq, 1); >> >> + enq += 1; >> >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); >> >> + >> >> + /* enqueue 2 objects */ >> >> + result = _ring_enqueue_burst(r, enq, 2); >> >> + enq += 2; >> >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); >> >> + >> >> + /* enqueue HALF_BULK objects */ >> >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); >> >> + enq += HALF_BULK; >> >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); >> >> + >> >> + /* ring is neither empty nor full */ >> >> + CU_ASSERT(0 == _ring_full(r)); >> >> + CU_ASSERT(0 == _ring_empty(r)); >> >> + >> >> + /* _ring_count() equals enqueued */ >> >> + count = (1 + 2 + HALF_BULK); >> >> + CU_ASSERT(count == _ring_count(r)); >> >> + /* _ring_free_count() equals rooms left */ >> >> + count = (RING_SIZE - 1) - count; >> >> + CU_ASSERT(count == _ring_free_count(r)); >> >> + >> >> + /* exceed the size, enquene as many as possible */ >> >> + result = _ring_enqueue_burst(r, enq, HALF_BULK); >> >> + enq += count; >> >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); >> >> + CU_ASSERT(1 == _ring_full(r)); >> >> + >> >> + /* dequeue 1 object */ >> >> + result = _ring_dequeue_burst(r, deq, 1); >> >> + deq += 1; >> >> + CU_ASSERT(1 == (result & _RING_SZ_MASK)); >> >> + >> >> + /* dequeue 2 objects */ >> >> + result = _ring_dequeue_burst(r, deq, 2); >> >> + deq += 2; >> >> + CU_ASSERT(2 == (result & _RING_SZ_MASK)); >> >> + >> >> + /* dequeue HALF_BULK objects */ >> >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); >> >> + deq += HALF_BULK; >> >> + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); >> >> + >> >> + /* _ring_free_count() equals dequeued */ >> >> + count = (1 + 2 + HALF_BULK); >> >> + CU_ASSERT(count == _ring_free_count(r)); >> >> + /* _ring_count() equals remained left */ >> >> + count = (RING_SIZE - 1) - count; >> >> + CU_ASSERT(count == _ring_count(r)); >> >> + >> >> + /* underrun the size, dequeue as many as possible */ >> >> + result = _ring_dequeue_burst(r, deq, HALF_BULK); >> >> + deq += count; >> >> + CU_ASSERT(count == (result & _RING_SZ_MASK)); >> >> + CU_ASSERT(1 == _ring_empty(r)); >> >> + >> >> + /* check data */ >> >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> >> + >> >> + /* reset dequeue data */ >> >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> >> +} >> >> + >> >> +/* incomplete ring API set: strange! >> >> + * complement _ring_enqueue/dequeue_bulk to improve coverage >> >> + */ >> >> +static inline int __ring_enqueue_bulk( >> >> + _ring_t *r, void * const *objects, unsigned bulk) >> >> +{ >> >> + if (r->prod.sp_enqueue) >> >> + return _ring_sp_enqueue_bulk(r, objects, bulk); >> >> + else >> >> + return _ring_mp_enqueue_bulk(r, objects, bulk); >> >> +} >> >> + >> >> +static inline int __ring_dequeue_bulk( >> >> + _ring_t *r, void **objects, unsigned bulk) >> >> +{ >> >> + if (r->cons.sc_dequeue) >> >> + return _ring_sc_dequeue_bulk(r, objects, bulk); >> >> + else >> >> + return _ring_mc_dequeue_bulk(r, objects, bulk); >> >> +} >> >> + >> >> +static void __do_basic_bulk(_ring_t *r) >> >> +{ >> >> + int result = 0; >> >> + unsigned int count = 0; >> >> + void * const *source = test_enq_data; >> >> + void * const *dest = test_deq_data; >> >> + void **enq = NULL, **deq = NULL; >> >> + >> >> + enq = test_enq_data; deq = test_deq_data; >> >> + >> >> + /* ring is empty */ >> >> + CU_ASSERT(1 == _ring_empty(r)); >> >> + >> >> + /* enqueue 1 object */ >> >> + result = __ring_enqueue_bulk(r, enq, 1); >> >> + enq += 1; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* enqueue 2 objects */ >> >> + result = __ring_enqueue_bulk(r, enq, 2); >> >> + enq += 2; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* enqueue HALF_BULK objects */ >> >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); >> >> + enq += HALF_BULK; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* ring is neither empty nor full */ >> >> + CU_ASSERT(0 == _ring_full(r)); >> >> + CU_ASSERT(0 == _ring_empty(r)); >> >> + >> >> + /* _ring_count() equals enqueued */ >> >> + count = (1 + 2 + HALF_BULK); >> >> + CU_ASSERT(count == _ring_count(r)); >> >> + /* _ring_free_count() equals rooms left */ >> >> + count = (RING_SIZE - 1) - count; >> >> + CU_ASSERT(count == _ring_free_count(r)); >> >> + >> >> + /* exceed the size, enquene shall fail with -ENOBUFS */ >> >> + result = __ring_enqueue_bulk(r, enq, HALF_BULK); >> >> + CU_ASSERT(-ENOBUFS == result); >> >> + >> >> + /* fullful the ring */ >> >> + result = __ring_enqueue_bulk(r, enq, count); >> >> + enq += count; >> >> + CU_ASSERT(0 == result); >> >> + CU_ASSERT(1 == _ring_full(r)); >> >> + >> >> + /* dequeue 1 object */ >> >> + result = __ring_dequeue_bulk(r, deq, 1); >> >> + deq += 1; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* dequeue 2 objects */ >> >> + result = __ring_dequeue_bulk(r, deq, 2); >> >> + deq += 2; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* dequeue HALF_BULK objects */ >> >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); >> >> + deq += HALF_BULK; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* _ring_free_count() equals dequeued */ >> >> + count = (1 + 2 + HALF_BULK); >> >> + CU_ASSERT(count == _ring_free_count(r)); >> >> + /* _ring_count() equals remained left */ >> >> + count = (RING_SIZE - 1) - count; >> >> + CU_ASSERT(count == _ring_count(r)); >> >> + >> >> + /* underrun the size, dequeue shall fail with -ENOENT */ >> >> + result = __ring_dequeue_bulk(r, deq, HALF_BULK); >> >> + CU_ASSERT(-ENOENT == result); >> >> + >> >> + /* empty the queue */ >> >> + result = __ring_dequeue_bulk(r, deq, count); >> >> + deq += count; >> >> + CU_ASSERT(0 == result); >> >> + CU_ASSERT(1 == _ring_empty(r)); >> >> + >> >> + /* check data */ >> >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> >> + >> >> + /* reset dequeue data */ >> >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> >> +} >> >> + >> >> +void __do_basic_watermark(_ring_t *r) >> >> +{ >> >> + int result = 0; >> >> + void * const *source = test_enq_data; >> >> + void * const *dest = test_deq_data; >> >> + void **enq = NULL, **deq = NULL; >> >> + >> >> + enq = test_enq_data; deq = test_deq_data; >> >> + >> >> + /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */ >> >> + const unsigned watermark = PIECE_BULK; >> >> + const unsigned bulk = (watermark / 4) * 3; >> >> + >> >> + /* watermark cannot exceed ring size */ >> >> + result = _ring_set_water_mark(r, ILLEGAL_SIZE); >> >> + CU_ASSERT(-EINVAL == result); >> >> + >> >> + /* set watermark */ >> >> + result = _ring_set_water_mark(r, watermark); >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* 1st enqueue shall succeed */ >> >> + result = __ring_enqueue_bulk(r, enq, bulk); >> >> + enq += bulk; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* 2nd enqueue shall succeed but return -EDQUOT */ >> >> + result = __ring_enqueue_bulk(r, enq, bulk); >> >> + enq += bulk; >> >> + CU_ASSERT(-EDQUOT == result); >> >> + >> >> + /* dequeue 1st bulk */ >> >> + result = __ring_dequeue_bulk(r, deq, bulk); >> >> + deq += bulk; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* dequeue 2nd bulk */ >> >> + result = __ring_dequeue_bulk(r, deq, bulk); >> >> + deq += bulk; >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* check data */ >> >> + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); >> >> + >> >> + /* reset watermark */ >> >> + result = _ring_set_water_mark(r, 0); >> >> + CU_ASSERT(0 == result); >> >> + >> >> + /* reset dequeue data */ >> >> + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); >> >> +} >> >> diff --git a/platform/linux-generic/test/ring/ring_main.c >> >> b/platform/linux-generic/test/ring/ring_main.c >> >> new file mode 100644 >> >> index 0000000..e465113 >> >> --- /dev/null >> >> +++ b/platform/linux-generic/test/ring/ring_main.c >> >> @@ -0,0 +1,12 @@ >> >> +/* Copyright (c) 2015, Linaro Limited >> >> + * All rights reserved. >> >> + * >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> + */ >> >> + >> >> +#include "ring_suites.h" >> >> + >> >> +int main(void) >> >> +{ >> >> + return ring_suites_main(); >> >> +} >> >> diff --git a/platform/linux-generic/test/ring/ring_stress.c >> >> b/platform/linux-generic/test/ring/ring_stress.c >> >> new file mode 100644 >> >> index 0000000..a4753e9 >> >> --- /dev/null >> >> +++ b/platform/linux-generic/test/ring/ring_stress.c >> >> @@ -0,0 +1,270 @@ >> >> +/* Copyright (c) 2014, Linaro Limited >> >> + * All rights reserved. >> >> + * >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> + */ >> >> + >> >> +/*- >> >> + * BSD LICENSE >> >> + * >> >> + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> >> + * All rights reserved. >> >> + * >> >> + * Redistribution and use in source and binary forms, with or >> without >> >> + * modification, are permitted provided that the following >> conditions >> >> + * are met: >> >> + * >> >> + * * Redistributions of source code must retain the above >> copyright >> >> + * notice, this list of conditions and the following disclaimer. >> >> + * * Redistributions in binary form must reproduce the above >> >> copyright >> >> + * notice, this list of conditions and the following disclaimer >> in >> >> + * the documentation and/or other materials provided with the >> >> + * distribution. >> >> + * * Neither the name of Intel Corporation nor the names of its >> >> + * contributors may be used to endorse or promote products >> derived >> >> + * from this software without specific prior written permission. >> >> + * >> >> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND >> CONTRIBUTORS >> >> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> >> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> >> FOR >> >> + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE >> COPYRIGHT >> >> + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> >> INCIDENTAL, >> >> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> >> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> >> USE, >> >> + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> >> ANY >> >> + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> TORT >> >> + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> >> USE >> >> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH >> DAMAGE. >> >> + */ >> >> + >> >> +/** >> >> + * @file >> >> + * >> >> + * ODP ring stress test >> >> + */ >> >> + >> >> +#include <stdlib.h> >> >> +#include <stdio.h> >> >> +#include <string.h> >> >> + >> >> +#include <odp_api.h> >> >> +#include <odp/helper/linux.h> >> >> +#include <odp_packet_io_ring_internal.h> >> >> +#include <test_debug.h> >> >> +#include <odp_cunit_common.h> >> >> + >> >> +#include "ring_suites.h" >> >> + >> >> +/* >> >> + * Since cunit framework cannot work with multi-threading, ask workers >> >> + * to save their results for delayed assertion after thread >> collection. >> >> + */ >> >> +static int worker_results[MAX_WORKERS]; >> >> + >> >> +/* >> >> + * Note : make sure that both enqueue and dequeue >> >> + * operation starts at same time so to avoid data corruption >> >> + * Its because atomic lock will protect only indexes, but if order of >> >> + * read or write operation incorrect then data mismatch will happen >> >> + * So its resposibility of application develop to take care of order >> of >> >> + * data read or write. >> >> + */ >> >> +typedef enum { >> >> + STRESS_1_1_PRODUCER_CONSUMER, >> >> + STRESS_1_N_PRODUCER_CONSUMER, >> >> + STRESS_N_1_PRODUCER_CONSUMER, >> >> + STRESS_N_M_PRODUCER_CONSUMER >> >> +} stress_case_t; >> >> + >> >> +/* worker function declarations */ >> >> +static void *stress_worker(void *_data); >> >> + >> >> +/* global name for later look up in workers' context */ >> >> +static const char *ring_name = "stress ring"; >> >> + >> >> +int ring_test_stress_start(void) >> >> +{ >> >> + /* multiple thread usage scenario only */ >> >> + _ring_t *r_stress = _ring_create(ring_name, RING_SIZE, >> >> + 0 /* not used, alignement >> >> + taken care inside function: todo */); >> >> + if (r_stress == NULL) { >> >> + LOG_ERR("create ring failed for stress.\n"); >> >> + return -1; >> >> + } >> >> + >> >> + return 0; >> >> +} >> >> + >> >> +void ring_test_stress_1_1_producer_consumer(void) >> >> +{ >> >> + int i = 0; >> >> + odp_cpumask_t cpus; >> >> + pthrd_arg worker_param; >> >> + >> >> + /* reset results for delayed assertion */ >> >> + memset(worker_results, 0, sizeof(worker_results)); >> >> + >> >> + /* request 2 threads to run 1:1 stress */ >> >> + worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2); >> >> + worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER; >> >> + >> >> + /* not failure, insufficient resource */ >> >> + if (worker_param.numthrds < 2) { >> >> + LOG_ERR("insufficient cpu for 1:1 " >> >> + "producer/consumer stress.\n"); >> >> + return; >> >> + } >> >> + >> >> + /* kick the workers */ >> >> + odp_cunit_thread_create(stress_worker, &worker_param); >> >> + >> >> + /* collect the results */ >> >> + odp_cunit_thread_exit(&worker_param); >> >> + >> >> + /* delayed assertion due to cunit limitation */ >> >> + for (i = 0; i < worker_param.numthrds; i++) >> >> + CU_ASSERT(0 == worker_results[i]); >> >> +} >> >> + >> >> +void ring_test_stress_N_M_producer_consumer(void) >> >> +{ >> >> + int i = 0; >> >> + odp_cpumask_t cpus; >> >> + pthrd_arg worker_param; >> >> + >> >> + /* reset results for delayed assertion */ >> >> + memset(worker_results, 0, sizeof(worker_results)); >> >> + >> >> + /* request MAX_WORKERS threads to run N:M stress */ >> >> + worker_param.numthrds = >> >> + odp_cpumask_default_worker(&cpus, MAX_WORKERS); >> >> + worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER; >> >> + >> >> + /* not failure, insufficient resource */ >> >> + if (worker_param.numthrds < 3) { >> >> + LOG_ERR("insufficient cpu for N:M " >> >> + "producer/consumer stress.\n"); >> >> + return; >> >> + } >> >> + >> >> + /* kick the workers */ >> >> + odp_cunit_thread_create(stress_worker, &worker_param); >> >> + >> >> + /* collect the results */ >> >> + odp_cunit_thread_exit(&worker_param); >> >> + >> >> + /* delayed assertion due to cunit limitation */ >> >> + for (i = 0; i < worker_param.numthrds; i++) >> >> + CU_ASSERT(0 == worker_results[i]); >> >> +} >> >> + >> >> +void ring_test_stress_1_N_producer_consumer(void) >> >> +{ >> >> +} >> >> + >> >> +void ring_test_stress_N_1_producer_consumer(void) >> >> +{ >> >> +} >> >> + >> >> +void ring_test_stress_ring_list_dump(void) >> >> +{ >> >> + /* improve code coverage */ >> >> + _ring_list_dump(); >> >> +} >> >> + >> >> +/* worker function for multiple producer instances */ >> >> +static int do_producer(_ring_t *r) >> >> +{ >> >> + int i, result = 0; >> >> + void **enq = NULL; >> >> + >> >> + /* allocate dummy object pointers for enqueue */ >> >> + enq = malloc(PIECE_BULK * 2 * sizeof(void *)); >> >> + if (NULL == enq) { >> >> + LOG_ERR("insufficient memory for producer enqueue.\n"); >> >> + return 0; /* not failure, skip for insufficient memory >> */ >> >> + } >> >> + >> >> + /* data pattern to be evaluated later in consumer */ >> >> + for (i = 0; i < PIECE_BULK; i++) >> >> + enq[i] = (void *)(unsigned long)i; >> >> + >> >> + do { >> >> + result = _ring_mp_enqueue_bulk(r, enq, PIECE_BULK); >> >> + if (0 == result) { >> >> + free(enq); >> >> + return 0; >> >> + } >> >> + } while (1); >> >> +} >> >> + >> >> +/* worker function for multiple consumer instances */ >> >> +static int do_consumer(_ring_t *r) >> >> +{ >> >> + int i, result = 0; >> >> + void **deq = NULL; >> >> + const char *message = "test OK!"; >> >> + const char *mismatch = "data mismatch..lockless enq/deq >> failed."; >> >> + >> >> + /* allocate dummy object pointers for dequeue */ >> >> + deq = malloc(PIECE_BULK * 2 * sizeof(void *)); >> >> + if (NULL == deq) { >> >> + LOG_ERR("insufficient memory for consumer dequeue.\n"); >> >> + return 0; /* not failure, skip for insufficient memory >> */ >> >> + } >> >> + >> >> + do { >> >> + result = _ring_mc_dequeue_bulk(r, deq, PIECE_BULK); >> >> + if (0 == result) { >> >> + /* evaluate the data pattern */ >> >> + for (i = 0; i < PIECE_BULK; i++) { >> >> + if (deq[i] != (void *)(unsigned >> long)i) { >> >> + result = -1; >> >> + message = mismatch; >> >> + break; >> >> + } >> >> + } >> >> + >> >> + free(deq); >> >> + LOG_ERR("%s\n", message); >> >> + return result; >> >> + } >> >> + } while (1); >> >> +} >> >> + >> >> +static void *stress_worker(void *_data) >> >> +{ >> >> + pthrd_arg *worker_param = (pthrd_arg *)_data; >> >> + _ring_t *r_stress = NULL; >> >> + >> >> + int worker_id = odp_thread_id(); >> >> + /* save the worker result for delayed assertion */ >> >> + int *result = &worker_results[(worker_id % >> >> worker_param->numthrds)]; >> >> + >> >> + /* verify ring lookup in worker context */ >> >> + r_stress = _ring_lookup(ring_name); >> >> + if (NULL == r_stress) { >> >> + LOG_ERR("ring lookup %s not found\n", ring_name); >> >> + *result = -1; >> >> + return NULL; >> >> + } >> >> + >> >> + switch (worker_param->testcase) { >> >> + case STRESS_1_1_PRODUCER_CONSUMER: >> >> + case STRESS_N_M_PRODUCER_CONSUMER: >> >> + /* interleaved producer/consumer */ >> >> + if (0 == (worker_id % 2)) >> >> + *result = do_producer(r_stress); >> >> + else if (1 == (worker_id % 2)) >> >> + *result = do_consumer(r_stress); >> >> + break; >> >> + case STRESS_1_N_PRODUCER_CONSUMER: >> >> + case STRESS_N_1_PRODUCER_CONSUMER: >> >> + default: >> >> + LOG_ERR("invalid or not-implemented stress type >> (%d)\n", >> >> + worker_param->testcase); >> >> + break; >> >> + } >> >> + return NULL; >> >> +} >> >> diff --git a/platform/linux-generic/test/ring/ring_suites.c >> >> b/platform/linux-generic/test/ring/ring_suites.c >> >> new file mode 100644 >> >> index 0000000..b310843 >> >> --- /dev/null >> >> +++ b/platform/linux-generic/test/ring/ring_suites.c >> >> @@ -0,0 +1,70 @@ >> >> +/* Copyright (c) 2015, Linaro Limited >> >> + * All rights reserved. >> >> + * >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> + */ >> >> + >> >> +#include <stdlib.h> >> >> +#include <stdio.h> >> >> +#include <string.h> >> >> + >> >> +#include <odp_api.h> >> >> +#include <test_debug.h> >> >> +#include <odp_cunit_common.h> >> >> +#include <odp_packet_io_ring_internal.h> >> >> + >> >> +#include "ring_suites.h" >> >> + >> >> +static int ring_suites_init(odp_instance_t *inst) >> >> +{ >> >> + if (0 != odp_init_global(inst, NULL, NULL)) { >> >> + LOG_ERR("error: odp_init_global() failed.\n"); >> >> + return -1; >> >> + } >> >> + if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) { >> >> + LOG_ERR("error: odp_init_local() failed.\n"); >> >> + return -1; >> >> + } >> >> + >> >> + _ring_tailq_init(); >> >> + return 0; >> >> +} >> >> + >> >> +static odp_testinfo_t ring_suite_basic[] = { >> >> + ODP_TEST_INFO(ring_test_basic_create), >> >> + ODP_TEST_INFO(ring_test_basic_burst), >> >> + ODP_TEST_INFO(ring_test_basic_bulk), >> >> + ODP_TEST_INFO(ring_test_basic_watermark), >> >> + ODP_TEST_INFO_NULL, >> >> +}; >> >> + >> >> +static odp_testinfo_t ring_suite_stress[] = { >> >> + ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer), >> >> + ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer), >> >> + ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer), >> >> + ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer), >> >> + ODP_TEST_INFO(ring_test_stress_ring_list_dump), >> >> + ODP_TEST_INFO_NULL, >> >> +}; >> >> + >> >> +static odp_suiteinfo_t ring_suites[] = { >> >> + {"ring basic", ring_test_basic_start, >> >> + ring_test_basic_end, ring_suite_basic}, >> >> + {"ring stress", ring_test_stress_start, >> >> + NULL, ring_suite_stress}, >> >> + ODP_SUITE_INFO_NULL >> >> +}; >> >> + >> >> +int ring_suites_main(void) >> >> +{ >> >> + int ret; >> >> + >> >> + odp_cunit_register_global_init(ring_suites_init); >> >> + >> >> + ret = odp_cunit_register(ring_suites); >> >> + >> >> + if (ret == 0) >> >> + ret = odp_cunit_run(); >> >> + >> >> + return ret; >> >> +} >> >> diff --git a/platform/linux-generic/test/ring/ring_suites.h >> >> b/platform/linux-generic/test/ring/ring_suites.h >> >> new file mode 100644 >> >> index 0000000..e26b6e8 >> >> --- /dev/null >> >> +++ b/platform/linux-generic/test/ring/ring_suites.h >> >> @@ -0,0 +1,33 @@ >> >> +/* Copyright (c) 2015, Linaro Limited >> >> + * All rights reserved. >> >> + * >> >> + * SPDX-License-Identifier: BSD-3-Clause >> >> + */ >> >> + >> >> +#define RING_SIZE 4096 >> >> +#define PIECE_BULK 32 >> >> + >> >> +#define HALF_BULK (RING_SIZE >> 1) >> >> +#define ILLEGAL_SIZE (RING_SIZE | 0x3) >> >> + >> >> +/* test suite start and stop */ >> >> +int ring_test_basic_start(void); >> >> +int ring_test_basic_end(void); >> >> + >> >> +/* basic test cases */ >> >> +void ring_test_basic_create(void); >> >> +void ring_test_basic_burst(void); >> >> +void ring_test_basic_bulk(void); >> >> +void ring_test_basic_watermark(void); >> >> + >> >> +/* test suite start and stop */ >> >> +int ring_test_stress_start(void); >> >> + >> >> +/* stress test cases */ >> >> +void ring_test_stress_1_1_producer_consumer(void); >> >> +void ring_test_stress_1_N_producer_consumer(void); >> >> +void ring_test_stress_N_1_producer_consumer(void); >> >> +void ring_test_stress_N_M_producer_consumer(void); >> >> +void ring_test_stress_ring_list_dump(void); >> >> + >> >> +int ring_suites_main(void); >> >> diff --git a/platform/linux-generic/test/ring/ringtest.c >> >> b/platform/linux-generic/test/ring/ringtest.c >> >> deleted file mode 100644 >> >> index ac0aa61..0000000 >> >> --- a/platform/linux-generic/test/ring/ringtest.c >> >> +++ /dev/null >> >> @@ -1,493 +0,0 @@ >> >> -/* Copyright (c) 2014, Linaro Limited >> >> - * All rights reserved. >> >> - * >> >> - * SPDX-License-Identifier: BSD-3-Clause >> >> - */ >> >> - >> >> -/*- >> >> - * BSD LICENSE >> >> - * >> >> - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. >> >> - * All rights reserved. >> >> - * >> >> - * Redistribution and use in source and binary forms, with or >> without >> >> - * modification, are permitted provided that the following >> conditions >> >> - * are met: >> >> - * >> >> - * * Redistributions of source code must retain the above >> copyright >> >> - * notice, this list of conditions and the following disclaimer. >> >> - * * Redistributions in binary form must reproduce the above >> >> copyright >> >> - * notice, this list of conditions and the following disclaimer >> in >> >> - * the documentation and/or other materials provided with the >> >> - * distribution. >> >> - * * Neither the name of Intel Corporation nor the names of its >> >> - * contributors may be used to endorse or promote products >> derived >> >> - * from this software without specific prior written permission. >> >> - * >> >> - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND >> CONTRIBUTORS >> >> - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >> >> - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS >> >> FOR >> >> - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE >> COPYRIGHT >> >> - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, >> >> INCIDENTAL, >> >> - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >> >> - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF >> >> USE, >> >> - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON >> >> ANY >> >> - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR >> TORT >> >> - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE >> >> USE >> >> - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH >> DAMAGE. >> >> - */ >> >> - >> >> -/** >> >> - * @file >> >> - * >> >> - * ODP test ring >> >> - */ >> >> - >> >> -#include <stdlib.h> >> >> -#include <stdio.h> >> >> -#include <string.h> >> >> - >> >> -#include <odp_api.h> >> >> -#include <odp/helper/linux.h> >> >> -#include <odp_packet_io_ring_internal.h> >> >> -#include <test_debug.h> >> >> -#include <odp_cunit_common.h> >> >> - >> >> -#define RING_SIZE 4096 >> >> -#define MAX_BULK 32 >> >> - >> >> -enum { >> >> - ODP_RING_TEST_BASIC, >> >> - ODP_RING_TEST_STRESS, >> >> -}; >> >> - >> >> -/* local struct for ring_thread argument */ >> >> -typedef struct { >> >> - pthrd_arg thrdarg; >> >> - int stress_type; >> >> -} ring_arg_t; >> >> - >> >> -static int test_ring_basic(_ring_t *r) >> >> -{ >> >> - void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = >> >> NULL; >> >> - int ret; >> >> - unsigned i, num_elems; >> >> - >> >> - /* alloc dummy object pointers */ >> >> - src = malloc(RING_SIZE * 2 * sizeof(void *)); >> >> - if (src == NULL) { >> >> - LOG_ERR("failed to allocate test ring src memory\n"); >> >> - goto fail; >> >> - } >> >> - for (i = 0; i < RING_SIZE * 2; i++) >> >> - src[i] = (void *)(unsigned long)i; >> >> - >> >> - cur_src = src; >> >> - >> >> - /* alloc some room for copied objects */ >> >> - dst = malloc(RING_SIZE * 2 * sizeof(void *)); >> >> - if (dst == NULL) { >> >> - LOG_ERR("failed to allocate test ring dst memory\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - memset(dst, 0, RING_SIZE * 2 * sizeof(void *)); >> >> - cur_dst = dst; >> >> - >> >> - printf("Test SP & SC basic functions\n"); >> >> - printf("enqueue 1 obj\n"); >> >> - ret = _ring_sp_enqueue_burst(r, cur_src, 1); >> >> - cur_src += 1; >> >> - if ((ret & _RING_SZ_MASK) != 1) { >> >> - LOG_ERR("sp_enq for 1 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("enqueue 2 objs\n"); >> >> - ret = _ring_sp_enqueue_burst(r, cur_src, 2); >> >> - cur_src += 2; >> >> - if ((ret & _RING_SZ_MASK) != 2) { >> >> - LOG_ERR("sp_enq for 2 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("enqueue MAX_BULK objs\n"); >> >> - ret = _ring_sp_enqueue_burst(r, cur_src, MAX_BULK); >> >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { >> >> - LOG_ERR("sp_enq for %d obj failed\n", MAX_BULK); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("dequeue 1 obj\n"); >> >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 1); >> >> - cur_dst += 1; >> >> - if ((ret & _RING_SZ_MASK) != 1) { >> >> - LOG_ERR("sc_deq for 1 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("dequeue 2 objs\n"); >> >> - ret = _ring_sc_dequeue_burst(r, cur_dst, 2); >> >> - cur_dst += 2; >> >> - if ((ret & _RING_SZ_MASK) != 2) { >> >> - LOG_ERR("sc_deq for 2 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("dequeue MAX_BULK objs\n"); >> >> - ret = _ring_sc_dequeue_burst(r, cur_dst, MAX_BULK); >> >> - cur_dst += MAX_BULK; >> >> - if ((ret & _RING_SZ_MASK) != MAX_BULK) { >> >> - LOG_ERR("sc_deq for %d obj failed\n", MAX_BULK); >> >> - goto fail; >> >> - } >> >> - >> >> - /* check data */ >> >> - if (memcmp(src, dst, cur_dst - dst)) { >> >> - LOG_ERR("data after dequeue is not the same\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - cur_src = src; >> >> - cur_dst = dst; >> >> - >> >> - printf("Test MP & MC basic functions\n"); >> >> - >> >> - printf("enqueue 1 obj\n"); >> >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 1); >> >> - cur_src += 1; >> >> - if (ret != 0) { >> >> - LOG_ERR("mp_enq for 1 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - printf("enqueue 2 objs\n"); >> >> - ret = _ring_mp_enqueue_bulk(r, cur_src, 2); >> >> - cur_src += 2; >> >> - if (ret != 0) { >> >> - LOG_ERR("mp_enq for 2 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - printf("enqueue MAX_BULK objs\n"); >> >> - ret = _ring_mp_enqueue_bulk(r, cur_src, MAX_BULK); >> >> - if (ret != 0) { >> >> - LOG_ERR("mp_enq for %d obj failed\n", MAX_BULK); >> >> - goto fail; >> >> - } >> >> - printf("dequeue 1 obj\n"); >> >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 1); >> >> - cur_dst += 1; >> >> - if (ret != 0) { >> >> - LOG_ERR("mc_deq for 1 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - printf("dequeue 2 objs\n"); >> >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, 2); >> >> - cur_dst += 2; >> >> - if (ret != 0) { >> >> - LOG_ERR("mc_deq for 2 obj failed\n"); >> >> - goto fail; >> >> - } >> >> - printf("dequeue MAX_BULK objs\n"); >> >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK); >> >> - cur_dst += MAX_BULK; >> >> - if (ret != 0) { >> >> - LOG_ERR("mc_deq for %d obj failed\n", MAX_BULK); >> >> - goto fail; >> >> - } >> >> - /* check data */ >> >> - if (memcmp(src, dst, cur_dst - dst)) { >> >> - LOG_ERR("data after dequeue is not the same\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("test watermark and default bulk enqueue / dequeue\n"); >> >> - _ring_set_water_mark(r, 20); >> >> - num_elems = 16; >> >> - >> >> - cur_src = src; >> >> - cur_dst = dst; >> >> - >> >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); >> >> - cur_src += num_elems; >> >> - if (ret != 0) { >> >> - LOG_ERR("Cannot enqueue\n"); >> >> - goto fail; >> >> - } >> >> - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); >> >> - if (ret != -EDQUOT) { >> >> - LOG_ERR("Watermark not exceeded\n"); >> >> - goto fail; >> >> - } >> >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); >> >> - cur_dst += num_elems; >> >> - if (ret != 0) { >> >> - LOG_ERR("Cannot dequeue\n"); >> >> - goto fail; >> >> - } >> >> - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); >> >> - cur_dst += num_elems; >> >> - if (ret != 0) { >> >> - LOG_ERR("Cannot dequeue2\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - /* check data */ >> >> - if (memcmp(src, dst, cur_dst - dst)) { >> >> - LOG_ERR("data after dequeue is not the same\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - printf("basic enqueu, dequeue test for ring <%s>@%p passed\n", >> >> - r->name, r); >> >> - >> >> - free(src); >> >> - free(dst); >> >> - return 0; >> >> - >> >> -fail: >> >> - free(src); >> >> - free(dst); >> >> - return -1; >> >> -} >> >> - >> >> -/* global shared ring used for stress testing */ >> >> -static _ring_t *r_stress; >> >> - >> >> -/* Stress func for Multi producer only */ >> >> -static int producer_fn(void) >> >> -{ >> >> - unsigned i; >> >> - >> >> - void **src = NULL; >> >> - >> >> - /* alloc dummy object pointers */ >> >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); >> >> - if (src == NULL) { >> >> - LOG_ERR("failed to allocate producer memory.\n"); >> >> - return -1; >> >> - } >> >> - for (i = 0; i < MAX_BULK; i++) >> >> - src[i] = (void *)(unsigned long)i; >> >> - >> >> - do { >> >> - i = _ring_mp_enqueue_bulk(r_stress, src, MAX_BULK); >> >> - if (i == 0) { >> >> - free(src); >> >> - return 0; >> >> - } >> >> - } while (1); >> >> -} >> >> - >> >> -/* Stress func for Multi consumer only */ >> >> -static int consumer_fn(void) >> >> -{ >> >> - unsigned i; >> >> - void **src = NULL; >> >> - >> >> - /* alloc dummy object pointers */ >> >> - src = malloc(MAX_BULK * 2 * sizeof(void *)); >> >> - if (src == NULL) { >> >> - LOG_ERR("failed to allocate consumer memory.\n"); >> >> - return -1; >> >> - } >> >> - >> >> - do { >> >> - i = _ring_mc_dequeue_bulk(r_stress, src, MAX_BULK); >> >> - if (i == 0) { >> >> - for (i = 0; i < MAX_BULK; i++) { >> >> - if (src[i] != (void *)(unsigned >> long)i) { >> >> - free(src); >> >> - printf("data mismatch.. >> lockless >> >> ops fail\n"); >> >> - return -1; >> >> - } >> >> - } >> >> - free(src); >> >> - printf("\n Test OK !\n"); >> >> - return 0; >> >> - } >> >> - } while (1); >> >> -} >> >> - >> >> -/* >> >> - * Note : make sure that both enqueue and dequeue >> >> - * operation starts at same time so to avoid data corruption >> >> - * Its because atomic lock will protect only indexes, but if order of >> >> - * read or write operation incorrect then data mismatch will happen >> >> - * So its resposibility of application develop to take care of order >> of >> >> - * data read or write. >> >> -*/ >> >> -typedef enum { >> >> - one_enq_one_deq, /* One thread to enqueue one to >> >> - dequeu at same time */ >> >> - one_enq_rest_deq, /* one thread to enq rest to >> >> - dequeue at same time */ >> >> - one_deq_rest_enq, /* one to deq and rest enq at very same >> >> time */ >> >> - multi_enq_multi_deq /* multiple enq,deq */ >> >> -} stress_type_t; >> >> - >> >> -static void test_ring_stress(stress_type_t type) >> >> -{ >> >> - int thr; >> >> - >> >> - thr = odp_thread_id(); >> >> - >> >> - switch (type) { >> >> - case one_enq_one_deq: >> >> - if (thr == 1) >> >> - producer_fn(); >> >> - if (thr == 2) >> >> - consumer_fn(); >> >> - break; >> >> - case multi_enq_multi_deq: >> >> - if (thr % 2 == 0) >> >> - producer_fn(); >> >> - else >> >> - consumer_fn(); >> >> - break; >> >> - case one_deq_rest_enq: >> >> - case one_enq_rest_deq:/*TBD*/ >> >> - default: >> >> - LOG_ERR("Invalid stress type or test case yet not >> >> supported\n"); >> >> - } >> >> -} >> >> - >> >> -static void *test_ring(void *arg) >> >> -{ >> >> - ring_arg_t *parg = (ring_arg_t *)arg; >> >> - int thr; >> >> - char ring_name[_RING_NAMESIZE]; >> >> - _ring_t *r; >> >> - int result = 0; >> >> - >> >> - thr = odp_thread_id(); >> >> - >> >> - printf("Thread %i starts\n", thr); >> >> - >> >> - switch (parg->thrdarg.testcase) { >> >> - case ODP_RING_TEST_BASIC: >> >> - snprintf(ring_name, sizeof(ring_name), "test_ring_%i", >> >> thr); >> >> - >> >> - r = _ring_create(ring_name, RING_SIZE, >> >> - 0 /* not used, alignement >> >> - taken care inside func : todo >> */); >> >> - if (r == NULL) { >> >> - LOG_ERR("ring create failed\n"); >> >> - result = -1; >> >> - break; >> >> - } >> >> - /* lookup ring from its name */ >> >> - if (_ring_lookup(ring_name) != r) { >> >> - LOG_ERR("ring lookup failed\n"); >> >> - result = -1; >> >> - break; >> >> - } >> >> - >> >> - /* basic operations */ >> >> - if (test_ring_basic(r) < 0) { >> >> - LOG_ERR("ring basic enqueue/dequeu ops >> failed\n"); >> >> - result = -1; >> >> - } >> >> - >> >> - if (result) >> >> - _ring_list_dump(); >> >> - >> >> - break; >> >> - >> >> - case ODP_RING_TEST_STRESS: >> >> - test_ring_stress(parg->stress_type); >> >> - >> >> - if (result) >> >> - _ring_list_dump(); >> >> - break; >> >> - >> >> - default: >> >> - LOG_ERR("Invalid test case [%d]\n", >> >> parg->thrdarg.testcase); >> >> - result = -1; >> >> - break; >> >> - } >> >> - >> >> - LOG_DBG("result = %d\n", result); >> >> - if (result == 0) >> >> - printf("test_ring Result:pass\n"); >> >> - else >> >> - printf("test_ring Result:fail\n"); >> >> - >> >> - fflush(stdout); >> >> - >> >> - return parg; >> >> -} >> >> - >> >> -int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED) >> >> -{ >> >> - ring_arg_t rarg; >> >> - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; >> >> - odp_cpumask_t cpu_mask; >> >> - int num_workers; >> >> - char ring_name[_RING_NAMESIZE]; >> >> - odp_instance_t instance; >> >> - odph_linux_thr_params_t thr_params; >> >> - >> >> - if (odp_init_global(&instance, NULL, NULL)) { >> >> - LOG_ERR("Error: ODP global init failed.\n"); >> >> - exit(EXIT_FAILURE); >> >> - } >> >> - >> >> - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { >> >> - LOG_ERR("Error: ODP local init failed.\n"); >> >> - exit(EXIT_FAILURE); >> >> - } >> >> - >> >> - _ring_tailq_init(); >> >> - >> >> - num_workers = odp_cpumask_default_worker(&cpu_mask, >> MAX_WORKERS); >> >> - rarg.thrdarg.numthrds = rarg.thrdarg.numthrds; >> >> - >> >> - rarg.thrdarg.testcase = ODP_RING_TEST_BASIC; >> >> - >> >> - memset(&thr_params, 0, sizeof(thr_params)); >> >> - thr_params.start = test_ring; >> >> - thr_params.arg = &rarg; >> >> - thr_params.thr_type = ODP_THREAD_WORKER; >> >> - thr_params.instance = instance; >> >> - >> >> - printf("starting stess test type : %d..\n", rarg.stress_type); >> >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, >> &thr_params); >> >> - odph_linux_pthread_join(thread_tbl, num_workers); >> >> - >> >> - rarg.thrdarg.testcase = ODP_RING_TEST_STRESS; >> >> - rarg.stress_type = one_enq_one_deq; >> >> - >> >> - printf("starting stess test type : %d..\n", rarg.stress_type); >> >> - snprintf(ring_name, sizeof(ring_name), "test_ring_stress"); >> >> - r_stress = _ring_create(ring_name, RING_SIZE, >> >> - 0/* not used, alignement >> >> - taken care inside func : todo */); >> >> - if (r_stress == NULL) { >> >> - LOG_ERR("ring create failed\n"); >> >> - goto fail; >> >> - } >> >> - /* lookup ring from its name */ >> >> - if (_ring_lookup(ring_name) != r_stress) { >> >> - LOG_ERR("ring lookup failed\n"); >> >> - goto fail; >> >> - } >> >> - >> >> - thr_params.start = test_ring; >> >> - thr_params.arg = &rarg; >> >> - >> >> - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, >> &thr_params); >> >> - odph_linux_pthread_join(thread_tbl, num_workers); >> >> - >> >> -fail: >> >> - if (odp_term_local()) { >> >> - LOG_ERR("Error: ODP local term failed.\n"); >> >> - exit(EXIT_FAILURE); >> >> - } >> >> - >> >> - if (odp_term_global(instance)) { >> >> - LOG_ERR("Error: ODP global term failed.\n"); >> >> - exit(EXIT_FAILURE); >> >> - } >> >> - >> >> - return 0; >> >> -} >> >> >> > >> > _______________________________________________ >> > lng-odp mailing list >> > lng-odp@lists.linaro.org >> <javascript:_e(%7B%7D,'cvml','lng-odp@lists.linaro.org');> >> > https://lists.linaro.org/mailman/listinfo/lng-odp >> > >> _______________________________________________ >> lng-odp mailing list >> lng-odp@lists.linaro.org >> <javascript:_e(%7B%7D,'cvml','lng-odp@lists.linaro.org');> >> https://lists.linaro.org/mailman/listinfo/lng-odp >> > >
diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am index f74185d..2d58c57 100644 --- a/platform/linux-generic/test/Makefile.am +++ b/platform/linux-generic/test/Makefile.am @@ -8,7 +8,7 @@ ODP_MODULES = pktio \ if test_vald TESTS = pktio/pktio_run.sh \ pktio/pktio_run_tap.sh \ - ring/ringtest$(EXEEXT) \ + ring/ring_main$(EXEEXT) \ shmem/shmem_linux \ ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ diff --git a/platform/linux-generic/test/ring/Makefile.am b/platform/linux-generic/test/ring/Makefile.am index 5a949d0..c086584 100644 --- a/platform/linux-generic/test/ring/Makefile.am +++ b/platform/linux-generic/test/ring/Makefile.am @@ -1,16 +1,14 @@ -include $(top_srcdir)/test/validation/Makefile.inc +include ../Makefile.inc -AM_CFLAGS += -I$(srcdir)/common -AM_CFLAGS += -I$(top_srcdir)/test/validation/common -AM_LDFLAGS += -static +noinst_LTLIBRARIES = libtestring.la +libtestring_la_SOURCES = ring_suites.c ring_basic.c ring_stress.c +libtestring_la_CFLAGS = $(AM_CFLAGS) $(INCCUNIT_COMMON) $(INCODP) -COMPILE_ONLY = +test_PROGRAMS = ring_main$(EXEEXT) +dist_ring_main_SOURCES = ring_main.c -TESTSCRIPTS = +ring_main_LDFLAGS = $(AM_LDFLAGS) +ring_main_LDADD = libtestring.la $(LIBCUNIT_COMMON) $(LIBODP) -EXECUTABLES = ringtest$(EXEEXT) +noinst_HEADERS = ring_suites.h -test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) - -ringtest_SOURCES = ringtest.c -ringtest_LDADD = $(LIBCUNIT_COMMON) $(LIBODP) diff --git a/platform/linux-generic/test/ring/ring_basic.c b/platform/linux-generic/test/ring/ring_basic.c new file mode 100644 index 0000000..20d9786 --- /dev/null +++ b/platform/linux-generic/test/ring/ring_basic.c @@ -0,0 +1,392 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * + * ODP ring basic test + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <test_debug.h> +#include <odp_cunit_common.h> +#include <odp_packet_io_ring_internal.h> + +#include "ring_suites.h" + +/* labor functions declaration */ +static void __do_basic_burst(_ring_t *r); +static void __do_basic_bulk(_ring_t *r); +static void __do_basic_watermark(_ring_t *r); + +/* dummy object pointers for enqueue and dequeue testing */ +static void **test_enq_data; +static void **test_deq_data; + +/* create two rings: one for single thread usage scenario + * and another for multiple thread usage scenario. + * st - single thread usage scenario + * mt - multiple thread usage scenario + */ +static const char *st_ring_name = "ST basic ring"; +static const char *mt_ring_name = "MT basic ring"; +static _ring_t *st_ring, *mt_ring; + +int ring_test_basic_start(void) +{ + int i = 0; + + /* alloc dummy object pointers for enqueue testing */ + test_enq_data = malloc(RING_SIZE * 2 * sizeof(void *)); + if (NULL == test_enq_data) { + LOG_ERR("failed to allocate basic test enqeue data\n"); + return -1; + } + + for (i = 0; i < RING_SIZE * 2; i++) + test_enq_data[i] = (void *)(unsigned long)i; + + /* alloc dummy object pointers for dequeue testing */ + test_deq_data = malloc(RING_SIZE * 2 * sizeof(void *)); + if (NULL == test_deq_data) { + LOG_ERR("failed to allocate basic test dequeue data\n"); + free(test_enq_data); test_enq_data = NULL; + return -1; + } + + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); + return 0; +} + +int ring_test_basic_end(void) +{ + free(test_enq_data); + free(test_deq_data); + return 0; +} + +/* basic test cases */ +void ring_test_basic_create(void) +{ + /* prove illegal size shall fail */ + st_ring = _ring_create(st_ring_name, ILLEGAL_SIZE, 0); + CU_ASSERT(NULL == st_ring); + CU_ASSERT(EINVAL == __odp_errno); + + /* create ring for single thread usage scenario */ + st_ring = _ring_create(st_ring_name, RING_SIZE, + _RING_F_SP_ENQ | _RING_F_SC_DEQ); + + CU_ASSERT(NULL != st_ring); + CU_ASSERT(_ring_lookup(st_ring_name) == st_ring); + + /* create ring for multiple thread usage scenario */ + mt_ring = _ring_create(mt_ring_name, RING_SIZE, + 0 /* not used, alignement + taken care inside function: todo */); + + CU_ASSERT(NULL != mt_ring); + CU_ASSERT(_ring_lookup(mt_ring_name) == mt_ring); +} + +void ring_test_basic_burst(void) +{ + /* two rounds to cover both single + * thread and multiple thread APIs + */ + __do_basic_burst(st_ring); + __do_basic_burst(mt_ring); +} + +void ring_test_basic_bulk(void) +{ + __do_basic_bulk(st_ring); + __do_basic_bulk(mt_ring); +} + +void ring_test_basic_watermark(void) +{ + __do_basic_watermark(st_ring); + __do_basic_watermark(mt_ring); +} + +/* labor functions definition */ +static void __do_basic_burst(_ring_t *r) +{ + int result = 0; + unsigned int count = 0; + void * const *source = test_enq_data; + void * const *dest = test_deq_data; + void **enq = NULL, **deq = NULL; + + enq = test_enq_data; deq = test_deq_data; + + /* ring is empty */ + CU_ASSERT(1 == _ring_empty(r)); + + /* enqueue 1 object */ + result = _ring_enqueue_burst(r, enq, 1); + enq += 1; + CU_ASSERT(1 == (result & _RING_SZ_MASK)); + + /* enqueue 2 objects */ + result = _ring_enqueue_burst(r, enq, 2); + enq += 2; + CU_ASSERT(2 == (result & _RING_SZ_MASK)); + + /* enqueue HALF_BULK objects */ + result = _ring_enqueue_burst(r, enq, HALF_BULK); + enq += HALF_BULK; + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); + + /* ring is neither empty nor full */ + CU_ASSERT(0 == _ring_full(r)); + CU_ASSERT(0 == _ring_empty(r)); + + /* _ring_count() equals enqueued */ + count = (1 + 2 + HALF_BULK); + CU_ASSERT(count == _ring_count(r)); + /* _ring_free_count() equals rooms left */ + count = (RING_SIZE - 1) - count; + CU_ASSERT(count == _ring_free_count(r)); + + /* exceed the size, enquene as many as possible */ + result = _ring_enqueue_burst(r, enq, HALF_BULK); + enq += count; + CU_ASSERT(count == (result & _RING_SZ_MASK)); + CU_ASSERT(1 == _ring_full(r)); + + /* dequeue 1 object */ + result = _ring_dequeue_burst(r, deq, 1); + deq += 1; + CU_ASSERT(1 == (result & _RING_SZ_MASK)); + + /* dequeue 2 objects */ + result = _ring_dequeue_burst(r, deq, 2); + deq += 2; + CU_ASSERT(2 == (result & _RING_SZ_MASK)); + + /* dequeue HALF_BULK objects */ + result = _ring_dequeue_burst(r, deq, HALF_BULK); + deq += HALF_BULK; + CU_ASSERT(HALF_BULK == (result & _RING_SZ_MASK)); + + /* _ring_free_count() equals dequeued */ + count = (1 + 2 + HALF_BULK); + CU_ASSERT(count == _ring_free_count(r)); + /* _ring_count() equals remained left */ + count = (RING_SIZE - 1) - count; + CU_ASSERT(count == _ring_count(r)); + + /* underrun the size, dequeue as many as possible */ + result = _ring_dequeue_burst(r, deq, HALF_BULK); + deq += count; + CU_ASSERT(count == (result & _RING_SZ_MASK)); + CU_ASSERT(1 == _ring_empty(r)); + + /* check data */ + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); + + /* reset dequeue data */ + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); +} + +/* incomplete ring API set: strange! + * complement _ring_enqueue/dequeue_bulk to improve coverage + */ +static inline int __ring_enqueue_bulk( + _ring_t *r, void * const *objects, unsigned bulk) +{ + if (r->prod.sp_enqueue) + return _ring_sp_enqueue_bulk(r, objects, bulk); + else + return _ring_mp_enqueue_bulk(r, objects, bulk); +} + +static inline int __ring_dequeue_bulk( + _ring_t *r, void **objects, unsigned bulk) +{ + if (r->cons.sc_dequeue) + return _ring_sc_dequeue_bulk(r, objects, bulk); + else + return _ring_mc_dequeue_bulk(r, objects, bulk); +} + +static void __do_basic_bulk(_ring_t *r) +{ + int result = 0; + unsigned int count = 0; + void * const *source = test_enq_data; + void * const *dest = test_deq_data; + void **enq = NULL, **deq = NULL; + + enq = test_enq_data; deq = test_deq_data; + + /* ring is empty */ + CU_ASSERT(1 == _ring_empty(r)); + + /* enqueue 1 object */ + result = __ring_enqueue_bulk(r, enq, 1); + enq += 1; + CU_ASSERT(0 == result); + + /* enqueue 2 objects */ + result = __ring_enqueue_bulk(r, enq, 2); + enq += 2; + CU_ASSERT(0 == result); + + /* enqueue HALF_BULK objects */ + result = __ring_enqueue_bulk(r, enq, HALF_BULK); + enq += HALF_BULK; + CU_ASSERT(0 == result); + + /* ring is neither empty nor full */ + CU_ASSERT(0 == _ring_full(r)); + CU_ASSERT(0 == _ring_empty(r)); + + /* _ring_count() equals enqueued */ + count = (1 + 2 + HALF_BULK); + CU_ASSERT(count == _ring_count(r)); + /* _ring_free_count() equals rooms left */ + count = (RING_SIZE - 1) - count; + CU_ASSERT(count == _ring_free_count(r)); + + /* exceed the size, enquene shall fail with -ENOBUFS */ + result = __ring_enqueue_bulk(r, enq, HALF_BULK); + CU_ASSERT(-ENOBUFS == result); + + /* fullful the ring */ + result = __ring_enqueue_bulk(r, enq, count); + enq += count; + CU_ASSERT(0 == result); + CU_ASSERT(1 == _ring_full(r)); + + /* dequeue 1 object */ + result = __ring_dequeue_bulk(r, deq, 1); + deq += 1; + CU_ASSERT(0 == result); + + /* dequeue 2 objects */ + result = __ring_dequeue_bulk(r, deq, 2); + deq += 2; + CU_ASSERT(0 == result); + + /* dequeue HALF_BULK objects */ + result = __ring_dequeue_bulk(r, deq, HALF_BULK); + deq += HALF_BULK; + CU_ASSERT(0 == result); + + /* _ring_free_count() equals dequeued */ + count = (1 + 2 + HALF_BULK); + CU_ASSERT(count == _ring_free_count(r)); + /* _ring_count() equals remained left */ + count = (RING_SIZE - 1) - count; + CU_ASSERT(count == _ring_count(r)); + + /* underrun the size, dequeue shall fail with -ENOENT */ + result = __ring_dequeue_bulk(r, deq, HALF_BULK); + CU_ASSERT(-ENOENT == result); + + /* empty the queue */ + result = __ring_dequeue_bulk(r, deq, count); + deq += count; + CU_ASSERT(0 == result); + CU_ASSERT(1 == _ring_empty(r)); + + /* check data */ + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); + + /* reset dequeue data */ + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); +} + +void __do_basic_watermark(_ring_t *r) +{ + int result = 0; + void * const *source = test_enq_data; + void * const *dest = test_deq_data; + void **enq = NULL, **deq = NULL; + + enq = test_enq_data; deq = test_deq_data; + + /* bulk = 3/4 watermark to trigger alarm on 2nd enqueue */ + const unsigned watermark = PIECE_BULK; + const unsigned bulk = (watermark / 4) * 3; + + /* watermark cannot exceed ring size */ + result = _ring_set_water_mark(r, ILLEGAL_SIZE); + CU_ASSERT(-EINVAL == result); + + /* set watermark */ + result = _ring_set_water_mark(r, watermark); + CU_ASSERT(0 == result); + + /* 1st enqueue shall succeed */ + result = __ring_enqueue_bulk(r, enq, bulk); + enq += bulk; + CU_ASSERT(0 == result); + + /* 2nd enqueue shall succeed but return -EDQUOT */ + result = __ring_enqueue_bulk(r, enq, bulk); + enq += bulk; + CU_ASSERT(-EDQUOT == result); + + /* dequeue 1st bulk */ + result = __ring_dequeue_bulk(r, deq, bulk); + deq += bulk; + CU_ASSERT(0 == result); + + /* dequeue 2nd bulk */ + result = __ring_dequeue_bulk(r, deq, bulk); + deq += bulk; + CU_ASSERT(0 == result); + + /* check data */ + CU_ASSERT(0 == memcmp(source, dest, deq - dest)); + + /* reset watermark */ + result = _ring_set_water_mark(r, 0); + CU_ASSERT(0 == result); + + /* reset dequeue data */ + memset(test_deq_data, 0, RING_SIZE * 2 * sizeof(void *)); +} diff --git a/platform/linux-generic/test/ring/ring_main.c b/platform/linux-generic/test/ring/ring_main.c new file mode 100644 index 0000000..e465113 --- /dev/null +++ b/platform/linux-generic/test/ring/ring_main.c @@ -0,0 +1,12 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "ring_suites.h" + +int main(void) +{ + return ring_suites_main(); +} diff --git a/platform/linux-generic/test/ring/ring_stress.c b/platform/linux-generic/test/ring/ring_stress.c new file mode 100644 index 0000000..a4753e9 --- /dev/null +++ b/platform/linux-generic/test/ring/ring_stress.c @@ -0,0 +1,270 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * + * ODP ring stress test + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <odp_api.h> +#include <odp/helper/linux.h> +#include <odp_packet_io_ring_internal.h> +#include <test_debug.h> +#include <odp_cunit_common.h> + +#include "ring_suites.h" + +/* + * Since cunit framework cannot work with multi-threading, ask workers + * to save their results for delayed assertion after thread collection. + */ +static int worker_results[MAX_WORKERS]; + +/* + * Note : make sure that both enqueue and dequeue + * operation starts at same time so to avoid data corruption + * Its because atomic lock will protect only indexes, but if order of + * read or write operation incorrect then data mismatch will happen + * So its resposibility of application develop to take care of order of + * data read or write. + */ +typedef enum { + STRESS_1_1_PRODUCER_CONSUMER, + STRESS_1_N_PRODUCER_CONSUMER, + STRESS_N_1_PRODUCER_CONSUMER, + STRESS_N_M_PRODUCER_CONSUMER +} stress_case_t; + +/* worker function declarations */ +static void *stress_worker(void *_data); + +/* global name for later look up in workers' context */ +static const char *ring_name = "stress ring"; + +int ring_test_stress_start(void) +{ + /* multiple thread usage scenario only */ + _ring_t *r_stress = _ring_create(ring_name, RING_SIZE, + 0 /* not used, alignement + taken care inside function: todo */); + if (r_stress == NULL) { + LOG_ERR("create ring failed for stress.\n"); + return -1; + } + + return 0; +} + +void ring_test_stress_1_1_producer_consumer(void) +{ + int i = 0; + odp_cpumask_t cpus; + pthrd_arg worker_param; + + /* reset results for delayed assertion */ + memset(worker_results, 0, sizeof(worker_results)); + + /* request 2 threads to run 1:1 stress */ + worker_param.numthrds = odp_cpumask_default_worker(&cpus, 2); + worker_param.testcase = STRESS_1_1_PRODUCER_CONSUMER; + + /* not failure, insufficient resource */ + if (worker_param.numthrds < 2) { + LOG_ERR("insufficient cpu for 1:1 " + "producer/consumer stress.\n"); + return; + } + + /* kick the workers */ + odp_cunit_thread_create(stress_worker, &worker_param); + + /* collect the results */ + odp_cunit_thread_exit(&worker_param); + + /* delayed assertion due to cunit limitation */ + for (i = 0; i < worker_param.numthrds; i++) + CU_ASSERT(0 == worker_results[i]); +} + +void ring_test_stress_N_M_producer_consumer(void) +{ + int i = 0; + odp_cpumask_t cpus; + pthrd_arg worker_param; + + /* reset results for delayed assertion */ + memset(worker_results, 0, sizeof(worker_results)); + + /* request MAX_WORKERS threads to run N:M stress */ + worker_param.numthrds = + odp_cpumask_default_worker(&cpus, MAX_WORKERS); + worker_param.testcase = STRESS_N_M_PRODUCER_CONSUMER; + + /* not failure, insufficient resource */ + if (worker_param.numthrds < 3) { + LOG_ERR("insufficient cpu for N:M " + "producer/consumer stress.\n"); + return; + } + + /* kick the workers */ + odp_cunit_thread_create(stress_worker, &worker_param); + + /* collect the results */ + odp_cunit_thread_exit(&worker_param); + + /* delayed assertion due to cunit limitation */ + for (i = 0; i < worker_param.numthrds; i++) + CU_ASSERT(0 == worker_results[i]); +} + +void ring_test_stress_1_N_producer_consumer(void) +{ +} + +void ring_test_stress_N_1_producer_consumer(void) +{ +} + +void ring_test_stress_ring_list_dump(void) +{ + /* improve code coverage */ + _ring_list_dump(); +} + +/* worker function for multiple producer instances */ +static int do_producer(_ring_t *r) +{ + int i, result = 0; + void **enq = NULL; + + /* allocate dummy object pointers for enqueue */ + enq = malloc(PIECE_BULK * 2 * sizeof(void *)); + if (NULL == enq) { + LOG_ERR("insufficient memory for producer enqueue.\n"); + return 0; /* not failure, skip for insufficient memory */ + } + + /* data pattern to be evaluated later in consumer */ + for (i = 0; i < PIECE_BULK; i++) + enq[i] = (void *)(unsigned long)i; + + do { + result = _ring_mp_enqueue_bulk(r, enq, PIECE_BULK); + if (0 == result) { + free(enq); + return 0; + } + } while (1); +} + +/* worker function for multiple consumer instances */ +static int do_consumer(_ring_t *r) +{ + int i, result = 0; + void **deq = NULL; + const char *message = "test OK!"; + const char *mismatch = "data mismatch..lockless enq/deq failed."; + + /* allocate dummy object pointers for dequeue */ + deq = malloc(PIECE_BULK * 2 * sizeof(void *)); + if (NULL == deq) { + LOG_ERR("insufficient memory for consumer dequeue.\n"); + return 0; /* not failure, skip for insufficient memory */ + } + + do { + result = _ring_mc_dequeue_bulk(r, deq, PIECE_BULK); + if (0 == result) { + /* evaluate the data pattern */ + for (i = 0; i < PIECE_BULK; i++) { + if (deq[i] != (void *)(unsigned long)i) { + result = -1; + message = mismatch; + break; + } + } + + free(deq); + LOG_ERR("%s\n", message); + return result; + } + } while (1); +} + +static void *stress_worker(void *_data) +{ + pthrd_arg *worker_param = (pthrd_arg *)_data; + _ring_t *r_stress = NULL; + + int worker_id = odp_thread_id(); + /* save the worker result for delayed assertion */ + int *result = &worker_results[(worker_id % worker_param->numthrds)]; + + /* verify ring lookup in worker context */ + r_stress = _ring_lookup(ring_name); + if (NULL == r_stress) { + LOG_ERR("ring lookup %s not found\n", ring_name); + *result = -1; + return NULL; + } + + switch (worker_param->testcase) { + case STRESS_1_1_PRODUCER_CONSUMER: + case STRESS_N_M_PRODUCER_CONSUMER: + /* interleaved producer/consumer */ + if (0 == (worker_id % 2)) + *result = do_producer(r_stress); + else if (1 == (worker_id % 2)) + *result = do_consumer(r_stress); + break; + case STRESS_1_N_PRODUCER_CONSUMER: + case STRESS_N_1_PRODUCER_CONSUMER: + default: + LOG_ERR("invalid or not-implemented stress type (%d)\n", + worker_param->testcase); + break; + } + return NULL; +} diff --git a/platform/linux-generic/test/ring/ring_suites.c b/platform/linux-generic/test/ring/ring_suites.c new file mode 100644 index 0000000..b310843 --- /dev/null +++ b/platform/linux-generic/test/ring/ring_suites.c @@ -0,0 +1,70 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <odp_api.h> +#include <test_debug.h> +#include <odp_cunit_common.h> +#include <odp_packet_io_ring_internal.h> + +#include "ring_suites.h" + +static int ring_suites_init(odp_instance_t *inst) +{ + if (0 != odp_init_global(inst, NULL, NULL)) { + LOG_ERR("error: odp_init_global() failed.\n"); + return -1; + } + if (0 != odp_init_local(*inst, ODP_THREAD_CONTROL)) { + LOG_ERR("error: odp_init_local() failed.\n"); + return -1; + } + + _ring_tailq_init(); + return 0; +} + +static odp_testinfo_t ring_suite_basic[] = { + ODP_TEST_INFO(ring_test_basic_create), + ODP_TEST_INFO(ring_test_basic_burst), + ODP_TEST_INFO(ring_test_basic_bulk), + ODP_TEST_INFO(ring_test_basic_watermark), + ODP_TEST_INFO_NULL, +}; + +static odp_testinfo_t ring_suite_stress[] = { + ODP_TEST_INFO(ring_test_stress_1_1_producer_consumer), + ODP_TEST_INFO(ring_test_stress_1_N_producer_consumer), + ODP_TEST_INFO(ring_test_stress_N_1_producer_consumer), + ODP_TEST_INFO(ring_test_stress_N_M_producer_consumer), + ODP_TEST_INFO(ring_test_stress_ring_list_dump), + ODP_TEST_INFO_NULL, +}; + +static odp_suiteinfo_t ring_suites[] = { + {"ring basic", ring_test_basic_start, + ring_test_basic_end, ring_suite_basic}, + {"ring stress", ring_test_stress_start, + NULL, ring_suite_stress}, + ODP_SUITE_INFO_NULL +}; + +int ring_suites_main(void) +{ + int ret; + + odp_cunit_register_global_init(ring_suites_init); + + ret = odp_cunit_register(ring_suites); + + if (ret == 0) + ret = odp_cunit_run(); + + return ret; +} diff --git a/platform/linux-generic/test/ring/ring_suites.h b/platform/linux-generic/test/ring/ring_suites.h new file mode 100644 index 0000000..e26b6e8 --- /dev/null +++ b/platform/linux-generic/test/ring/ring_suites.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2015, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#define RING_SIZE 4096 +#define PIECE_BULK 32 + +#define HALF_BULK (RING_SIZE >> 1) +#define ILLEGAL_SIZE (RING_SIZE | 0x3) + +/* test suite start and stop */ +int ring_test_basic_start(void); +int ring_test_basic_end(void); + +/* basic test cases */ +void ring_test_basic_create(void); +void ring_test_basic_burst(void); +void ring_test_basic_bulk(void); +void ring_test_basic_watermark(void); + +/* test suite start and stop */ +int ring_test_stress_start(void); + +/* stress test cases */ +void ring_test_stress_1_1_producer_consumer(void); +void ring_test_stress_1_N_producer_consumer(void); +void ring_test_stress_N_1_producer_consumer(void); +void ring_test_stress_N_M_producer_consumer(void); +void ring_test_stress_ring_list_dump(void); + +int ring_suites_main(void); diff --git a/platform/linux-generic/test/ring/ringtest.c b/platform/linux-generic/test/ring/ringtest.c deleted file mode 100644 index ac0aa61..0000000 --- a/platform/linux-generic/test/ring/ringtest.c +++ /dev/null @@ -1,493 +0,0 @@ -/* Copyright (c) 2014, Linaro Limited - * All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * - * ODP test ring - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <odp_api.h> -#include <odp/helper/linux.h> -#include <odp_packet_io_ring_internal.h> -#include <test_debug.h> -#include <odp_cunit_common.h> - -#define RING_SIZE 4096 -#define MAX_BULK 32 - -enum { - ODP_RING_TEST_BASIC, - ODP_RING_TEST_STRESS, -}; - -/* local struct for ring_thread argument */ -typedef struct { - pthrd_arg thrdarg; - int stress_type; -} ring_arg_t; - -static int test_ring_basic(_ring_t *r) -{ - void **src = NULL, **cur_src = NULL, **dst = NULL, **cur_dst = NULL; - int ret; - unsigned i, num_elems; - - /* alloc dummy object pointers */ - src = malloc(RING_SIZE * 2 * sizeof(void *)); - if (src == NULL) { - LOG_ERR("failed to allocate test ring src memory\n"); - goto fail; - } - for (i = 0; i < RING_SIZE * 2; i++) - src[i] = (void *)(unsigned long)i; - - cur_src = src; - - /* alloc some room for copied objects */ - dst = malloc(RING_SIZE * 2 * sizeof(void *)); - if (dst == NULL) { - LOG_ERR("failed to allocate test ring dst memory\n"); - goto fail; - } - - memset(dst, 0, RING_SIZE * 2 * sizeof(void *)); - cur_dst = dst; - - printf("Test SP & SC basic functions\n"); - printf("enqueue 1 obj\n"); - ret = _ring_sp_enqueue_burst(r, cur_src, 1); - cur_src += 1; - if ((ret & _RING_SZ_MASK) != 1) { - LOG_ERR("sp_enq for 1 obj failed\n"); - goto fail; - } - - printf("enqueue 2 objs\n"); - ret = _ring_sp_enqueue_burst(r, cur_src, 2); - cur_src += 2; - if ((ret & _RING_SZ_MASK) != 2) { - LOG_ERR("sp_enq for 2 obj failed\n"); - goto fail; - } - - printf("enqueue MAX_BULK objs\n"); - ret = _ring_sp_enqueue_burst(r, cur_src, MAX_BULK); - if ((ret & _RING_SZ_MASK) != MAX_BULK) { - LOG_ERR("sp_enq for %d obj failed\n", MAX_BULK); - goto fail; - } - - printf("dequeue 1 obj\n"); - ret = _ring_sc_dequeue_burst(r, cur_dst, 1); - cur_dst += 1; - if ((ret & _RING_SZ_MASK) != 1) { - LOG_ERR("sc_deq for 1 obj failed\n"); - goto fail; - } - - printf("dequeue 2 objs\n"); - ret = _ring_sc_dequeue_burst(r, cur_dst, 2); - cur_dst += 2; - if ((ret & _RING_SZ_MASK) != 2) { - LOG_ERR("sc_deq for 2 obj failed\n"); - goto fail; - } - - printf("dequeue MAX_BULK objs\n"); - ret = _ring_sc_dequeue_burst(r, cur_dst, MAX_BULK); - cur_dst += MAX_BULK; - if ((ret & _RING_SZ_MASK) != MAX_BULK) { - LOG_ERR("sc_deq for %d obj failed\n", MAX_BULK); - goto fail; - } - - /* check data */ - if (memcmp(src, dst, cur_dst - dst)) { - LOG_ERR("data after dequeue is not the same\n"); - goto fail; - } - - cur_src = src; - cur_dst = dst; - - printf("Test MP & MC basic functions\n"); - - printf("enqueue 1 obj\n"); - ret = _ring_mp_enqueue_bulk(r, cur_src, 1); - cur_src += 1; - if (ret != 0) { - LOG_ERR("mp_enq for 1 obj failed\n"); - goto fail; - } - printf("enqueue 2 objs\n"); - ret = _ring_mp_enqueue_bulk(r, cur_src, 2); - cur_src += 2; - if (ret != 0) { - LOG_ERR("mp_enq for 2 obj failed\n"); - goto fail; - } - printf("enqueue MAX_BULK objs\n"); - ret = _ring_mp_enqueue_bulk(r, cur_src, MAX_BULK); - if (ret != 0) { - LOG_ERR("mp_enq for %d obj failed\n", MAX_BULK); - goto fail; - } - printf("dequeue 1 obj\n"); - ret = _ring_mc_dequeue_bulk(r, cur_dst, 1); - cur_dst += 1; - if (ret != 0) { - LOG_ERR("mc_deq for 1 obj failed\n"); - goto fail; - } - printf("dequeue 2 objs\n"); - ret = _ring_mc_dequeue_bulk(r, cur_dst, 2); - cur_dst += 2; - if (ret != 0) { - LOG_ERR("mc_deq for 2 obj failed\n"); - goto fail; - } - printf("dequeue MAX_BULK objs\n"); - ret = _ring_mc_dequeue_bulk(r, cur_dst, MAX_BULK); - cur_dst += MAX_BULK; - if (ret != 0) { - LOG_ERR("mc_deq for %d obj failed\n", MAX_BULK); - goto fail; - } - /* check data */ - if (memcmp(src, dst, cur_dst - dst)) { - LOG_ERR("data after dequeue is not the same\n"); - goto fail; - } - - printf("test watermark and default bulk enqueue / dequeue\n"); - _ring_set_water_mark(r, 20); - num_elems = 16; - - cur_src = src; - cur_dst = dst; - - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); - cur_src += num_elems; - if (ret != 0) { - LOG_ERR("Cannot enqueue\n"); - goto fail; - } - ret = _ring_mp_enqueue_bulk(r, cur_src, num_elems); - if (ret != -EDQUOT) { - LOG_ERR("Watermark not exceeded\n"); - goto fail; - } - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); - cur_dst += num_elems; - if (ret != 0) { - LOG_ERR("Cannot dequeue\n"); - goto fail; - } - ret = _ring_mc_dequeue_bulk(r, cur_dst, num_elems); - cur_dst += num_elems; - if (ret != 0) { - LOG_ERR("Cannot dequeue2\n"); - goto fail; - } - - /* check data */ - if (memcmp(src, dst, cur_dst - dst)) { - LOG_ERR("data after dequeue is not the same\n"); - goto fail; - } - - printf("basic enqueu, dequeue test for ring <%s>@%p passed\n", - r->name, r); - - free(src); - free(dst); - return 0; - -fail: - free(src); - free(dst); - return -1; -} - -/* global shared ring used for stress testing */ -static _ring_t *r_stress; - -/* Stress func for Multi producer only */ -static int producer_fn(void) -{ - unsigned i; - - void **src = NULL; - - /* alloc dummy object pointers */ - src = malloc(MAX_BULK * 2 * sizeof(void *)); - if (src == NULL) { - LOG_ERR("failed to allocate producer memory.\n"); - return -1; - } - for (i = 0; i < MAX_BULK; i++) - src[i] = (void *)(unsigned long)i; - - do { - i = _ring_mp_enqueue_bulk(r_stress, src, MAX_BULK); - if (i == 0) { - free(src); - return 0; - } - } while (1); -} - -/* Stress func for Multi consumer only */ -static int consumer_fn(void) -{ - unsigned i; - void **src = NULL; - - /* alloc dummy object pointers */ - src = malloc(MAX_BULK * 2 * sizeof(void *)); - if (src == NULL) { - LOG_ERR("failed to allocate consumer memory.\n"); - return -1; - } - - do { - i = _ring_mc_dequeue_bulk(r_stress, src, MAX_BULK); - if (i == 0) { - for (i = 0; i < MAX_BULK; i++) { - if (src[i] != (void *)(unsigned long)i) { - free(src); - printf("data mismatch.. lockless ops fail\n"); - return -1; - } - } - free(src); - printf("\n Test OK !\n"); - return 0; - } - } while (1); -} - -/* - * Note : make sure that both enqueue and dequeue - * operation starts at same time so to avoid data corruption - * Its because atomic lock will protect only indexes, but if order of - * read or write operation incorrect then data mismatch will happen - * So its resposibility of application develop to take care of order of - * data read or write. -*/ -typedef enum { - one_enq_one_deq, /* One thread to enqueue one to - dequeu at same time */ - one_enq_rest_deq, /* one thread to enq rest to - dequeue at same time */ - one_deq_rest_enq, /* one to deq and rest enq at very same time */ - multi_enq_multi_deq /* multiple enq,deq */ -} stress_type_t; - -static void test_ring_stress(stress_type_t type) -{ - int thr; - - thr = odp_thread_id(); - - switch (type) { - case one_enq_one_deq: - if (thr == 1) - producer_fn(); - if (thr == 2) - consumer_fn(); - break; - case multi_enq_multi_deq: - if (thr % 2 == 0) - producer_fn(); - else - consumer_fn(); - break; - case one_deq_rest_enq: - case one_enq_rest_deq:/*TBD*/ - default: - LOG_ERR("Invalid stress type or test case yet not supported\n"); - } -} - -static void *test_ring(void *arg) -{ - ring_arg_t *parg = (ring_arg_t *)arg; - int thr; - char ring_name[_RING_NAMESIZE]; - _ring_t *r; - int result = 0; - - thr = odp_thread_id(); - - printf("Thread %i starts\n", thr); - - switch (parg->thrdarg.testcase) { - case ODP_RING_TEST_BASIC: - snprintf(ring_name, sizeof(ring_name), "test_ring_%i", thr); - - r = _ring_create(ring_name, RING_SIZE, - 0 /* not used, alignement - taken care inside func : todo */); - if (r == NULL) { - LOG_ERR("ring create failed\n"); - result = -1; - break; - } - /* lookup ring from its name */ - if (_ring_lookup(ring_name) != r) { - LOG_ERR("ring lookup failed\n"); - result = -1; - break; - } - - /* basic operations */ - if (test_ring_basic(r) < 0) { - LOG_ERR("ring basic enqueue/dequeu ops failed\n"); - result = -1; - } - - if (result) - _ring_list_dump(); - - break; - - case ODP_RING_TEST_STRESS: - test_ring_stress(parg->stress_type); - - if (result) - _ring_list_dump(); - break; - - default: - LOG_ERR("Invalid test case [%d]\n", parg->thrdarg.testcase); - result = -1; - break; - } - - LOG_DBG("result = %d\n", result); - if (result == 0) - printf("test_ring Result:pass\n"); - else - printf("test_ring Result:fail\n"); - - fflush(stdout); - - return parg; -} - -int main(int argc TEST_UNUSED, char *argv[] TEST_UNUSED) -{ - ring_arg_t rarg; - odph_linux_pthread_t thread_tbl[MAX_WORKERS]; - odp_cpumask_t cpu_mask; - int num_workers; - char ring_name[_RING_NAMESIZE]; - odp_instance_t instance; - odph_linux_thr_params_t thr_params; - - if (odp_init_global(&instance, NULL, NULL)) { - LOG_ERR("Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - if (odp_init_local(instance, ODP_THREAD_CONTROL)) { - LOG_ERR("Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - _ring_tailq_init(); - - num_workers = odp_cpumask_default_worker(&cpu_mask, MAX_WORKERS); - rarg.thrdarg.numthrds = rarg.thrdarg.numthrds; - - rarg.thrdarg.testcase = ODP_RING_TEST_BASIC; - - memset(&thr_params, 0, sizeof(thr_params)); - thr_params.start = test_ring; - thr_params.arg = &rarg; - thr_params.thr_type = ODP_THREAD_WORKER; - thr_params.instance = instance; - - printf("starting stess test type : %d..\n", rarg.stress_type); - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); - odph_linux_pthread_join(thread_tbl, num_workers); - - rarg.thrdarg.testcase = ODP_RING_TEST_STRESS; - rarg.stress_type = one_enq_one_deq; - - printf("starting stess test type : %d..\n", rarg.stress_type); - snprintf(ring_name, sizeof(ring_name), "test_ring_stress"); - r_stress = _ring_create(ring_name, RING_SIZE, - 0/* not used, alignement - taken care inside func : todo */); - if (r_stress == NULL) { - LOG_ERR("ring create failed\n"); - goto fail; - } - /* lookup ring from its name */ - if (_ring_lookup(ring_name) != r_stress) { - LOG_ERR("ring lookup failed\n"); - goto fail; - } - - thr_params.start = test_ring; - thr_params.arg = &rarg; - - odph_linux_pthread_create(&thread_tbl[0], &cpu_mask, &thr_params); - odph_linux_pthread_join(thread_tbl, num_workers); - -fail: - if (odp_term_local()) { - LOG_ERR("Error: ODP local term failed.\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - LOG_ERR("Error: ODP global term failed.\n"); - exit(EXIT_FAILURE); - } - - return 0; -}
Fixes: https://bugs.linaro.org/show_bug.cgi?id=2228 Convert ring test program into cunit framework Improve LCOV coverage for linux-generic/pktio/ring.c Signed-off-by: Yi He <yi.he@linaro.org> --- platform/linux-generic/test/Makefile.am | 2 +- platform/linux-generic/test/ring/Makefile.am | 20 +- platform/linux-generic/test/ring/ring_basic.c | 392 ++++++++++++++++++++ platform/linux-generic/test/ring/ring_main.c | 12 + platform/linux-generic/test/ring/ring_stress.c | 270 ++++++++++++++ platform/linux-generic/test/ring/ring_suites.c | 70 ++++ platform/linux-generic/test/ring/ring_suites.h | 33 ++ platform/linux-generic/test/ring/ringtest.c | 493 ------------------------- 8 files changed, 787 insertions(+), 505 deletions(-) create mode 100644 platform/linux-generic/test/ring/ring_basic.c create mode 100644 platform/linux-generic/test/ring/ring_main.c create mode 100644 platform/linux-generic/test/ring/ring_stress.c create mode 100644 platform/linux-generic/test/ring/ring_suites.c create mode 100644 platform/linux-generic/test/ring/ring_suites.h delete mode 100644 platform/linux-generic/test/ring/ringtest.c