Message ID | 1463472682-2703-1-git-send-email-yi.he@linaro.org |
---|---|
State | Superseded |
Headers | show |
On 17 May 2016 at 04:11, Yi He <yi.he@linaro.org> 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> > Tested-by: Mike Holmes <mike.holmes@linaro.org> This does fix the bug > 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 05998e3..85417e2 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 \ > pktio/pktio_run_tap \ > - 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; > -} > -- > 1.9.1 > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > https://lists.linaro.org/mailman/listinfo/lng-odp >
This patch fails to apply. Needs a rebase? bill@Ubuntu15:~/linaro/review$ git am --reject ~/Mail/Incoming/Yi\ He/1 Applying: linux-generic: test: ring: convert to cunit and improve coverage Checking patch platform/linux-generic/test/Makefile.am... error: while searching for: if test_vald TESTS = pktio/pktio_run \ pktio/pktio_run_tap \ ring/ringtest$(EXEEXT) \ shmem/shmem_linux \ ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ error: patch failed: platform/linux-generic/test/Makefile.am:8 Checking patch platform/linux-generic/test/ring/Makefile.am... Checking patch platform/linux-generic/test/ring/ring_basic.c... Checking patch platform/linux-generic/test/ring/ring_main.c... Checking patch platform/linux-generic/test/ring/ring_stress.c... Checking patch platform/linux-generic/test/ring/ring_suites.c... Checking patch platform/linux-generic/test/ring/ring_suites.h... Checking patch platform/linux-generic/test/ring/ringtest.c... Applying patch platform/linux-generic/test/Makefile.am with 1 reject... Rejected hunk #1. Applied patch platform/linux-generic/test/ring/Makefile.am cleanly. Applied patch platform/linux-generic/test/ring/ring_basic.c cleanly. Applied patch platform/linux-generic/test/ring/ring_main.c cleanly. Applied patch platform/linux-generic/test/ring/ring_stress.c cleanly. Applied patch platform/linux-generic/test/ring/ring_suites.c cleanly. Applied patch platform/linux-generic/test/ring/ring_suites.h cleanly. Applied patch platform/linux-generic/test/ring/ringtest.c cleanly. Patch failed at 0001 linux-generic: test: ring: convert to cunit and improve coverage The copy of the patch that failed is found in: .git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". On Tue, May 17, 2016 at 3:11 AM, Yi He <yi.he@linaro.org> 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 05998e3..85417e2 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 \ > pktio/pktio_run_tap \ > - 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; > -} > -- > 1.9.1 > > _______________________________________________ > lng-odp mailing list > lng-odp@lists.linaro.org > https://lists.linaro.org/mailman/listinfo/lng-odp >
Hi, Bill I've re-based and re-send the v2 patch. thanks and best regards, Yi On 20 May 2016 at 08:09, Bill Fischofer <bill.fischofer@linaro.org> wrote: > This patch fails to apply. Needs a rebase? > > bill@Ubuntu15:~/linaro/review$ git am --reject ~/Mail/Incoming/Yi\ He/1 > Applying: linux-generic: test: ring: convert to cunit and improve coverage > Checking patch platform/linux-generic/test/Makefile.am... > error: while searching for: > if test_vald > TESTS = pktio/pktio_run \ > pktio/pktio_run_tap \ > ring/ringtest$(EXEEXT) \ > shmem/shmem_linux \ > ${top_builddir}/test/validation/atomic/atomic_main$(EXEEXT) \ > ${top_builddir}/test/validation/barrier/barrier_main$(EXEEXT) \ > > error: patch failed: platform/linux-generic/test/Makefile.am:8 > Checking patch platform/linux-generic/test/ring/Makefile.am... > Checking patch platform/linux-generic/test/ring/ring_basic.c... > Checking patch platform/linux-generic/test/ring/ring_main.c... > Checking patch platform/linux-generic/test/ring/ring_stress.c... > Checking patch platform/linux-generic/test/ring/ring_suites.c... > Checking patch platform/linux-generic/test/ring/ring_suites.h... > Checking patch platform/linux-generic/test/ring/ringtest.c... > Applying patch platform/linux-generic/test/Makefile.am with 1 reject... > Rejected hunk #1. > Applied patch platform/linux-generic/test/ring/Makefile.am cleanly. > Applied patch platform/linux-generic/test/ring/ring_basic.c cleanly. > Applied patch platform/linux-generic/test/ring/ring_main.c cleanly. > Applied patch platform/linux-generic/test/ring/ring_stress.c cleanly. > Applied patch platform/linux-generic/test/ring/ring_suites.c cleanly. > Applied patch platform/linux-generic/test/ring/ring_suites.h cleanly. > Applied patch platform/linux-generic/test/ring/ringtest.c cleanly. > Patch failed at 0001 linux-generic: test: ring: convert to cunit and > improve coverage > The copy of the patch that failed is found in: .git/rebase-apply/patch > When you have resolved this problem, run "git am --continue". > If you prefer to skip this patch, run "git am --skip" instead. > To restore the original branch and stop patching, run "git am --abort". > > > On Tue, May 17, 2016 at 3:11 AM, Yi He <yi.he@linaro.org> 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 05998e3..85417e2 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 \ >> pktio/pktio_run_tap \ >> - 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; >> -} >> -- >> 1.9.1 >> >> _______________________________________________ >> lng-odp mailing list >> 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 05998e3..85417e2 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 \ pktio/pktio_run_tap \ - 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