diff mbox

odp_counter.h: relaxed memory model for atomic counters

Message ID 1415564069-11554-1-git-send-email-ola.liljedahl@linaro.org
State New
Headers show

Commit Message

Ola Liljedahl Nov. 9, 2014, 8:14 p.m. UTC
Signed-off-by: Ola Liljedahl <ola.liljedahl@linaro.org>
---
New API odp_counter.h with support for 32- and 64-bit shared (atomic) counters.
Implementation uses GCC __atomic builtins behind a wrapper type and wrapper API
which enforces the usage of the appropriate access functions.
This also provides a layer of abstraction which enables the ODP implementation
to override or complement the compiler implementation.
API test program based on the test program for odp_atomic.h.

 .gitignore                                         |   1 +
 example/generator/odp_generator.c                  |  42 ++-
 platform/linux-generic/Makefile.am                 |   1 +
 platform/linux-generic/include/api/odp.h           |   1 +
 platform/linux-generic/include/api/odp_counter.h   | 206 ++++++++++++
 .../linux-generic/include/api/odp_ticketlock.h     |   4 +-
 .../linux-generic/include/odp_buffer_internal.h    |   4 +-
 platform/linux-generic/odp_buffer.c                |   3 +-
 platform/linux-generic/odp_crypto.c                |   6 +-
 platform/linux-generic/odp_thread.c                |   6 +-
 platform/linux-generic/odp_ticketlock.c            |   9 +-
 test/api_test/Makefile.am                          |   4 +-
 test/api_test/odp_counter_test.c                   | 362 +++++++++++++++++++++
 test/api_test/odp_counter_test.h                   |  51 +++
 14 files changed, 666 insertions(+), 34 deletions(-)
 create mode 100644 platform/linux-generic/include/api/odp_counter.h
 create mode 100644 test/api_test/odp_counter_test.c
 create mode 100644 test/api_test/odp_counter_test.h

Comments

Mike Holmes Nov. 10, 2014, 6:58 p.m. UTC | #1
I test built this with CFLAGS="-std=c99 -Wno-error" CC=clang ./configure &&
make -k and did not find any new warnings, and ran it on x86

My only issue is that now that we have cunit tests I think that
 test/api_test/odp_counter_test.c  would be much better as a unit test for
counters.

On 9 November 2014 15:14, Ola Liljedahl <ola.liljedahl@linaro.org> wrote:

> Signed-off-by: Ola Liljedahl <ola.liljedahl@linaro.org>
> ---
> New API odp_counter.h with support for 32- and 64-bit shared (atomic)
> counters.
> Implementation uses GCC __atomic builtins behind a wrapper type and
> wrapper API
> which enforces the usage of the appropriate access functions.
> This also provides a layer of abstraction which enables the ODP
> implementation
> to override or complement the compiler implementation.
> API test program based on the test program for odp_atomic.h.
>
>  .gitignore                                         |   1 +
>  example/generator/odp_generator.c                  |  42 ++-
>  platform/linux-generic/Makefile.am                 |   1 +
>  platform/linux-generic/include/api/odp.h           |   1 +
>  platform/linux-generic/include/api/odp_counter.h   | 206 ++++++++++++
>  .../linux-generic/include/api/odp_ticketlock.h     |   4 +-
>  .../linux-generic/include/odp_buffer_internal.h    |   4 +-
>  platform/linux-generic/odp_buffer.c                |   3 +-
>  platform/linux-generic/odp_crypto.c                |   6 +-
>  platform/linux-generic/odp_thread.c                |   6 +-
>  platform/linux-generic/odp_ticketlock.c            |   9 +-
>  test/api_test/Makefile.am                          |   4 +-
>  test/api_test/odp_counter_test.c                   | 362
> +++++++++++++++++++++
>  test/api_test/odp_counter_test.h                   |  51 +++
>  14 files changed, 666 insertions(+), 34 deletions(-)
>  create mode 100644 platform/linux-generic/include/api/odp_counter.h
>  create mode 100644 test/api_test/odp_counter_test.c
>  create mode 100644 test/api_test/odp_counter_test.h
>
> diff --git a/.gitignore b/.gitignore
> index 57b47ea..9d3d9a3 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -38,6 +38,7 @@ odp_atomic
>  odp_shm
>  odp_ring
>  odp_timer_ping
> +odp_counters
>  odp_pktio
>  odp_timer_test
>  odp_generator
> diff --git a/example/generator/odp_generator.c
> b/example/generator/odp_generator.c
> index ffa5e62..782b7f0 100644
> --- a/example/generator/odp_generator.c
> +++ b/example/generator/odp_generator.c
> @@ -62,10 +62,10 @@ typedef struct {
>   * counters
>  */
>  static struct {
> -       odp_atomic_u64_t seq;   /**< ip seq to be send */
> -       odp_atomic_u64_t ip;    /**< ip packets */
> -       odp_atomic_u64_t udp;   /**< udp packets */
> -       odp_atomic_u64_t icmp;  /**< icmp packets */
> +       odp_counter_u64_t seq;  /**< ip seq to be send */
> +       odp_counter_u64_t ip;   /**< ip packets */
> +       odp_counter_u64_t udp;  /**< udp packets */
> +       odp_counter_u64_t icmp; /**< icmp packets */
>  } counters;
>
>  /** * Thread specific arguments
> @@ -201,7 +201,7 @@ static void pack_udp_pkt(odp_buffer_t obuf)
>         ip->tot_len = odp_cpu_to_be_16(args->appl.payload +
> ODPH_UDPHDR_LEN +
>                                        ODPH_IPV4HDR_LEN);
>         ip->proto = ODPH_IPPROTO_UDP;
> -       seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF;
> +       seq = odp_counter_u64_read_inc(&counters.seq) % 0xFFFF;
>         ip->id = odp_cpu_to_be_16(seq);
>         ip->chksum = 0;
>         odph_ipv4_csum_update(pkt);
> @@ -258,7 +258,7 @@ static void pack_icmp_pkt(odp_buffer_t obuf)
>         ip->tot_len = odp_cpu_to_be_16(args->appl.payload +
> ODPH_ICMPHDR_LEN +
>                                        ODPH_IPV4HDR_LEN);
>         ip->proto = ODPH_IPPROTO_ICMP;
> -       seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff;
> +       seq = odp_counter_u64_read_inc(&counters.seq) % 0xffff;
>         ip->id = odp_cpu_to_be_16(seq);
>         ip->chksum = 0;
>         odph_ipv4_csum_update(pkt);
> @@ -335,11 +335,14 @@ static void *gen_send_thread(void *arg)
>
>                 if (args->appl.interval != 0) {
>                         printf("  [%02i] send pkt no:%ju seq %ju\n",
> -                              thr, counters.seq, counters.seq%0xffff);
> +                              thr,
> +                              odp_counter_u64_read(&counters.seq),
> +                              odp_counter_u64_read(&counters.seq)%0xffff);
>                         /* TODO use odp timer */
>                         usleep(args->appl.interval * 1000);
>                 }
> -               if (args->appl.number != -1 && counters.seq
> +               if (args->appl.number != -1 &&
> +                   odp_counter_u64_read(&counters.seq)
>                     >= (unsigned int)args->appl.number) {
>                         break;
>                 }
> @@ -348,7 +351,8 @@ static void *gen_send_thread(void *arg)
>         /* receive number of reply pks until timeout */
>         if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) {
>                 while (args->appl.timeout >= 0) {
> -                       if (counters.icmp >= (unsigned
> int)args->appl.number)
> +                       if (odp_counter_u64_read(&counters.icmp) >=
> +                           (unsigned int)args->appl.number)
>                                 break;
>                         /* TODO use odp timer */
>                         sleep(1);
> @@ -358,10 +362,12 @@ static void *gen_send_thread(void *arg)
>
>         /* print info */
>         if (args->appl.mode == APPL_MODE_UDP) {
> -               printf("  [%02i] total send: %ju\n", thr, counters.seq);
> +               printf("  [%02i] total send: %ju\n",
> +                      thr, odp_counter_u64_read(&counters.seq));
>         } else if (args->appl.mode == APPL_MODE_PING) {
>                 printf("  [%02i] total send: %ju total receive: %ju\n",
> -                      thr, counters.seq, counters.icmp);
> +                      thr, odp_counter_u64_read(&counters.seq),
> +                      odp_counter_u64_read(&counters.icmp));
>         }
>         return arg;
>  }
> @@ -395,7 +401,7 @@ static void print_pkts(int thr, odp_packet_t
> pkt_tbl[], unsigned len)
>                 if (!odp_packet_inflag_ipv4(pkt))
>                         continue;
>
> -               odp_atomic_inc_u64(&counters.ip);
> +               odp_counter_u64_inc(&counters.ip);
>                 rlen += sprintf(msg, "receive Packet proto:IP ");
>                 buf = odp_buffer_addr(odp_packet_to_buffer(pkt));
>                 ip = (odph_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt));
> @@ -405,7 +411,7 @@ static void print_pkts(int thr, odp_packet_t
> pkt_tbl[], unsigned len)
>
>                 /* udp */
>                 if (ip->proto == ODPH_IPPROTO_UDP) {
> -                       odp_atomic_inc_u64(&counters.udp);
> +                       odp_counter_u64_inc(&counters.udp);
>                         udp = (odph_udphdr_t *)(buf + offset);
>                         rlen += sprintf(msg + rlen, "UDP payload %d ",
>                                         odp_be_to_cpu_16(udp->length) -
> @@ -417,7 +423,7 @@ static void print_pkts(int thr, odp_packet_t
> pkt_tbl[], unsigned len)
>                         icmp = (odph_icmphdr_t *)(buf + offset);
>                         /* echo reply */
>                         if (icmp->type == ICMP_ECHOREPLY) {
> -                               odp_atomic_inc_u64(&counters.icmp);
> +                               odp_counter_u64_inc(&counters.icmp);
>                                 memcpy(&tvsend, buf + offset +
> ODPH_ICMPHDR_LEN,
>                                        sizeof(struct timeval));
>                                 /* TODO This should be changed to use an
> @@ -530,10 +536,10 @@ int main(int argc, char *argv[])
>         }
>
>         /* init counters */
> -       odp_atomic_init_u64(&counters.seq);
> -       odp_atomic_init_u64(&counters.ip);
> -       odp_atomic_init_u64(&counters.udp);
> -       odp_atomic_init_u64(&counters.icmp);
> +       odp_counter_u64_init(&counters.seq, 0);
> +       odp_counter_u64_init(&counters.ip, 0);
> +       odp_counter_u64_init(&counters.udp, 0);
> +       odp_counter_u64_init(&counters.icmp, 0);
>
>         /* Reserve memory for args from shared mem */
>         shm = odp_shm_reserve("shm_args", sizeof(args_t),
> diff --git a/platform/linux-generic/Makefile.am
> b/platform/linux-generic/Makefile.am
> index 0153a22..39a035d 100644
> --- a/platform/linux-generic/Makefile.am
> +++ b/platform/linux-generic/Makefile.am
> @@ -17,6 +17,7 @@ include_HEADERS = \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_compiler.h \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_config.h \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_coremask.h \
> +
>  $(top_srcdir)/platform/linux-generic/include/api/odp_counter.h \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_crypto.h \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_debug.h \
>
> $(top_srcdir)/platform/linux-generic/include/api/odp_hints.h \
> diff --git a/platform/linux-generic/include/api/odp.h
> b/platform/linux-generic/include/api/odp.h
> index 6e4f69e..9aa05e3 100644
> --- a/platform/linux-generic/include/api/odp.h
> +++ b/platform/linux-generic/include/api/odp.h
> @@ -31,6 +31,7 @@ extern "C" {
>  #include <odp_barrier.h>
>  #include <odp_spinlock.h>
>  #include <odp_atomic.h>
> +#include <odp_counter.h>
>  #include <odp_init.h>
>  #include <odp_system_info.h>
>  #include <odp_thread.h>
> diff --git a/platform/linux-generic/include/api/odp_counter.h
> b/platform/linux-generic/include/api/odp_counter.h
> new file mode 100644
> index 0000000..0ee1ec1
> --- /dev/null
> +++ b/platform/linux-generic/include/api/odp_counter.h
> @@ -0,0 +1,206 @@
> +/* Copyright (c) 2013, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +/**
> + * @file odp_counter.h
> + *
> + * ODP atomic counter types and operations, suitable for e.g. shared
> statistics.
> + * Relaxed memory model assumed for lowest overhead. These types and
> + * operations cannot be used for synchronization!
> + * Scalar variable wrapped in a struct to avoid accessing scalar directly
> + * without using the required access functions.
> + * Counter functions must be used to operate on counter variables!
> + */
> +
> +#ifndef ODP_COUNTER_H_
> +#define ODP_COUNTER_H_
> +
> +#include <stdint.h>
> +#include <odp_align.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/**
> + * 32-bit (unsigned) atomic counter type
> + */
> +typedef struct {
> +       uint32_t v; /**< Actual storage for the counter variable */
> +} odp_counter_u32_t
> +ODP_ALIGNED(sizeof(uint32_t)); /* Enforce alignement! */
> +
> +/**
> + * 64-bit (unsigned) atomic counter type
> + */
> +typedef struct {
> +       uint64_t v; /**< Actual storage for the counter variable */
> +       /* Room for other data structures (e.g. spin lock) that might be
> +        * needed to ensure atomicity on some architectures */
> +} odp_counter_u64_t
> +ODP_ALIGNED(sizeof(uint64_t)); /* Enforce alignement! */
> +
>
> +/*****************************************************************************
> + * Operations on 32-bit atomic counters
> + * odp_counter_u32_init - returns no value
> + * odp_counter_u32_read - returns current value
> + * odp_counter_u32_write - returns no value
> + * odp_counter_u32_add - returns no value
> + * odp_counter_u32_read_inc - returns old value
> + * odp_counter_u32_inc - returns no value
> +
> *****************************************************************************/
> +
> +/**
> + * Initialize 32-bit counter variable
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + * @param val   Initial value
> + */
> +static inline void odp_counter_u32_init(odp_counter_u32_t *ptr, uint32_t
> val)
> +{
> +       __atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Read 32-bit counter variable
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + *
> + * @return Value of the variable
> + */
> +static inline uint32_t odp_counter_u32_read(const odp_counter_u32_t *ptr)
> +{
> +       return __atomic_load_n(&ptr->v, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Write 32-bit counter variable
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + * @param val   Value to write to the variable
> + */
> +static inline void odp_counter_u32_write(odp_counter_u32_t *ptr, uint32_t
> val)
> +{
> +       __atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Atomic add to 32-bit counter variable
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + * @param incr  The value to be added to the counter variable
> + */
> +static inline void odp_counter_u32_add(odp_counter_u32_t *ptr, uint32_t
> incr)
> +{
> +       (void)__atomic_add_fetch(&ptr->v, incr, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Atomic increment (+1) of 32-bit counter variable, return original value
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + *
> + * @return Previous value of counter
> + */
> +static inline uint32_t odp_counter_u32_read_inc(odp_counter_u32_t *ptr)
> +{
> +       return __atomic_fetch_add(&ptr->v, 1, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Atomic increment (+1) 32-bit counter variable
> + *
> + * @param ptr   Pointer to a 32-bit counter variable
> + */
> +static inline void odp_counter_u32_inc(odp_counter_u32_t *ptr)
> +{
> +       (void)__atomic_add_fetch(&ptr->v, 1, __ATOMIC_RELAXED);
> +}
> +
>
> +/*****************************************************************************
> + * Operations on 64-bit atomic counters
> + * odp_counter_u64_init
> + * odp_counter_u64_read
> + * odp_counter_u64_write
> + * odp_counter_u64_add
> + * odp_counter_u64_read_inc
> + * odp_counter_u64_inc
> +
> *****************************************************************************/
> +
> +/**
> + * Read 64-bit counter variable
> + *
> + * @param ptr   Pointer to a 64-bit counter variable
> + *
> + * @return Value of the counter variable
> + */
> +static inline uint64_t odp_counter_u64_read(const odp_counter_u64_t *ptr)
> +{
> +       return __atomic_load_n(&ptr->v, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Write 64-bit counter variable
> + *
> + * @param ptr  Pointer to a 64-bit counter variable
> + * @param val  Value to write to the counter variable
> + */
> +static inline void odp_counter_u64_write(odp_counter_u64_t *ptr, uint64_t
> val)
> +{
> +       __atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Initialize 64-bit counter variable
> + * Perform implementation specific initializations, assign initial value.
> + *
> + * @param ptr   Pointer to a 64-bit counter variable
> + * @param val   Initial value
> + */
> +static inline void odp_counter_u64_init(odp_counter_u64_t *ptr, uint64_t
> val)
> +{
> +       __atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Atomic add to 64-bit counter variable
> + *
> + * @param ptr   Pointer to a 64-bit counter variable
> + * @param incr  The value to be added to the counter variable
> + */
> +static inline void odp_counter_u64_add(odp_counter_u64_t *ptr, uint64_t
> incr)
> +{
> +       (void)__atomic_add_fetch(&ptr->v, incr, __ATOMIC_RELAXED);
> +}
> +
> +
> +/**
> + * Atomic increment (+1) 64-bit counter variable and return original value
> + *
> + * @param ptr   Pointer to a 64-bit counter variable
> + *
> + * @return Previous value of counter
> + */
> +static inline uint64_t odp_counter_u64_read_inc(odp_counter_u64_t *ptr)
> +{
> +       return __atomic_fetch_add(&ptr->v, 1, __ATOMIC_RELAXED);
> +}
> +
> +/**
> + * Atomic increment (+1) 64-bit counter variable
> + *
> + * @param ptr   Pointer to a 64-bit counter variable
> + */
> +static inline void odp_counter_u64_inc(odp_counter_u64_t *ptr)
> +{
> +       (void)__atomic_add_fetch(&ptr->v, 1, __ATOMIC_RELAXED);
> +}
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif
> diff --git a/platform/linux-generic/include/api/odp_ticketlock.h
> b/platform/linux-generic/include/api/odp_ticketlock.h
> index a3b3ab5..4a84136 100644
> --- a/platform/linux-generic/include/api/odp_ticketlock.h
> +++ b/platform/linux-generic/include/api/odp_ticketlock.h
> @@ -20,7 +20,7 @@ extern "C" {
>
>
>  #include <odp_std_types.h>
> -#include <odp_atomic.h>
> +#include <odp_counter.h>
>
>  /** @addtogroup odp_synchronizers
>   *  @{
> @@ -30,7 +30,7 @@ extern "C" {
>   * ODP ticketlock
>   */
>  typedef struct odp_ticketlock_t {
> -       odp_atomic_u32_t  next_ticket; /**< @private Next ticket */
> +       odp_counter_u32_t next_ticket; /**< @private Next ticket */
>         volatile uint32_t cur_ticket;  /**< @private Current ticket */
>  } odp_ticketlock_t;
>
> diff --git a/platform/linux-generic/include/odp_buffer_internal.h
> b/platform/linux-generic/include/odp_buffer_internal.h
> index 0027bfc..76d005c 100644
> --- a/platform/linux-generic/include/odp_buffer_internal.h
> +++ b/platform/linux-generic/include/odp_buffer_internal.h
> @@ -19,7 +19,7 @@ extern "C" {
>  #endif
>
>  #include <odp_std_types.h>
> -#include <odp_atomic.h>
> +#include <odp_counter.h>
>  #include <odp_buffer_pool.h>
>  #include <odp_buffer.h>
>  #include <odp_debug.h>
> @@ -88,7 +88,7 @@ typedef struct odp_buffer_hdr_t {
>         uint32_t                 index;      /* buf index in the pool */
>         size_t                   size;       /* max data size */
>         size_t                   cur_offset; /* current offset */
> -       odp_atomic_u32_t         ref_count;  /* reference count */
> +       odp_counter_u32_t        ref_count;  /* reference count */
>         odp_buffer_scatter_t     scatter;    /* Scatter/gather list */
>         int                      type;       /* type of next header */
>         odp_buffer_pool_t        pool_hdl;   /* buffer pool handle */
> diff --git a/platform/linux-generic/odp_buffer.c
> b/platform/linux-generic/odp_buffer.c
> index e54e0e7..1d0b4d5 100644
> --- a/platform/linux-generic/odp_buffer.c
> +++ b/platform/linux-generic/odp_buffer.c
> @@ -73,7 +73,8 @@ int odp_buffer_snprint(char *str, size_t n, odp_buffer_t
> buf)
>         len += snprintf(&str[len], n-len,
>                         "  cur_offset   %zu\n",       hdr->cur_offset);
>         len += snprintf(&str[len], n-len,
> -                       "  ref_count    %i\n",        hdr->ref_count);
> +                       "  ref_count    %i\n",
> +                       odp_counter_u32_read(&hdr->ref_count));
>         len += snprintf(&str[len], n-len,
>                         "  type         %i\n",        hdr->type);
>         len += snprintf(&str[len], n-len,
> diff --git a/platform/linux-generic/odp_crypto.c
> b/platform/linux-generic/odp_crypto.c
> index 1475437..f51f4a3 100644
> --- a/platform/linux-generic/odp_crypto.c
> +++ b/platform/linux-generic/odp_crypto.c
> @@ -6,7 +6,7 @@
>
>  #include <odp_crypto.h>
>  #include <odp_internal.h>
> -#include <odp_atomic.h>
> +#include <odp_counter.h>
>  #include <odp_spinlock.h>
>  #include <odp_sync.h>
>  #include <odp_debug.h>
> @@ -26,7 +26,7 @@
>  #define MAX_SESSIONS 32
>
>  typedef struct {
> -       odp_atomic_u32_t next;
> +       odp_counter_u32_t next;
>         uint32_t         max;
>         odp_crypto_generic_session_t sessions[0];
>  } odp_crypto_global_t;
> @@ -58,7 +58,7 @@ odp_crypto_generic_session_t *alloc_session(void)
>         uint32_t idx;
>         odp_crypto_generic_session_t *session = NULL;
>
> -       idx = odp_atomic_fetch_inc_u32(&global->next);
> +       idx = odp_counter_u32_read_inc(&global->next);
>         if (idx < global->max) {
>                 session = &global->sessions[idx];
>                 session->index = idx;
> diff --git a/platform/linux-generic/odp_thread.c
> b/platform/linux-generic/odp_thread.c
> index dcb893d..9620d41 100644
> --- a/platform/linux-generic/odp_thread.c
> +++ b/platform/linux-generic/odp_thread.c
> @@ -11,7 +11,7 @@
>
>  #include <odp_thread.h>
>  #include <odp_internal.h>
> -#include <odp_atomic.h>
> +#include <odp_counter.h>
>  #include <odp_config.h>
>  #include <odp_debug.h>
>  #include <odp_shared_memory.h>
> @@ -31,7 +31,7 @@ typedef struct {
>
>  typedef struct {
>         thread_state_t   thr[ODP_CONFIG_MAX_THREADS];
> -       odp_atomic_u32_t num;
> +       odp_counter_u32_t num;
>
>  } thread_globals_t;
>
> @@ -67,7 +67,7 @@ static int thread_id(void)
>         uint32_t id;
>         int cpu;
>
> -       id = odp_atomic_fetch_inc_u32(&thread_globals->num);
> +       id = odp_counter_u32_read_inc(&thread_globals->num);
>
>         if (id >= ODP_CONFIG_MAX_THREADS) {
>                 ODP_ERR("Too many threads\n");
> diff --git a/platform/linux-generic/odp_ticketlock.c
> b/platform/linux-generic/odp_ticketlock.c
> index be5b885..0e1d880 100644
> --- a/platform/linux-generic/odp_ticketlock.c
> +++ b/platform/linux-generic/odp_ticketlock.c
> @@ -5,14 +5,14 @@
>   */
>
>  #include <odp_ticketlock.h>
> -#include <odp_atomic.h>
> +#include <odp_counter.h>
>  #include <odp_sync.h>
>  #include <odp_spin_internal.h>
>
>
>  void odp_ticketlock_init(odp_ticketlock_t *ticketlock)
>  {
> -       ticketlock->next_ticket = 0;
> +       odp_counter_u32_init(&ticketlock->next_ticket, 0);
>         ticketlock->cur_ticket  = 0;
>         odp_sync_stores();
>  }
> @@ -22,7 +22,7 @@ void odp_ticketlock_lock(odp_ticketlock_t *ticketlock)
>  {
>         uint32_t ticket;
>
> -       ticket = odp_atomic_fetch_inc_u32(&ticketlock->next_ticket);
> +       ticket = odp_counter_u32_read_inc(&ticketlock->next_ticket);
>
>         while (ticket != ticketlock->cur_ticket)
>                 odp_spin();
> @@ -47,5 +47,6 @@ void odp_ticketlock_unlock(odp_ticketlock_t *ticketlock)
>
>  int odp_ticketlock_is_locked(odp_ticketlock_t *ticketlock)
>  {
> -       return ticketlock->cur_ticket != ticketlock->next_ticket;
> +       return ticketlock->cur_ticket !=
> +               odp_counter_u32_read(&ticketlock->next_ticket);
>  }
> diff --git a/test/api_test/Makefile.am b/test/api_test/Makefile.am
> index 5104454..55603e0 100644
> --- a/test/api_test/Makefile.am
> +++ b/test/api_test/Makefile.am
> @@ -1,12 +1,14 @@
>  include $(top_srcdir)/test/Makefile.inc
>
> -bin_PROGRAMS = odp_atomic odp_shm odp_ring odp_timer_ping
> +bin_PROGRAMS = odp_atomic odp_shm odp_ring odp_timer_ping odp_counters
>  odp_atomic_LDFLAGS = $(AM_LDFLAGS) -static
>  odp_shm_LDFLAGS = $(AM_LDFLAGS) -static
>  odp_ring_LDFLAGS = $(AM_LDFLAGS) -static
>  odp_timer_ping_LDFLAGS = $(AM_LDFLAGS) -static
> +odp_counters_LDFLAGS = $(AM_LDFLAGS) -static
>
>  dist_odp_atomic_SOURCES = odp_atomic_test.c odp_common.c
>  dist_odp_shm_SOURCES = odp_shm_test.c odp_common.c
>  dist_odp_ring_SOURCES = odp_ring_test.c odp_common.c
>  dist_odp_timer_ping_SOURCES = odp_timer_ping.c odp_common.c
> +dist_odp_counters_SOURCES = odp_counter_test.c odp_common.c
> diff --git a/test/api_test/odp_counter_test.c
> b/test/api_test/odp_counter_test.c
> new file mode 100644
> index 0000000..abbc3cb
> --- /dev/null
> +++ b/test/api_test/odp_counter_test.c
> @@ -0,0 +1,362 @@
> +/* Copyright (c) 2013, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +#include <string.h>
> +#include <sys/time.h>
> +#include <odp.h>
> +#include <odp_counter.h>
> +#include <odp_debug.h>
> +#include <odp_common.h>
> +#include <odph_linux.h>
> +
> +/**
> + * add_sub_cnt could be any valid value
> + * so to excercise explicit counter_add/sub
> + * ops. For now using 5..
> + */
> +#define ADD_SUB_CNT    5
> +
> +#define        CNT 500000
> +#define        U32_INIT_VAL    (1UL << 10)
> +#define        U64_INIT_VAL    (1ULL << 33)
> +
> +typedef enum {
> +       TEST_MIX = 1, /* Must be first test case num */
> +       TEST_INC_DEC_U32 = 2,
> +       TEST_ADD_SUB_U32 = 3,
> +       TEST_INC_DEC_U64 = 4,
> +       TEST_ADD_SUB_U64 = 5,
> +       TEST_MAX,
> +} odp_test_counter_t;
> +
> +
> +static uint32_t test_counter_inc_dec_u32(void);
> +static uint32_t test_counter_add_sub_u32(void);
> +static uint32_t test_counter_inc_dec_u64(void);
> +static uint32_t test_counter_add_sub_u64(void);
> +static uint32_t test_counter_inc_u32(void);
> +static uint32_t test_counter_dec_u32(void);
> +static uint32_t test_counter_add_u32(void);
> +static uint32_t test_counter_sub_u32(void);
> +static uint32_t test_counter_inc_u64(void);
> +static uint32_t test_counter_dec_u64(void);
> +static uint32_t test_counter_add_u64(void);
> +static uint32_t test_counter_sub_u64(void);
> +static void test_counter_init(void);
> +static uint32_t test_counter_basic(void);
> +static void test_counter_write(void);
> +static int test_counter_validate(void);
> +
> +static odp_counter_u32_t a32u;
> +static odp_counter_u64_t a64u;
> +
> +static odp_barrier_t barrier;
> +
> +static const char * const test_name[] = {
> +       "dummy",
> +       "test shared counter basic ops add/sub/inc/dec",
> +       "test inc/dec of 32-bit shared counter",
> +       "test add/sub of 32-bit shared counter",
> +       "test inc/dec of 64-bit shared counter",
> +       "test add/sub of 64-bit shared counter"
> +};
> +
> +static uint64_t accops[MAX_WORKERS];
> +
> +static void usage(void)
> +{
> +       printf("\n./odp_counter -t <testcase> -n <num of threads>\n\n"
> +              "\t<testcase> is\n"
> +              "\t\t1 - Test mix (inc/dec/add/sub on 32- and 64-bit
> counters)\n"
> +              "\t\t2 - Test inc/dec of 32-bit counter\n"
> +              "\t\t3 - Test add/sub of 32-bit counter\n"
> +              "\t\t4 - Test inc/dec of 64-bit counter\n"
> +              "\t\t5 - Test add/sub of 64-bit counter\n"
> +              "\t<num of thread> is optional\n"
> +              "\t\t<1 - 31> - no of threads to start\n"
> +              "\t\tif user doesn't specify this option, then\n"
> +              "\t\tno of threads created is equivalent to no of cores\n"
> +              "\t\tavailable in the system\n"
> +              "\tExample usage:\n"
> +              "\t\t./odp_counter -t 2\n"
> +              "\t\t./odp_counter -t 3 -n 12\n");
> +}
> +
> +static uint32_t test_counter_inc_u32(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < CNT; i++)
> +               odp_counter_u32_inc(&a32u);
> +       return i;
> +}
> +
> +static uint32_t test_counter_inc_u64(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < CNT; i++)
> +               odp_counter_u64_inc(&a64u);
> +       return i;
> +}
> +
> +static uint32_t test_counter_dec_u32(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < CNT; i++)
> +               odp_counter_u32_add(&a32u, (uint32_t)-1);
> +       return i;
> +}
> +
> +static uint32_t test_counter_dec_u64(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < CNT; i++)
> +               odp_counter_u64_add(&a64u, (uint64_t)-1);
> +       return i;
> +}
> +
> +static uint32_t test_counter_add_u32(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
> +               odp_counter_u32_add(&a32u, ADD_SUB_CNT);
> +       return i;
> +}
> +
> +static uint32_t test_counter_add_u64(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
> +               odp_counter_u64_add(&a64u, ADD_SUB_CNT);
> +       return i;
> +}
> +
> +static uint32_t test_counter_sub_u32(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
> +               odp_counter_u32_add(&a32u, -ADD_SUB_CNT);
> +       return i;
> +}
> +
> +static uint32_t test_counter_sub_u64(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
> +               odp_counter_u64_add(&a64u, -ADD_SUB_CNT);
> +       return i;
> +}
> +
> +static uint32_t test_counter_inc_dec_u32(void)
> +{
> +       uint32_t nops = 0;
> +       nops += test_counter_inc_u32();
> +       nops += test_counter_dec_u32();
> +       return nops;
> +}
> +
> +static uint32_t test_counter_add_sub_u32(void)
> +{
> +       uint32_t nops = 0;
> +       nops += test_counter_add_u32();
> +       nops += test_counter_sub_u32();
> +       return nops;
> +}
> +
> +static uint32_t test_counter_inc_dec_u64(void)
> +{
> +       uint32_t nops = 0;
> +       nops += test_counter_inc_u64();
> +       nops += test_counter_dec_u64();
> +       return nops;
> +}
> +
> +static uint32_t test_counter_add_sub_u64(void)
> +{
> +       uint32_t nops = 0;
> +       nops += test_counter_add_u64();
> +       nops += test_counter_sub_u64();
> +       return nops;
> +}
> +
> +/**
> + * Test basic counter operation like
> + * add/sub/increment/decrement operation.
> + */
> +static uint32_t test_counter_basic(void)
> +{
> +       uint32_t nops = 0;
> +       nops += test_counter_inc_u32();
> +       nops += test_counter_dec_u32();
> +       nops += test_counter_add_u32();
> +       nops += test_counter_sub_u32();
> +
> +       nops += test_counter_inc_u64();
> +       nops += test_counter_dec_u64();
> +       nops += test_counter_add_u64();
> +       nops += test_counter_sub_u64();
> +
> +       return nops;
> +}
> +
> +static void test_counter_init(void)
> +{
> +       odp_counter_u32_init(&a32u, 0);
> +       odp_counter_u64_init(&a64u, 0);
> +}
> +
> +static void test_counter_write(void)
> +{
> +       odp_counter_u32_write(&a32u, U32_INIT_VAL);
> +       odp_counter_u64_write(&a64u, U64_INIT_VAL);
> +}
> +
> +static int test_counter_validate(void)
> +{
> +       if (odp_counter_u32_read(&a32u) != U32_INIT_VAL) {
> +               ODP_ERR("Atomic u32 usual functions failed\n");
> +               return -1;
> +       }
> +
> +       if (odp_counter_u64_read(&a64u) != U64_INIT_VAL) {
> +               ODP_ERR("Atomic u64 usual functions failed\n");
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +static void *run_thread(void *arg)
> +{
> +       pthrd_arg *parg = (pthrd_arg *)arg;
> +       int thr;
> +       uint64_t nops = 0;
> +       struct timeval tv0, tv1;
> +
> +       thr = odp_thread_id();
> +
> +       ODP_DBG("Thread %i starts\n", thr);
> +
> +       /* Wait here until all threads have arrived */
> +       /* Use multiple barriers to verify that it handles wrap around and
> +        * has no race conditions which could be exposed when invoked back-
> +        * to-back */
> +       odp_barrier_sync(&barrier);
> +       odp_barrier_sync(&barrier);
> +       odp_barrier_sync(&barrier);
> +       odp_barrier_sync(&barrier);
> +
> +       gettimeofday(&tv0, NULL);
> +
> +       switch (parg->testcase) {
> +       case TEST_MIX:
> +               nops += test_counter_basic();
> +               break;
> +       case TEST_INC_DEC_U32:
> +               nops += test_counter_inc_dec_u32();
> +               break;
> +       case TEST_ADD_SUB_U32:
> +               nops += test_counter_add_sub_u32();
> +               break;
> +       case TEST_INC_DEC_U64:
> +               nops += test_counter_inc_dec_u64();
> +               break;
> +       case TEST_ADD_SUB_U64:
> +               nops += test_counter_add_sub_u64();
> +               break;
> +       }
> +       gettimeofday(&tv1, NULL);
> +       accops[thr] = nops;
> +       fflush(NULL);
> +
> +       uint64_t usecs = (tv1.tv_sec - tv0.tv_sec) * 1000000ULL +
> +                        tv1.tv_usec - tv0.tv_usec;
> +       printf("Time taken in thread %d to complete %"PRIu64" op is "
> +              "%"PRIu64" usec, %"PRIu64" ns/op\n",
> +              thr, nops, usecs, 1000 * usecs / nops);
> +
> +       return parg;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       pthrd_arg thrdarg;
> +       int test_type = 0, pthrdnum = 0, i = 0, cnt = argc - 1;
> +       char c;
> +       int result;
> +
> +       if (argc == 1 || argc % 2 == 0) {
> +               usage();
> +               goto err_exit;
> +       }
> +       if (odp_test_global_init() != 0)
> +               goto err_exit;
> +       odp_print_system_info();
> +
> +       while (cnt != 0) {
> +               sscanf(argv[++i], "-%c", &c);
> +               switch (c) {
> +               case 't':
> +                       sscanf(argv[++i], "%d", &test_type);
> +                       break;
> +               case 'n':
> +                       sscanf(argv[++i], "%d", &pthrdnum);
> +                       break;
> +               default:
> +                       ODP_ERR("Invalid option %c\n", c);
> +                       usage();
> +                       goto err_exit;
> +               }
> +               if (test_type < TEST_MIX || test_type > TEST_MAX ||
> +                   pthrdnum > odp_sys_core_count()) {
> +                       usage();
> +                       goto err_exit;
> +               }
> +               cnt -= 2;
> +       }
> +       if (pthrdnum == 0)
> +               pthrdnum = odp_sys_core_count();
> +
> +       test_counter_init();
> +       test_counter_write();
> +
> +       memset(&thrdarg, 0, sizeof(pthrd_arg));
> +       thrdarg.testcase = test_type;
> +       thrdarg.numthrds = pthrdnum;
> +
> +       if ((test_type > 0) && (test_type < TEST_MAX)) {
> +               printf("%s\n", test_name[test_type]);
> +       } else {
> +               ODP_ERR("Invalid test case [%d]\n", test_type);
> +               usage();
> +               goto err_exit;
> +       }
> +       odp_barrier_init_count(&barrier, pthrdnum);
> +       odp_test_thread_create(run_thread, &thrdarg);
> +
> +       odp_test_thread_exit(&thrdarg);
> +
> +       result = test_counter_validate();
> +
> +       if (result == 0) {
> +               printf("%s_%d_%d Result:pass\n",
> +                      test_name[test_type], test_type, pthrdnum);
> +       } else {
> +               printf("%s_%d_%d Result:fail\n",
> +                      test_name[test_type], test_type, pthrdnum);
> +       }
> +       return 0;
> +
> +err_exit:
> +       return -1;
> +}
> diff --git a/test/api_test/odp_counter_test.h
> b/test/api_test/odp_counter_test.h
> new file mode 100644
> index 0000000..9991006
> --- /dev/null
> +++ b/test/api_test/odp_counter_test.h
> @@ -0,0 +1,51 @@
> +/* Copyright (c) 2013, Linaro Limited
> + * All rights reserved.
> + *
> + * SPDX-License-Identifier:     BSD-3-Clause
> + */
> +
> +#ifndef ODP_COUNTER_TEST_H_
> +#define ODP_COUNTER_TEST_H_
> +
> +#include <odp.h>
> +#include <odph_linux.h>
> +
> +/**
> + * add_sub_cnt could be any valid value
> + * so to excercise explicit counter_add/sub
> + * ops. For now using 5..
> + */
> +#define ADD_SUB_CNT    5
> +
> +#define        CNT 500000
> +#define        U32_INIT_VAL    (1UL << 10)
> +#define        U64_INIT_VAL    (1ULL << 33)
> +
> +typedef enum {
> +       TEST_MIX = 1, /* Must be first test case num */
> +       TEST_INC_DEC_U32,
> +       TEST_ADD_SUB_U32,
> +       TEST_INC_DEC_64,
> +       TEST_ADD_SUB_64,
> +       TEST_MAX,
> +} odp_test_counter_t;
> +
> +
> +void test_counter_inc_dec_u32(void);
> +void test_counter_add_sub_u32(void);
> +void test_counter_inc_dec_64(void);
> +void test_counter_add_sub_64(void);
> +void test_counter_inc_u32(void);
> +void test_counter_dec_u32(void);
> +void test_counter_add_u32(void);
> +void test_counter_sub_u32(void);
> +void test_counter_inc_64(void);
> +void test_counter_dec_64(void);
> +void test_counter_add_64(void);
> +void test_counter_sub_64(void);
> +void test_counter_init(void);
> +void test_counter_basic(void);
> +void test_counter_store(void);
> +int test_counter_validate(void);
> +
> +#endif /* ODP_COUNTER_TEST_H_ */
> --
> 1.9.1
>
>
> _______________________________________________
> lng-odp mailing list
> lng-odp@lists.linaro.org
> http://lists.linaro.org/mailman/listinfo/lng-odp
>
diff mbox

Patch

diff --git a/.gitignore b/.gitignore
index 57b47ea..9d3d9a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,7 @@  odp_atomic
 odp_shm
 odp_ring
 odp_timer_ping
+odp_counters
 odp_pktio
 odp_timer_test
 odp_generator
diff --git a/example/generator/odp_generator.c b/example/generator/odp_generator.c
index ffa5e62..782b7f0 100644
--- a/example/generator/odp_generator.c
+++ b/example/generator/odp_generator.c
@@ -62,10 +62,10 @@  typedef struct {
  * counters
 */
 static struct {
-	odp_atomic_u64_t seq;	/**< ip seq to be send */
-	odp_atomic_u64_t ip;	/**< ip packets */
-	odp_atomic_u64_t udp;	/**< udp packets */
-	odp_atomic_u64_t icmp;	/**< icmp packets */
+	odp_counter_u64_t seq;	/**< ip seq to be send */
+	odp_counter_u64_t ip;	/**< ip packets */
+	odp_counter_u64_t udp;	/**< udp packets */
+	odp_counter_u64_t icmp;	/**< icmp packets */
 } counters;
 
 /** * Thread specific arguments
@@ -201,7 +201,7 @@  static void pack_udp_pkt(odp_buffer_t obuf)
 	ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_UDPHDR_LEN +
 				       ODPH_IPV4HDR_LEN);
 	ip->proto = ODPH_IPPROTO_UDP;
-	seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xFFFF;
+	seq = odp_counter_u64_read_inc(&counters.seq) % 0xFFFF;
 	ip->id = odp_cpu_to_be_16(seq);
 	ip->chksum = 0;
 	odph_ipv4_csum_update(pkt);
@@ -258,7 +258,7 @@  static void pack_icmp_pkt(odp_buffer_t obuf)
 	ip->tot_len = odp_cpu_to_be_16(args->appl.payload + ODPH_ICMPHDR_LEN +
 				       ODPH_IPV4HDR_LEN);
 	ip->proto = ODPH_IPPROTO_ICMP;
-	seq = odp_atomic_fetch_add_u64(&counters.seq, 1) % 0xffff;
+	seq = odp_counter_u64_read_inc(&counters.seq) % 0xffff;
 	ip->id = odp_cpu_to_be_16(seq);
 	ip->chksum = 0;
 	odph_ipv4_csum_update(pkt);
@@ -335,11 +335,14 @@  static void *gen_send_thread(void *arg)
 
 		if (args->appl.interval != 0) {
 			printf("  [%02i] send pkt no:%ju seq %ju\n",
-			       thr, counters.seq, counters.seq%0xffff);
+			       thr,
+			       odp_counter_u64_read(&counters.seq),
+			       odp_counter_u64_read(&counters.seq)%0xffff);
 			/* TODO use odp timer */
 			usleep(args->appl.interval * 1000);
 		}
-		if (args->appl.number != -1 && counters.seq
+		if (args->appl.number != -1 &&
+		    odp_counter_u64_read(&counters.seq)
 		    >= (unsigned int)args->appl.number) {
 			break;
 		}
@@ -348,7 +351,8 @@  static void *gen_send_thread(void *arg)
 	/* receive number of reply pks until timeout */
 	if (args->appl.mode == APPL_MODE_PING && args->appl.number > 0) {
 		while (args->appl.timeout >= 0) {
-			if (counters.icmp >= (unsigned int)args->appl.number)
+			if (odp_counter_u64_read(&counters.icmp) >=
+			    (unsigned int)args->appl.number)
 				break;
 			/* TODO use odp timer */
 			sleep(1);
@@ -358,10 +362,12 @@  static void *gen_send_thread(void *arg)
 
 	/* print info */
 	if (args->appl.mode == APPL_MODE_UDP) {
-		printf("  [%02i] total send: %ju\n", thr, counters.seq);
+		printf("  [%02i] total send: %ju\n",
+		       thr, odp_counter_u64_read(&counters.seq));
 	} else if (args->appl.mode == APPL_MODE_PING) {
 		printf("  [%02i] total send: %ju total receive: %ju\n",
-		       thr, counters.seq, counters.icmp);
+		       thr, odp_counter_u64_read(&counters.seq),
+		       odp_counter_u64_read(&counters.icmp));
 	}
 	return arg;
 }
@@ -395,7 +401,7 @@  static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len)
 		if (!odp_packet_inflag_ipv4(pkt))
 			continue;
 
-		odp_atomic_inc_u64(&counters.ip);
+		odp_counter_u64_inc(&counters.ip);
 		rlen += sprintf(msg, "receive Packet proto:IP ");
 		buf = odp_buffer_addr(odp_packet_to_buffer(pkt));
 		ip = (odph_ipv4hdr_t *)(buf + odp_packet_l3_offset(pkt));
@@ -405,7 +411,7 @@  static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len)
 
 		/* udp */
 		if (ip->proto == ODPH_IPPROTO_UDP) {
-			odp_atomic_inc_u64(&counters.udp);
+			odp_counter_u64_inc(&counters.udp);
 			udp = (odph_udphdr_t *)(buf + offset);
 			rlen += sprintf(msg + rlen, "UDP payload %d ",
 					odp_be_to_cpu_16(udp->length) -
@@ -417,7 +423,7 @@  static void print_pkts(int thr, odp_packet_t pkt_tbl[], unsigned len)
 			icmp = (odph_icmphdr_t *)(buf + offset);
 			/* echo reply */
 			if (icmp->type == ICMP_ECHOREPLY) {
-				odp_atomic_inc_u64(&counters.icmp);
+				odp_counter_u64_inc(&counters.icmp);
 				memcpy(&tvsend, buf + offset + ODPH_ICMPHDR_LEN,
 				       sizeof(struct timeval));
 				/* TODO This should be changed to use an
@@ -530,10 +536,10 @@  int main(int argc, char *argv[])
 	}
 
 	/* init counters */
-	odp_atomic_init_u64(&counters.seq);
-	odp_atomic_init_u64(&counters.ip);
-	odp_atomic_init_u64(&counters.udp);
-	odp_atomic_init_u64(&counters.icmp);
+	odp_counter_u64_init(&counters.seq, 0);
+	odp_counter_u64_init(&counters.ip, 0);
+	odp_counter_u64_init(&counters.udp, 0);
+	odp_counter_u64_init(&counters.icmp, 0);
 
 	/* Reserve memory for args from shared mem */
 	shm = odp_shm_reserve("shm_args", sizeof(args_t),
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 0153a22..39a035d 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -17,6 +17,7 @@  include_HEADERS = \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_compiler.h \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_config.h \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_coremask.h \
+		  $(top_srcdir)/platform/linux-generic/include/api/odp_counter.h \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_crypto.h \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_debug.h \
 		  $(top_srcdir)/platform/linux-generic/include/api/odp_hints.h \
diff --git a/platform/linux-generic/include/api/odp.h b/platform/linux-generic/include/api/odp.h
index 6e4f69e..9aa05e3 100644
--- a/platform/linux-generic/include/api/odp.h
+++ b/platform/linux-generic/include/api/odp.h
@@ -31,6 +31,7 @@  extern "C" {
 #include <odp_barrier.h>
 #include <odp_spinlock.h>
 #include <odp_atomic.h>
+#include <odp_counter.h>
 #include <odp_init.h>
 #include <odp_system_info.h>
 #include <odp_thread.h>
diff --git a/platform/linux-generic/include/api/odp_counter.h b/platform/linux-generic/include/api/odp_counter.h
new file mode 100644
index 0000000..0ee1ec1
--- /dev/null
+++ b/platform/linux-generic/include/api/odp_counter.h
@@ -0,0 +1,206 @@ 
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+/**
+ * @file odp_counter.h
+ *
+ * ODP atomic counter types and operations, suitable for e.g. shared statistics.
+ * Relaxed memory model assumed for lowest overhead. These types and
+ * operations cannot be used for synchronization!
+ * Scalar variable wrapped in a struct to avoid accessing scalar directly
+ * without using the required access functions.
+ * Counter functions must be used to operate on counter variables!
+ */
+
+#ifndef ODP_COUNTER_H_
+#define ODP_COUNTER_H_
+
+#include <stdint.h>
+#include <odp_align.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * 32-bit (unsigned) atomic counter type
+ */
+typedef struct {
+	uint32_t v; /**< Actual storage for the counter variable */
+} odp_counter_u32_t
+ODP_ALIGNED(sizeof(uint32_t)); /* Enforce alignement! */
+
+/**
+ * 64-bit (unsigned) atomic counter type
+ */
+typedef struct {
+	uint64_t v; /**< Actual storage for the counter variable */
+	/* Room for other data structures (e.g. spin lock) that might be
+	 * needed to ensure atomicity on some architectures */
+} odp_counter_u64_t
+ODP_ALIGNED(sizeof(uint64_t)); /* Enforce alignement! */
+
+/*****************************************************************************
+ * Operations on 32-bit atomic counters
+ * odp_counter_u32_init - returns no value
+ * odp_counter_u32_read - returns current value
+ * odp_counter_u32_write - returns no value
+ * odp_counter_u32_add - returns no value
+ * odp_counter_u32_read_inc - returns old value
+ * odp_counter_u32_inc - returns no value
+ *****************************************************************************/
+
+/**
+ * Initialize 32-bit counter variable
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ * @param val   Initial value
+ */
+static inline void odp_counter_u32_init(odp_counter_u32_t *ptr, uint32_t val)
+{
+	__atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
+}
+
+/**
+ * Read 32-bit counter variable
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ *
+ * @return Value of the variable
+ */
+static inline uint32_t odp_counter_u32_read(const odp_counter_u32_t *ptr)
+{
+	return __atomic_load_n(&ptr->v, __ATOMIC_RELAXED);
+}
+
+/**
+ * Write 32-bit counter variable
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ * @param val   Value to write to the variable
+ */
+static inline void odp_counter_u32_write(odp_counter_u32_t *ptr, uint32_t val)
+{
+	__atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
+}
+
+/**
+ * Atomic add to 32-bit counter variable
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ * @param incr  The value to be added to the counter variable
+ */
+static inline void odp_counter_u32_add(odp_counter_u32_t *ptr, uint32_t incr)
+{
+	(void)__atomic_add_fetch(&ptr->v, incr, __ATOMIC_RELAXED);
+}
+
+/**
+ * Atomic increment (+1) of 32-bit counter variable, return original value
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ *
+ * @return Previous value of counter
+ */
+static inline uint32_t odp_counter_u32_read_inc(odp_counter_u32_t *ptr)
+{
+	return __atomic_fetch_add(&ptr->v, 1, __ATOMIC_RELAXED);
+}
+
+/**
+ * Atomic increment (+1) 32-bit counter variable
+ *
+ * @param ptr   Pointer to a 32-bit counter variable
+ */
+static inline void odp_counter_u32_inc(odp_counter_u32_t *ptr)
+{
+	(void)__atomic_add_fetch(&ptr->v, 1, __ATOMIC_RELAXED);
+}
+
+/*****************************************************************************
+ * Operations on 64-bit atomic counters
+ * odp_counter_u64_init
+ * odp_counter_u64_read
+ * odp_counter_u64_write
+ * odp_counter_u64_add
+ * odp_counter_u64_read_inc
+ * odp_counter_u64_inc
+ *****************************************************************************/
+
+/**
+ * Read 64-bit counter variable
+ *
+ * @param ptr   Pointer to a 64-bit counter variable
+ *
+ * @return Value of the counter variable
+ */
+static inline uint64_t odp_counter_u64_read(const odp_counter_u64_t *ptr)
+{
+	return __atomic_load_n(&ptr->v, __ATOMIC_RELAXED);
+}
+
+/**
+ * Write 64-bit counter variable
+ *
+ * @param ptr  Pointer to a 64-bit counter variable
+ * @param val  Value to write to the counter variable
+ */
+static inline void odp_counter_u64_write(odp_counter_u64_t *ptr, uint64_t val)
+{
+	__atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
+}
+
+/**
+ * Initialize 64-bit counter variable
+ * Perform implementation specific initializations, assign initial value.
+ *
+ * @param ptr   Pointer to a 64-bit counter variable
+ * @param val   Initial value
+ */
+static inline void odp_counter_u64_init(odp_counter_u64_t *ptr, uint64_t val)
+{
+	__atomic_store_n(&ptr->v, val, __ATOMIC_RELAXED);
+}
+
+/**
+ * Atomic add to 64-bit counter variable
+ *
+ * @param ptr   Pointer to a 64-bit counter variable
+ * @param incr  The value to be added to the counter variable
+ */
+static inline void odp_counter_u64_add(odp_counter_u64_t *ptr, uint64_t incr)
+{
+	(void)__atomic_add_fetch(&ptr->v, incr, __ATOMIC_RELAXED);
+}
+
+
+/**
+ * Atomic increment (+1) 64-bit counter variable and return original value
+ *
+ * @param ptr   Pointer to a 64-bit counter variable
+ *
+ * @return Previous value of counter
+ */
+static inline uint64_t odp_counter_u64_read_inc(odp_counter_u64_t *ptr)
+{
+	return __atomic_fetch_add(&ptr->v, 1, __ATOMIC_RELAXED);
+}
+
+/**
+ * Atomic increment (+1) 64-bit counter variable
+ *
+ * @param ptr   Pointer to a 64-bit counter variable
+ */
+static inline void odp_counter_u64_inc(odp_counter_u64_t *ptr)
+{
+	(void)__atomic_add_fetch(&ptr->v, 1, __ATOMIC_RELAXED);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/linux-generic/include/api/odp_ticketlock.h b/platform/linux-generic/include/api/odp_ticketlock.h
index a3b3ab5..4a84136 100644
--- a/platform/linux-generic/include/api/odp_ticketlock.h
+++ b/platform/linux-generic/include/api/odp_ticketlock.h
@@ -20,7 +20,7 @@  extern "C" {
 
 
 #include <odp_std_types.h>
-#include <odp_atomic.h>
+#include <odp_counter.h>
 
 /** @addtogroup odp_synchronizers
  *  @{
@@ -30,7 +30,7 @@  extern "C" {
  * ODP ticketlock
  */
 typedef struct odp_ticketlock_t {
-	odp_atomic_u32_t  next_ticket; /**< @private Next ticket */
+	odp_counter_u32_t next_ticket; /**< @private Next ticket */
 	volatile uint32_t cur_ticket;  /**< @private Current ticket */
 } odp_ticketlock_t;
 
diff --git a/platform/linux-generic/include/odp_buffer_internal.h b/platform/linux-generic/include/odp_buffer_internal.h
index 0027bfc..76d005c 100644
--- a/platform/linux-generic/include/odp_buffer_internal.h
+++ b/platform/linux-generic/include/odp_buffer_internal.h
@@ -19,7 +19,7 @@  extern "C" {
 #endif
 
 #include <odp_std_types.h>
-#include <odp_atomic.h>
+#include <odp_counter.h>
 #include <odp_buffer_pool.h>
 #include <odp_buffer.h>
 #include <odp_debug.h>
@@ -88,7 +88,7 @@  typedef struct odp_buffer_hdr_t {
 	uint32_t                 index;	     /* buf index in the pool */
 	size_t                   size;       /* max data size */
 	size_t                   cur_offset; /* current offset */
-	odp_atomic_u32_t         ref_count;  /* reference count */
+	odp_counter_u32_t        ref_count;  /* reference count */
 	odp_buffer_scatter_t     scatter;    /* Scatter/gather list */
 	int                      type;       /* type of next header */
 	odp_buffer_pool_t        pool_hdl;   /* buffer pool handle */
diff --git a/platform/linux-generic/odp_buffer.c b/platform/linux-generic/odp_buffer.c
index e54e0e7..1d0b4d5 100644
--- a/platform/linux-generic/odp_buffer.c
+++ b/platform/linux-generic/odp_buffer.c
@@ -73,7 +73,8 @@  int odp_buffer_snprint(char *str, size_t n, odp_buffer_t buf)
 	len += snprintf(&str[len], n-len,
 			"  cur_offset   %zu\n",       hdr->cur_offset);
 	len += snprintf(&str[len], n-len,
-			"  ref_count    %i\n",        hdr->ref_count);
+			"  ref_count    %i\n",
+			odp_counter_u32_read(&hdr->ref_count));
 	len += snprintf(&str[len], n-len,
 			"  type         %i\n",        hdr->type);
 	len += snprintf(&str[len], n-len,
diff --git a/platform/linux-generic/odp_crypto.c b/platform/linux-generic/odp_crypto.c
index 1475437..f51f4a3 100644
--- a/platform/linux-generic/odp_crypto.c
+++ b/platform/linux-generic/odp_crypto.c
@@ -6,7 +6,7 @@ 
 
 #include <odp_crypto.h>
 #include <odp_internal.h>
-#include <odp_atomic.h>
+#include <odp_counter.h>
 #include <odp_spinlock.h>
 #include <odp_sync.h>
 #include <odp_debug.h>
@@ -26,7 +26,7 @@ 
 #define MAX_SESSIONS 32
 
 typedef struct {
-	odp_atomic_u32_t next;
+	odp_counter_u32_t next;
 	uint32_t         max;
 	odp_crypto_generic_session_t sessions[0];
 } odp_crypto_global_t;
@@ -58,7 +58,7 @@  odp_crypto_generic_session_t *alloc_session(void)
 	uint32_t idx;
 	odp_crypto_generic_session_t *session = NULL;
 
-	idx = odp_atomic_fetch_inc_u32(&global->next);
+	idx = odp_counter_u32_read_inc(&global->next);
 	if (idx < global->max) {
 		session = &global->sessions[idx];
 		session->index = idx;
diff --git a/platform/linux-generic/odp_thread.c b/platform/linux-generic/odp_thread.c
index dcb893d..9620d41 100644
--- a/platform/linux-generic/odp_thread.c
+++ b/platform/linux-generic/odp_thread.c
@@ -11,7 +11,7 @@ 
 
 #include <odp_thread.h>
 #include <odp_internal.h>
-#include <odp_atomic.h>
+#include <odp_counter.h>
 #include <odp_config.h>
 #include <odp_debug.h>
 #include <odp_shared_memory.h>
@@ -31,7 +31,7 @@  typedef struct {
 
 typedef struct {
 	thread_state_t   thr[ODP_CONFIG_MAX_THREADS];
-	odp_atomic_u32_t num;
+	odp_counter_u32_t num;
 
 } thread_globals_t;
 
@@ -67,7 +67,7 @@  static int thread_id(void)
 	uint32_t id;
 	int cpu;
 
-	id = odp_atomic_fetch_inc_u32(&thread_globals->num);
+	id = odp_counter_u32_read_inc(&thread_globals->num);
 
 	if (id >= ODP_CONFIG_MAX_THREADS) {
 		ODP_ERR("Too many threads\n");
diff --git a/platform/linux-generic/odp_ticketlock.c b/platform/linux-generic/odp_ticketlock.c
index be5b885..0e1d880 100644
--- a/platform/linux-generic/odp_ticketlock.c
+++ b/platform/linux-generic/odp_ticketlock.c
@@ -5,14 +5,14 @@ 
  */
 
 #include <odp_ticketlock.h>
-#include <odp_atomic.h>
+#include <odp_counter.h>
 #include <odp_sync.h>
 #include <odp_spin_internal.h>
 
 
 void odp_ticketlock_init(odp_ticketlock_t *ticketlock)
 {
-	ticketlock->next_ticket = 0;
+	odp_counter_u32_init(&ticketlock->next_ticket, 0);
 	ticketlock->cur_ticket  = 0;
 	odp_sync_stores();
 }
@@ -22,7 +22,7 @@  void odp_ticketlock_lock(odp_ticketlock_t *ticketlock)
 {
 	uint32_t ticket;
 
-	ticket = odp_atomic_fetch_inc_u32(&ticketlock->next_ticket);
+	ticket = odp_counter_u32_read_inc(&ticketlock->next_ticket);
 
 	while (ticket != ticketlock->cur_ticket)
 		odp_spin();
@@ -47,5 +47,6 @@  void odp_ticketlock_unlock(odp_ticketlock_t *ticketlock)
 
 int odp_ticketlock_is_locked(odp_ticketlock_t *ticketlock)
 {
-	return ticketlock->cur_ticket != ticketlock->next_ticket;
+	return ticketlock->cur_ticket !=
+		odp_counter_u32_read(&ticketlock->next_ticket);
 }
diff --git a/test/api_test/Makefile.am b/test/api_test/Makefile.am
index 5104454..55603e0 100644
--- a/test/api_test/Makefile.am
+++ b/test/api_test/Makefile.am
@@ -1,12 +1,14 @@ 
 include $(top_srcdir)/test/Makefile.inc
 
-bin_PROGRAMS = odp_atomic odp_shm odp_ring odp_timer_ping
+bin_PROGRAMS = odp_atomic odp_shm odp_ring odp_timer_ping odp_counters
 odp_atomic_LDFLAGS = $(AM_LDFLAGS) -static
 odp_shm_LDFLAGS = $(AM_LDFLAGS) -static
 odp_ring_LDFLAGS = $(AM_LDFLAGS) -static
 odp_timer_ping_LDFLAGS = $(AM_LDFLAGS) -static
+odp_counters_LDFLAGS = $(AM_LDFLAGS) -static
 
 dist_odp_atomic_SOURCES = odp_atomic_test.c odp_common.c
 dist_odp_shm_SOURCES = odp_shm_test.c odp_common.c
 dist_odp_ring_SOURCES = odp_ring_test.c odp_common.c
 dist_odp_timer_ping_SOURCES = odp_timer_ping.c odp_common.c
+dist_odp_counters_SOURCES = odp_counter_test.c odp_common.c
diff --git a/test/api_test/odp_counter_test.c b/test/api_test/odp_counter_test.c
new file mode 100644
index 0000000..abbc3cb
--- /dev/null
+++ b/test/api_test/odp_counter_test.c
@@ -0,0 +1,362 @@ 
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#include <string.h>
+#include <sys/time.h>
+#include <odp.h>
+#include <odp_counter.h>
+#include <odp_debug.h>
+#include <odp_common.h>
+#include <odph_linux.h>
+
+/**
+ * add_sub_cnt could be any valid value
+ * so to excercise explicit counter_add/sub
+ * ops. For now using 5..
+ */
+#define ADD_SUB_CNT	5
+
+#define	CNT 500000
+#define	U32_INIT_VAL	(1UL << 10)
+#define	U64_INIT_VAL	(1ULL << 33)
+
+typedef enum {
+	TEST_MIX = 1, /* Must be first test case num */
+	TEST_INC_DEC_U32 = 2,
+	TEST_ADD_SUB_U32 = 3,
+	TEST_INC_DEC_U64 = 4,
+	TEST_ADD_SUB_U64 = 5,
+	TEST_MAX,
+} odp_test_counter_t;
+
+
+static uint32_t test_counter_inc_dec_u32(void);
+static uint32_t test_counter_add_sub_u32(void);
+static uint32_t test_counter_inc_dec_u64(void);
+static uint32_t test_counter_add_sub_u64(void);
+static uint32_t test_counter_inc_u32(void);
+static uint32_t test_counter_dec_u32(void);
+static uint32_t test_counter_add_u32(void);
+static uint32_t test_counter_sub_u32(void);
+static uint32_t test_counter_inc_u64(void);
+static uint32_t test_counter_dec_u64(void);
+static uint32_t test_counter_add_u64(void);
+static uint32_t test_counter_sub_u64(void);
+static void test_counter_init(void);
+static uint32_t test_counter_basic(void);
+static void test_counter_write(void);
+static int test_counter_validate(void);
+
+static odp_counter_u32_t a32u;
+static odp_counter_u64_t a64u;
+
+static odp_barrier_t barrier;
+
+static const char * const test_name[] = {
+	"dummy",
+	"test shared counter basic ops add/sub/inc/dec",
+	"test inc/dec of 32-bit shared counter",
+	"test add/sub of 32-bit shared counter",
+	"test inc/dec of 64-bit shared counter",
+	"test add/sub of 64-bit shared counter"
+};
+
+static uint64_t accops[MAX_WORKERS];
+
+static void usage(void)
+{
+	printf("\n./odp_counter -t <testcase> -n <num of threads>\n\n"
+	       "\t<testcase> is\n"
+	       "\t\t1 - Test mix (inc/dec/add/sub on 32- and 64-bit counters)\n"
+	       "\t\t2 - Test inc/dec of 32-bit counter\n"
+	       "\t\t3 - Test add/sub of 32-bit counter\n"
+	       "\t\t4 - Test inc/dec of 64-bit counter\n"
+	       "\t\t5 - Test add/sub of 64-bit counter\n"
+	       "\t<num of thread> is optional\n"
+	       "\t\t<1 - 31> - no of threads to start\n"
+	       "\t\tif user doesn't specify this option, then\n"
+	       "\t\tno of threads created is equivalent to no of cores\n"
+	       "\t\tavailable in the system\n"
+	       "\tExample usage:\n"
+	       "\t\t./odp_counter -t 2\n"
+	       "\t\t./odp_counter -t 3 -n 12\n");
+}
+
+static uint32_t test_counter_inc_u32(void)
+{
+	int i;
+
+	for (i = 0; i < CNT; i++)
+		odp_counter_u32_inc(&a32u);
+	return i;
+}
+
+static uint32_t test_counter_inc_u64(void)
+{
+	int i;
+
+	for (i = 0; i < CNT; i++)
+		odp_counter_u64_inc(&a64u);
+	return i;
+}
+
+static uint32_t test_counter_dec_u32(void)
+{
+	int i;
+
+	for (i = 0; i < CNT; i++)
+		odp_counter_u32_add(&a32u, (uint32_t)-1);
+	return i;
+}
+
+static uint32_t test_counter_dec_u64(void)
+{
+	int i;
+
+	for (i = 0; i < CNT; i++)
+		odp_counter_u64_add(&a64u, (uint64_t)-1);
+	return i;
+}
+
+static uint32_t test_counter_add_u32(void)
+{
+	int i;
+
+	for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
+		odp_counter_u32_add(&a32u, ADD_SUB_CNT);
+	return i;
+}
+
+static uint32_t test_counter_add_u64(void)
+{
+	int i;
+
+	for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
+		odp_counter_u64_add(&a64u, ADD_SUB_CNT);
+	return i;
+}
+
+static uint32_t test_counter_sub_u32(void)
+{
+	int i;
+
+	for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
+		odp_counter_u32_add(&a32u, -ADD_SUB_CNT);
+	return i;
+}
+
+static uint32_t test_counter_sub_u64(void)
+{
+	int i;
+
+	for (i = 0; i < (CNT / ADD_SUB_CNT); i++)
+		odp_counter_u64_add(&a64u, -ADD_SUB_CNT);
+	return i;
+}
+
+static uint32_t test_counter_inc_dec_u32(void)
+{
+	uint32_t nops = 0;
+	nops += test_counter_inc_u32();
+	nops += test_counter_dec_u32();
+	return nops;
+}
+
+static uint32_t test_counter_add_sub_u32(void)
+{
+	uint32_t nops = 0;
+	nops += test_counter_add_u32();
+	nops += test_counter_sub_u32();
+	return nops;
+}
+
+static uint32_t test_counter_inc_dec_u64(void)
+{
+	uint32_t nops = 0;
+	nops += test_counter_inc_u64();
+	nops += test_counter_dec_u64();
+	return nops;
+}
+
+static uint32_t test_counter_add_sub_u64(void)
+{
+	uint32_t nops = 0;
+	nops += test_counter_add_u64();
+	nops += test_counter_sub_u64();
+	return nops;
+}
+
+/**
+ * Test basic counter operation like
+ * add/sub/increment/decrement operation.
+ */
+static uint32_t test_counter_basic(void)
+{
+	uint32_t nops = 0;
+	nops += test_counter_inc_u32();
+	nops += test_counter_dec_u32();
+	nops += test_counter_add_u32();
+	nops += test_counter_sub_u32();
+
+	nops += test_counter_inc_u64();
+	nops += test_counter_dec_u64();
+	nops += test_counter_add_u64();
+	nops += test_counter_sub_u64();
+
+	return nops;
+}
+
+static void test_counter_init(void)
+{
+	odp_counter_u32_init(&a32u, 0);
+	odp_counter_u64_init(&a64u, 0);
+}
+
+static void test_counter_write(void)
+{
+	odp_counter_u32_write(&a32u, U32_INIT_VAL);
+	odp_counter_u64_write(&a64u, U64_INIT_VAL);
+}
+
+static int test_counter_validate(void)
+{
+	if (odp_counter_u32_read(&a32u) != U32_INIT_VAL) {
+		ODP_ERR("Atomic u32 usual functions failed\n");
+		return -1;
+	}
+
+	if (odp_counter_u64_read(&a64u) != U64_INIT_VAL) {
+		ODP_ERR("Atomic u64 usual functions failed\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void *run_thread(void *arg)
+{
+	pthrd_arg *parg = (pthrd_arg *)arg;
+	int thr;
+	uint64_t nops = 0;
+	struct timeval tv0, tv1;
+
+	thr = odp_thread_id();
+
+	ODP_DBG("Thread %i starts\n", thr);
+
+	/* Wait here until all threads have arrived */
+	/* Use multiple barriers to verify that it handles wrap around and
+	 * has no race conditions which could be exposed when invoked back-
+	 * to-back */
+	odp_barrier_sync(&barrier);
+	odp_barrier_sync(&barrier);
+	odp_barrier_sync(&barrier);
+	odp_barrier_sync(&barrier);
+
+	gettimeofday(&tv0, NULL);
+
+	switch (parg->testcase) {
+	case TEST_MIX:
+		nops += test_counter_basic();
+		break;
+	case TEST_INC_DEC_U32:
+		nops += test_counter_inc_dec_u32();
+		break;
+	case TEST_ADD_SUB_U32:
+		nops += test_counter_add_sub_u32();
+		break;
+	case TEST_INC_DEC_U64:
+		nops += test_counter_inc_dec_u64();
+		break;
+	case TEST_ADD_SUB_U64:
+		nops += test_counter_add_sub_u64();
+		break;
+	}
+	gettimeofday(&tv1, NULL);
+	accops[thr] = nops;
+	fflush(NULL);
+
+	uint64_t usecs = (tv1.tv_sec - tv0.tv_sec) * 1000000ULL +
+			 tv1.tv_usec - tv0.tv_usec;
+	printf("Time taken in thread %d to complete %"PRIu64" op is "
+	       "%"PRIu64" usec, %"PRIu64" ns/op\n",
+	       thr, nops, usecs, 1000 * usecs / nops);
+
+	return parg;
+}
+
+int main(int argc, char *argv[])
+{
+	pthrd_arg thrdarg;
+	int test_type = 0, pthrdnum = 0, i = 0, cnt = argc - 1;
+	char c;
+	int result;
+
+	if (argc == 1 || argc % 2 == 0) {
+		usage();
+		goto err_exit;
+	}
+	if (odp_test_global_init() != 0)
+		goto err_exit;
+	odp_print_system_info();
+
+	while (cnt != 0) {
+		sscanf(argv[++i], "-%c", &c);
+		switch (c) {
+		case 't':
+			sscanf(argv[++i], "%d", &test_type);
+			break;
+		case 'n':
+			sscanf(argv[++i], "%d", &pthrdnum);
+			break;
+		default:
+			ODP_ERR("Invalid option %c\n", c);
+			usage();
+			goto err_exit;
+		}
+		if (test_type < TEST_MIX || test_type > TEST_MAX ||
+		    pthrdnum > odp_sys_core_count()) {
+			usage();
+			goto err_exit;
+		}
+		cnt -= 2;
+	}
+	if (pthrdnum == 0)
+		pthrdnum = odp_sys_core_count();
+
+	test_counter_init();
+	test_counter_write();
+
+	memset(&thrdarg, 0, sizeof(pthrd_arg));
+	thrdarg.testcase = test_type;
+	thrdarg.numthrds = pthrdnum;
+
+	if ((test_type > 0) && (test_type < TEST_MAX)) {
+		printf("%s\n", test_name[test_type]);
+	} else {
+		ODP_ERR("Invalid test case [%d]\n", test_type);
+		usage();
+		goto err_exit;
+	}
+	odp_barrier_init_count(&barrier, pthrdnum);
+	odp_test_thread_create(run_thread, &thrdarg);
+
+	odp_test_thread_exit(&thrdarg);
+
+	result = test_counter_validate();
+
+	if (result == 0) {
+		printf("%s_%d_%d Result:pass\n",
+		       test_name[test_type], test_type, pthrdnum);
+	} else {
+		printf("%s_%d_%d Result:fail\n",
+		       test_name[test_type], test_type, pthrdnum);
+	}
+	return 0;
+
+err_exit:
+	return -1;
+}
diff --git a/test/api_test/odp_counter_test.h b/test/api_test/odp_counter_test.h
new file mode 100644
index 0000000..9991006
--- /dev/null
+++ b/test/api_test/odp_counter_test.h
@@ -0,0 +1,51 @@ 
+/* Copyright (c) 2013, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ */
+
+#ifndef ODP_COUNTER_TEST_H_
+#define ODP_COUNTER_TEST_H_
+
+#include <odp.h>
+#include <odph_linux.h>
+
+/**
+ * add_sub_cnt could be any valid value
+ * so to excercise explicit counter_add/sub
+ * ops. For now using 5..
+ */
+#define ADD_SUB_CNT	5
+
+#define	CNT 500000
+#define	U32_INIT_VAL	(1UL << 10)
+#define	U64_INIT_VAL	(1ULL << 33)
+
+typedef enum {
+	TEST_MIX = 1, /* Must be first test case num */
+	TEST_INC_DEC_U32,
+	TEST_ADD_SUB_U32,
+	TEST_INC_DEC_64,
+	TEST_ADD_SUB_64,
+	TEST_MAX,
+} odp_test_counter_t;
+
+
+void test_counter_inc_dec_u32(void);
+void test_counter_add_sub_u32(void);
+void test_counter_inc_dec_64(void);
+void test_counter_add_sub_64(void);
+void test_counter_inc_u32(void);
+void test_counter_dec_u32(void);
+void test_counter_add_u32(void);
+void test_counter_sub_u32(void);
+void test_counter_inc_64(void);
+void test_counter_dec_64(void);
+void test_counter_add_64(void);
+void test_counter_sub_64(void);
+void test_counter_init(void);
+void test_counter_basic(void);
+void test_counter_store(void);
+int test_counter_validate(void);
+
+#endif /* ODP_COUNTER_TEST_H_ */