[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openvswitch-dev
Subject:    [ovs-dev] [PATCH v2 5/7] tests/test-atomic: Cover more of the atomic API.
From:       jrajahalme () nicira ! com (Jarno Rajahalme)
Date:       2014-07-31 16:17:24
Message-ID: 1406823446-35198-6-git-send-email-jrajahalme () nicira ! com
[Download RAW message or body]

This adds tests using all of the defined memory orders, as well as
simple two-thread test cases for the acquire-release and
consume-release patterns.

These new tests helped uncover a bug in the ovs-atomic-gcc4+
implementation, which was fixed in a preceding patch.

Signed-off-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
v2: Split the test function to smaller functions to make compilation
    easier.  GCC used to give a note and clang actually choke on the
    big test_atomic_main function.

 tests/test-atomic.c |  291 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 290 insertions(+), 1 deletion(-)

diff --git a/tests/test-atomic.c b/tests/test-atomic.c
index 24456d8..ca293ba 100644
--- a/tests/test-atomic.c
+++ b/tests/test-atomic.c
@@ -19,6 +19,7 @@
 #include "ovs-atomic.h"
 #include "util.h"
 #include "ovstest.h"
+#include "ovs-thread.h"
 
 #define TEST_ATOMIC_TYPE(ATOMIC_TYPE, BASE_TYPE)        \
     {                                                   \
@@ -62,6 +63,100 @@
         ovs_assert(value == 8);                         \
     }
 
+#define TEST_ATOMIC_TYPE_EXPLICIT(ATOMIC_TYPE, BASE_TYPE,               \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW)   \
+    {                                                                   \
+        ATOMIC_TYPE x = ATOMIC_VAR_INIT(1);                             \
+        BASE_TYPE value, orig;                                          \
+                                                                        \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 1);                                         \
+                                                                        \
+        atomic_store_explicit(&x, 2, ORDER_STORE);                      \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 2);                                         \
+                                                                        \
+        atomic_init(&x, 3);                                             \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 3);                                         \
+                                                                        \
+        atomic_add_explicit(&x, 1, &orig, ORDER_RMW);                   \
+        ovs_assert(orig == 3);                                          \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 4);                                         \
+                                                                        \
+        atomic_sub_explicit(&x, 2, &orig, ORDER_RMW);                   \
+        ovs_assert(orig == 4);                                          \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 2);                                         \
+                                                                        \
+        atomic_or_explicit(&x, 6, &orig, ORDER_RMW);                    \
+        ovs_assert(orig == 2);                                          \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 6);                                         \
+                                                                        \
+        atomic_and_explicit(&x, 10, &orig, ORDER_RMW);                  \
+        ovs_assert(orig == 6);                                          \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 2);                                         \
+                                                                        \
+        atomic_xor_explicit(&x, 10, &orig, ORDER_RMW);                  \
+        ovs_assert(orig == 2);                                          \
+        atomic_read_explicit(&x, &value, ORDER_READ);                   \
+        ovs_assert(value == 8);                                         \
+    }
+
+
+#define TEST_ATOMIC_ORDER(ORDER_READ, ORDER_STORE, ORDER_RMW)           \
+    {                                                                   \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_char, char,                    \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uchar, unsigned char,          \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_schar, signed char,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_short, short,                  \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_ushort, unsigned short,        \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_int, int,                      \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint, unsigned int,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_long, long int,                \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_ulong, unsigned long int,      \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_llong, long long int,          \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_ullong, unsigned long long int, \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_size_t, size_t,                \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_ptrdiff_t, ptrdiff_t,          \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_intmax_t, intmax_t,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintmax_t, uintmax_t,          \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_intptr_t, intptr_t,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uintptr_t, uintptr_t,          \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint8_t, uint8_t,              \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_int8_t, int8_t,                \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint16_t, uint16_t,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_int16_t, int16_t,              \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_uint32_t, uint32_t,            \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+        TEST_ATOMIC_TYPE_EXPLICIT(atomic_int32_t, int32_t,              \
+                                  ORDER_READ, ORDER_STORE, ORDER_RMW);  \
+    }
+
 static void
 test_atomic_flag(void)
 {
@@ -72,9 +167,154 @@ test_atomic_flag(void)
     ovs_assert(atomic_flag_test_and_set(&flag) == false);
 }
 
+uint32_t a;
+
+struct atomic_aux {
+    atomic_uint32_t count;
+    uint32_t b;
+    ATOMIC(uint32_t *) data;
+};
+
+ATOMIC(struct atomic_aux *) paux = ATOMIC_VAR_INIT(NULL);
+static struct atomic_aux *auxes = NULL;
+
+#define ATOMIC_ITEM_COUNT 1000000
+
+static void *
+atomic_consumer(void * arg1 OVS_UNUSED)
+{
+    struct atomic_aux *old_aux = NULL;
+    uint32_t count;
+
+    do {
+        struct atomic_aux *aux;
+        uint32_t b;
+
+        /* Wait for a new item.  We may not be fast enough to process every
+         * item, but we are guaranteed to see the last one. */
+        do {
+            atomic_read_explicit(&paux, &aux, memory_order_consume);
+        } while (aux == old_aux);
+
+        b = aux->b;
+        atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
+        ovs_assert(b == count + 42);
+
+        old_aux = aux;
+    } while (count < ATOMIC_ITEM_COUNT - 1);
+
+    return NULL;
+}
+
+static void *
+atomic_producer(void * arg1 OVS_UNUSED)
+{
+    size_t i;
+
+    for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
+        struct atomic_aux *aux = &auxes[i];
+
+        aux->count = ATOMIC_VAR_INIT(i);
+        aux->b = i + 42;
+
+        /* Publish the new item. */
+        atomic_store_explicit(&paux, aux, memory_order_release);
+    }
+
+    return NULL;
+}
 
 static void
-test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+test_cons_rel(void)
+{
+    pthread_t reader, writer;
+
+    atomic_init(&paux, NULL);
+
+    auxes = xmalloc(sizeof *auxes * ATOMIC_ITEM_COUNT);
+
+    reader = ovs_thread_create("consumer", atomic_consumer, NULL);
+    writer = ovs_thread_create("producer", atomic_producer, NULL);
+
+    xpthread_join(reader, NULL);
+    xpthread_join(writer, NULL);
+
+    free(auxes);
+}
+
+static void *
+atomic_reader(void *aux_)
+{
+    struct atomic_aux *aux = aux_;
+    uint32_t count;
+    uint32_t *data;
+
+    do {
+        /* Non-synchronized add. */
+        atomic_add_explicit(&aux->count, 1, &count, memory_order_relaxed);
+
+        do {
+            atomic_read_explicit(&aux->data, &data, memory_order_acquire);
+        } while (!data);
+
+        ovs_assert(*data == a && *data == aux->b && a == aux->b);
+
+        atomic_read_explicit(&aux->count, &count, memory_order_relaxed);
+
+        ovs_assert(count == 2 * a && count == 2 * aux->b && count == 2 * *data);
+
+        atomic_store_explicit(&aux->data, NULL, memory_order_release);
+    } while (count < 2 * ATOMIC_ITEM_COUNT);
+
+    return NULL;
+}
+
+static void *
+atomic_writer(void *aux_)
+{
+    struct atomic_aux *aux = aux_;
+    atomic_uint32_t old_count;
+    uint32_t *data;
+    size_t i;
+
+    for (i = 0; i < ATOMIC_ITEM_COUNT; i++) {
+        /* Wait for the reader to be done with the data. */
+        do {
+            atomic_read_explicit(&aux->data, &data, memory_order_acquire);
+        } while (data);
+
+        a = i + 1;
+        atomic_add_explicit(&aux->count, 1, &old_count, memory_order_relaxed);
+        aux->b++;
+        atomic_store_explicit(&aux->data,
+                              (i & 1) ? &aux->b : &a, memory_order_release);
+    }
+
+    return NULL;
+}
+
+static void
+test_acq_rel(void)
+{
+    pthread_t reader, writer;
+    struct atomic_aux *aux = xmalloc(sizeof *aux);
+
+    a = 0;
+    aux->b = 0;
+
+    aux->count = ATOMIC_VAR_INIT(0);
+    atomic_init(&aux->data, NULL);
+
+    reader = ovs_thread_create("reader", atomic_reader, aux);
+    writer = ovs_thread_create("writer", atomic_writer, aux);
+
+    xpthread_join(reader, NULL);
+    xpthread_join(writer, NULL);
+    free(aux);
+}
+
+static void
+test_atomic_plain(void)
 {
     TEST_ATOMIC_TYPE(atomic_char, char);
     TEST_ATOMIC_TYPE(atomic_uchar, unsigned char);
@@ -99,8 +339,57 @@ test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
     TEST_ATOMIC_TYPE(atomic_int16_t, int16_t);
     TEST_ATOMIC_TYPE(atomic_uint32_t, uint32_t);
     TEST_ATOMIC_TYPE(atomic_int32_t, int32_t);
+}
+
+static void
+test_atomic_relaxed(void)
+{
+    TEST_ATOMIC_ORDER(memory_order_relaxed, memory_order_relaxed,
+                      memory_order_relaxed);
+}
+
+static void
+test_atomic_consume(void)
+{
+    TEST_ATOMIC_ORDER(memory_order_consume, memory_order_release,
+                      memory_order_release);
+}
+
+static void
+test_atomic_acquire(void)
+{
+    TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
+                      memory_order_release);
+}
+
+static void
+test_atomic_acq_rel(void)
+{
+    TEST_ATOMIC_ORDER(memory_order_acquire, memory_order_release,
+                      memory_order_acq_rel);
+}
+
+static void
+test_atomic_seq_cst(void)
+{
+    TEST_ATOMIC_ORDER(memory_order_seq_cst, memory_order_seq_cst,
+                      memory_order_seq_cst);
+}
+
+static void
+test_atomic_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    test_atomic_plain();
+    test_atomic_relaxed();
+    test_atomic_consume();
+    test_atomic_acquire();
+    test_atomic_acq_rel();
+    test_atomic_seq_cst();
 
     test_atomic_flag();
+
+    test_acq_rel();
+    test_cons_rel();
 }
 
 OVSTEST_REGISTER("test-atomic", test_atomic_main);
-- 
1.7.10.4


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic