Message ID | 1415564069-11554-1-git-send-email-ola.liljedahl@linaro.org |
---|---|
State | New |
Headers | show |
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 --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_ */
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