On Wed, Dec 17, 2014 at 11:05:52AM +0100, Ola Liljedahl wrote:
> On 17 December 2014 at 10:19, Jerin Jacob
> <jerin.ja...@caviumnetworks.com> wrote:
> > On Wed, Dec 17, 2014 at 09:28:48AM +0530, Jerin Jacob wrote:
> >> On Mon, Dec 08, 2014 at 11:49:46PM +0100, Ola Liljedahl wrote:
> >> > Signed-off-by: Ola Liljedahl <ola.liljed...@linaro.org>
> >> > ---
> >> > (This document/code contribution attached is provided under the terms of
> >> > agreement LES-LTM-21309)
> >> > A new cunit test program test/validation/odp_timer.c for the updated 
> >> > timer API.
> >> >
> >> >  test/validation/.gitignore  |   1 +
> >> >  test/validation/Makefile.am |   4 +-
> >> >  test/validation/odp_timer.c | 336 
> >> > ++++++++++++++++++++++++++++++++++++++++++++
> >> >  3 files changed, 340 insertions(+), 1 deletion(-)
> >> >  create mode 100644 test/validation/odp_timer.c
> >> >
> >> > diff --git a/test/validation/.gitignore b/test/validation/.gitignore
> >> > index 37e2594..586def0 100644
> >> > --- a/test/validation/.gitignore
> >> > +++ b/test/validation/.gitignore
> >> > @@ -4,3 +4,4 @@ odp_init
> >> >  odp_queue
> >> >  odp_crypto
> >> >  odp_shm
> >> > +odp_timer
> >> > diff --git a/test/validation/Makefile.am b/test/validation/Makefile.am
> >> > index 8547085..043bf4c 100644
> >> > --- a/test/validation/Makefile.am
> >> > +++ b/test/validation/Makefile.am
> >> > @@ -6,13 +6,14 @@ AM_LDFLAGS += -static
> >> >  if ODP_CUNIT_ENABLED
> >> >  TESTS = ${bin_PROGRAMS}
> >> >  check_PROGRAMS = ${bin_PROGRAMS}
> >> > -bin_PROGRAMS = odp_init odp_queue odp_crypto odp_shm
> >> > +bin_PROGRAMS = odp_init odp_queue odp_crypto odp_shm odp_timer
> >> >  odp_init_LDFLAGS = $(AM_LDFLAGS)
> >> >  odp_queue_LDFLAGS = $(AM_LDFLAGS)
> >> >  odp_crypto_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/crypto
> >> >  odp_crypto_LDFLAGS = $(AM_LDFLAGS)
> >> >  odp_shm_CFLAGS = $(AM_CFLAGS)
> >> >  odp_shm_LDFLAGS = $(AM_LDFLAGS)
> >> > +odp_timer_LDFLAGS = $(AM_LDFLAGS)
> >> >  endif
> >> >
> >> >  dist_odp_init_SOURCES = odp_init.c
> >> > @@ -22,3 +23,4 @@ dist_odp_crypto_SOURCES = 
> >> > crypto/odp_crypto_test_async_inp.c \
> >> >                       crypto/odp_crypto_test_rng.c \
> >> >                       odp_crypto.c common/odp_cunit_common.c
> >> >  dist_odp_shm_SOURCES = odp_shm.c common/odp_cunit_common.c
> >> > +dist_odp_timer_SOURCES = odp_timer.c common/odp_cunit_common.c
> >> > diff --git a/test/validation/odp_timer.c b/test/validation/odp_timer.c
> >> > new file mode 100644
> >> > index 0000000..4b6b872
> >> > --- /dev/null
> >> > +++ b/test/validation/odp_timer.c
> >> > @@ -0,0 +1,336 @@
> >> > +/* Copyright (c) 2014, Linaro Limited
> >> > + * All rights reserved.
> >> > + *
> >> > + * SPDX-License-Identifier:     BSD-3-Clause
> >> > + */
> >> > +
> >> > +/**
> >> > + * @file
> >> > + */
> >> > +
> >> > +#include <assert.h>
> >> > +#include <unistd.h>
> >> > +#include <odp.h>
> >> > +#include <odp_timer.h>
> >> > +#include <odph_linux.h>
> >> > +#include <odph_chksum.h>
> >> > +#include "odp_cunit_common.h"
> >> > +
> >> > +/** @private Timeout range in milliseconds (ms) */
> >> > +#define RANGE_MS 2000
> >> > +
> >> > +/** @private Number of timers per thread */
> >> > +#define NTIMERS 2000
> >> > +
> >> > +/** @private Timeout pool size per thread */
> >> > +#define TMO_POOL_SIZE      (512 * NTIMERS)
> >> > +
> >> > +/** @private Barrier for thread synchronisation */
> >> > +static odp_barrier_t test_barrier;
> >> > +
> >> > +/** @private Timeout buffer pool handle used by all threads */
> >> > +static odp_buffer_pool_t tbp;
> >> > +
> >> > +/** @private Timer pool handle used by all threads */
> >> > +static odp_timer_pool_t tp;
> >> > +
> >> > +/** @private min() function */
> >> > +static int min(int a, int b)
> >> > +{
> >> > +   return a < b ? a : b;
> >> > +}
> >> > +
> >> > +/* @private Timer helper structure */
> >> > +struct test_timer {
> >> > +   odp_timer_t tim; /* Timer handle */
> >> > +   odp_buffer_t buf; /* Timeout buffer */
> >> > +   odp_buffer_t buf2; /* Copy of buffer handle */
> >> > +   uint64_t tick; /* Expiration tick or ODP_TICK_INVALID */
> >> > +};
> >> > +
> >> > +/* @private Handle a received (timeout) buffer */
> >> > +static void handle_tmo(odp_buffer_t buf, bool stale, uint64_t prev_tick)
> >> > +{
> >> > +   odp_timer_t tim = ODP_TIMER_INVALID;
> >> > +   uint64_t tick = ODP_TICK_INVALID;
> >> > +   struct test_timer *ttp = NULL;
> >> > +
> >> > +   /* Use assert() for correctness check of test program itself */
> >> > +   assert(buf != ODP_BUFFER_INVALID);
> >> > +   if (!odp_timer_tmo_metadata(buf, &tim, &tick, (void **)&ttp)) {
> >> > +           /* Not a default timeout buffer */
> >> > +           CU_FAIL("Unexpected buffer type received");
> >> > +           return;
> >> > +   }
> >> > +
> >> > +   if (tim == ODP_TIMER_INVALID)
> >> > +           CU_FAIL("odp_timer_tmo_metadata() invalid timer");
> >> > +   if (tick == ODP_TICK_INVALID)
> >> > +           CU_FAIL("odp_timer_tmo_metadata() invalid tick");
> >> > +   if (ttp == NULL)
> >> > +           CU_FAIL("odp_timer_tmo_metadata() null user ptr");
> >> > +
> >> > +   if (ttp->buf2 != buf)
> >> > +           CU_FAIL("odp_timer_tmo_metadata() wrong user ptr");
> >> > +   if (ttp->tim != tim)
> >> > +           CU_FAIL("odp_timer_tmo_metadata() wrong timer");
> >> > +   if (stale) {
> >> > +           /* Stale timeout => timer must have invalid tick */
> >> > +           if (ttp->tick != ODP_TICK_INVALID)
> >> > +                   CU_FAIL("Stale timeout for active timer");
> >> > +   } else {
> >> > +           /* Fresh timeout => timer must have matching tick */
> >> > +           if (ttp->tick != tick)
> >> > +                   CU_FAIL("odp_timer_tmo_metadata() wrong tick");
> >> > +           /* Check that timeout was delivered 'timely' */
> >> > +           if (tick > odp_timer_current_tick(tp))
> >> > +                   CU_FAIL("Timeout delivered too early");
> >> > +           if (tick < prev_tick)
> >> > +                   CU_FAIL("Timeout delivered too late");
> >> > +   }
> >> > +
> >> > +   /* Use assert() for correctness check of test program itself */
> >> > +   assert(ttp->buf == ODP_BUFFER_INVALID);
> >> > +   ttp->buf = buf;
> >> > +}
> >> > +
> >> > +/* @private Worker thread entrypoint which performs timer 
> >> > alloc/set/cancel/free
> >> > + * tests */
> >> > +static void *worker_entrypoint(void *arg)
> >> > +{
> >> > +   int thr = odp_thread_id();
> >> > +   uint32_t i;
> >> > +   unsigned seed = thr;
> >> > +   (void)arg;
> >> > +
> >> > +   odp_queue_t queue = odp_queue_create("timer_queue",
> >> > +                                        ODP_QUEUE_TYPE_POLL,
> >> > +                                        NULL);
> >> > +   if (queue == ODP_QUEUE_INVALID)
> >> > +           CU_FAIL_FATAL("Queue create failed");
> >> > +
> >> > +   struct test_timer *tt = malloc(sizeof(struct test_timer) * NTIMERS);
> >>
> >>
> >> allocate the memory from odp shm mem to share between different worker 
> >> threads
> >
> > Found tt used only for local storage. malloc is fine then.
> Good.
> 
> Are unit tests supposed to work with the multiprocess model as well
> and thus cannot use malloc() for shared data?

lets keep the ODP contract between implmentation and application so that
odp application can run on any run time enviroment.

> 
> >
> >>
> >>
> >> > +   if (tt == NULL)
> >> > +           perror("malloc"), abort();
> >> > +
> >> > +   /* Prepare all timers */
> >> > +   for (i = 0; i < NTIMERS; i++) {
> >> > +           tt[i].tim = odp_timer_alloc(tp, queue, &tt[i]);
> >> > +           if (tt[i].tim == ODP_TIMER_INVALID)
> >> > +                   CU_FAIL_FATAL("Failed to allocate timer");
> >> > +           tt[i].buf = odp_buffer_alloc(tbp);
> >> > +           if (tt[i].buf == ODP_BUFFER_INVALID)
> >> > +                   CU_FAIL_FATAL("Failed to allocate timeout buffer");
> >> > +           tt[i].buf2 = tt[i].buf;
> >> > +           tt[i].tick = ODP_TICK_INVALID;
> >> > +   }
> >> > +
> >> > +   odp_barrier_wait(&test_barrier);
> >> > +
> >> > +   /* Initial set all timers with a random expiration time */
> >> > +   uint32_t nset = 0;
> >> > +   for (i = 0; i < NTIMERS; i++) {
> >> > +           uint64_t tck = odp_timer_current_tick(tp) + 1 +
> >> > +                          odp_timer_ns_to_tick(tp,
> >> > +                                               (rand_r(&seed) % 
> >> > RANGE_MS)
> >> > +                                               * 1000000ULL);
> >> > +           tt[i].tick = odp_timer_set_abs(tt[i].tim, tck, &tt[i].buf);
> >> > +           uint64_t rc = tt[i].tick;
> >> > +           if (rc == ODP_TICK_TOOEARLY ||
> >> > +               rc == ODP_TICK_TOOLATE ||
> >> > +               rc == ODP_TICK_INVALID) {
> >> > +                   CU_FAIL("Failed to set timer");
> >> > +           }
> >> > +           nset++;
> >> > +   }
> >> > +
> >> > +   /* Step through wall time, 1ms at a time and check for expired 
> >> > timers */
> >> > +   uint32_t nrcv = 0;
> >> > +   uint32_t nreset = 0;
> >> > +   uint32_t ncancel = 0;
> >> > +   uint32_t ntoolate = 0;
> >> > +   uint32_t ms;
> >> > +   uint64_t prev_tick = odp_timer_current_tick(tp);
> >> > +   for (ms = 0; ms < 7 * RANGE_MS / 10; ms++) {
> >> > +           odp_buffer_t buf;
> >> > +           while ((buf = odp_queue_deq(queue)) != ODP_BUFFER_INVALID) {
> >> > +                   handle_tmo(buf, false, prev_tick - 1);
> >> > +                   nrcv++;
> >> > +           }
> >> > +           prev_tick = odp_timer_current_tick(tp);
> >> > +           i = rand_r(&seed) % NTIMERS;
> >> > +           if (tt[i].buf == ODP_BUFFER_INVALID &&
> >> > +               (rand_r(&seed) % 2 == 0)) {
> >> > +                   /* Timer active, cancel it */
> >> > +                   tt[i].tick = odp_timer_cancel(tt[i].tim, &tt[i].buf);
> >> > +                   if (tt[i].buf == ODP_BUFFER_INVALID) {
> >> > +                           /* Cancel failed, timer already expired */
> >> > +                           ntoolate++;
> >> > +                   }
> >> > +                   ncancel++;
> >> > +           } else {
> >> > +                   if (tt[i].buf != ODP_BUFFER_INVALID)
> >> > +                           /* Timer inactive => set */
> >> > +                           nset++;
> >> > +                   else
> >> > +                           /* Timer active => reset */
> >> > +                           nreset++;
> >> > +                   uint64_t tck = 1 + odp_timer_ns_to_tick(tp,
> >> > +                                  (rand_r(&seed) % RANGE_MS) * 
> >> > 1000000ULL);
> >> > +                   tt[i].tick = odp_timer_set_rel(tt[i].tim, tck,
> >> > +                                                  &tt[i].buf);
> >> > +                   uint64_t rc = tt[i].tick;
> >> > +                   if (rc == ODP_TICK_TOOEARLY ||
> >> > +                       rc == ODP_TICK_TOOLATE) {
> >> > +                           CU_FAIL("Failed to set timer 
> >> > (tooearly/toolate)");
> >> > +                   } else if (rc == ODP_TICK_INVALID) {
> >> > +                           /* Reset failed, timer already expired */
> >> > +                           ntoolate++;
> >> > +                   }
> >> > +           }
> >> > +           if (usleep(1000/*1ms*/) < 0)
> >> > +                   perror("usleep"), abort();
> >> > +   }
> >> > +
> >> > +   /* Free (including cancel) all timers */
> >> > +   uint32_t nstale = 0;
> >> > +   for (i = 0; i < NTIMERS; i++) {
> >> > +           tt[i].tick = odp_timer_free(tt[i].tim, &tt[i].buf);
> >> > +           if (tt[i].buf == ODP_BUFFER_INVALID)
> >> > +                   /* Cancel/free too late, timer already expired and
> >> > +                    * timoeut buffer enqueued */
> >> > +                   nstale++;
> >> > +   }
> >> > +
> >> > +   printf("Thread %u: %u timers set\n", thr, nset);
> >> > +   printf("Thread %u: %u timers reset\n", thr, nreset);
> >> > +   printf("Thread %u: %u timers cancelled\n", thr, ncancel);
> >> > +   printf("Thread %u: %u timers reset/cancelled too late\n",
> >> > +          thr, ntoolate);
> >> > +   printf("Thread %u: %u timeouts received\n", thr, nrcv);
> >> > +   printf("Thread %u: %u stale timeout(s) after odp_timer_free()\n",
> >> > +          thr, nstale);
> >> > +
> >> > +   /* Delay some more to ensure timeouts for expired timers can be
> >> > +    * received */
> >> > +   usleep(1000/*1ms*/);
> >> > +   while (nstale != 0) {
> >> > +           odp_buffer_t buf = odp_queue_deq(queue);
> >> > +           if (buf != ODP_BUFFER_INVALID) {
> >> > +                   handle_tmo(buf, true, 0/*Dont' care for stale 
> >> > tmo's*/);
> >> > +                   nstale--;
> >> > +           } else {
> >> > +                   CU_FAIL("Failed to receive stale timeout");
> >> > +                   break;
> >> > +           }
> >> > +   }
> >> > +   /* Check if there any more (unexpected) buffers */
> >> > +   odp_buffer_t buf = odp_queue_deq(queue);
> >> > +   if (buf != ODP_BUFFER_INVALID)
> >> > +           CU_FAIL("Unexpected buffer received");
> >> > +
> >> > +   printf("Thread %u: exiting\n", thr);
> >> > +   return NULL;
> >> > +}
> >> > +
> >> > +/* @private Timer test case entrypoint */
> >> > +static void test_odp_timer_all(void)
> >> > +{
> >> > +   odp_shm_t shm;
> >> > +   int num_workers = min(odp_sys_core_count(), MAX_WORKERS);
> >> > +
> >> > +   /* Create timeout buffer pools */
> >> > +   shm = odp_shm_reserve("tmo_bufs",
> >> > +                         TMO_POOL_SIZE * num_workers,
> >> > +                         ODP_CACHE_LINE_SIZE, 0);
> >> > +   if (shm == ODP_SHM_INVALID)
> >> > +           CU_FAIL_FATAL("Timeout shared memory alloc failed");
> >> > +
> >> > +   tbp = odp_buffer_pool_create("tmo_pool", odp_shm_addr(shm),
> >> > +                                  TMO_POOL_SIZE * num_workers,
> >> > +                                  0,
> >> > +                                  ODP_CACHE_LINE_SIZE,
> >> > +                                  ODP_BUFFER_TYPE_TIMEOUT);
> >> > +   if (tbp == ODP_BUFFER_POOL_INVALID)
> >> > +           CU_FAIL_FATAL("Timeout buffer pool create failed");
> >> > +
> >> > +#define NAME "timer_pool"
> >> > +#define RES (10 * ODP_TIME_MSEC / 3)
> >> > +#define MIN (10 * ODP_TIME_MSEC / 3)
> >> > +#define MAX (1000000 * ODP_TIME_MSEC)
> >> > +   /* Create a timer pool */
> >> > +   tp = odp_timer_pool_create(NAME, tbp,
> >> > +                              RES, MIN, MAX,
> >> > +                              num_workers * NTIMERS,
> >> > +                              true, ODP_CLOCK_CPU);
> >> > +   if (tp == ODP_TIMER_POOL_INVALID)
> >> > +           CU_FAIL_FATAL("Timer pool create failed");
> >> > +
> >> > +   /* Start all created timer pools */
> >> > +   odp_timer_pool_start();
> >> > +
> >> > +   odp_timer_pool_info_t tpinfo;
> >> > +   size_t sz = odp_timer_pool_info(tp, &tpinfo, sizeof(tpinfo));
> >> > +   if (sz < offsetof(odp_timer_pool_info_t, name) + strlen(NAME) + 1)
> >> > +           CU_FAIL("odp_timer_pool_info");
> >> > +   CU_ASSERT(strcmp(tpinfo.name, NAME) == 0);
> >> > +   CU_ASSERT(tpinfo.resolution == RES);
> >> > +   CU_ASSERT(tpinfo.min_tmo == odp_timer_ns_to_tick(tp, MIN));
> >> > +   CU_ASSERT(tpinfo.max_tmo == odp_timer_ns_to_tick(tp, MAX));
> >> > +   printf("Timer pool\n");
> >> > +   printf("----------\n");
> >> > +   printf("  name: %s\n", tpinfo.name);
> >> > +   printf("  resolution: %"PRIu64" ns (%"PRIu64" us)\n",
> >> > +          tpinfo.resolution, tpinfo.resolution / 1000);
> >> > +   printf("  min tmo: %"PRIu64" tick(s)\n", tpinfo.min_tmo);
> >> > +   printf("  max tmo: %"PRIu64" ticks\n", tpinfo.max_tmo);
> >> > +   printf("\n");
> >> > +
> >> > +   printf("#timers..: %u\n", NTIMERS);
> >> > +   printf("Tmo range: %u ms (%"PRIu64" ticks)\n", RANGE_MS,
> >> > +          odp_timer_ns_to_tick(tp, 1000000ULL * RANGE_MS));
> >> > +   printf("\n");
> >> > +
> >> > +   uint64_t tick;
> >> > +   for (tick = 0; tick < 1000000000000ULL; tick += 1000000ULL) {
> >> > +           uint64_t ns = odp_timer_tick_to_ns(tp, tick);
> >> > +           uint64_t t2 = odp_timer_ns_to_tick(tp, ns);
> >> > +           if (tick != t2)
> >> > +                   CU_FAIL("Invalid conversion tick->ns->tick");
> >> > +   }
> >> > +
> >> > +   /* Initialize barrier used by worker threads for synchronization */
> >> > +   odp_barrier_init(&test_barrier, num_workers);
> >> > +
> >> > +   /* Create and start worker threads */
> >> > +   pthrd_arg thrdarg;
> >> > +   thrdarg.testcase = 0;
> >> > +   thrdarg.numthrds = num_workers;
> >> > +   odp_cunit_thread_create(worker_entrypoint, &thrdarg);
> >> > +
> >> > +   /* Wait for worker threads to exit */
> >> > +   odp_cunit_thread_exit(&thrdarg);
> >> > +
> >> > +   /* Check some statistics after the test */
> >> > +   sz = odp_timer_pool_info(tp, &tpinfo, sizeof(tpinfo));
> >> > +   if (sz < offsetof(odp_timer_pool_info_t, name) + strlen(NAME) + 1)
> >> > +           CU_FAIL("odp_timer_pool_info");
> >> > +   CU_ASSERT(tpinfo.num_timers == (unsigned)num_workers * NTIMERS);
> >> > +   CU_ASSERT(tpinfo.cur_timers == 0);
> >> > +   CU_ASSERT(tpinfo.hwm_timers == (unsigned)num_workers * NTIMERS);
> >> > +
> >> > +   /* Destroy timer pool, all timers must have been freed */
> >> > +   odp_timer_pool_destroy(tp);
> >> > +
> >> > +   CU_PASS("ODP timer test");
> >> > +}
> >> > +
> >> > +CU_TestInfo test_odp_timer[] = {
> >> > +   {"test_odp_timer_all",  test_odp_timer_all},
> >> > +   CU_TEST_INFO_NULL,
> >> > +};
> >> > +
> >> > +CU_SuiteInfo odp_testsuites[] = {
> >> > +   {"Timer", NULL, NULL, NULL, NULL, test_odp_timer},
> >> > +   CU_SUITE_INFO_NULL,
> >> > +};
> >> > --
> >> > 1.9.1
> >> >
> >> >
> >> > _______________________________________________
> >> > lng-odp mailing list
> >> > lng-odp@lists.linaro.org
> >> > http://lists.linaro.org/mailman/listinfo/lng-odp
> >>
> >> _______________________________________________
> >> lng-odp mailing list
> >> lng-odp@lists.linaro.org
> >> http://lists.linaro.org/mailman/listinfo/lng-odp

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to