summaryrefslogtreecommitdiffstats
path: root/testsuites/smptests/smpatomic01/init.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-06-01 09:50:44 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-06-01 09:53:43 +0200
commita9cc6a84c50c7745155192ca8fda2ba36e43dd69 (patch)
treeff464e2f53f67c8b1a14703a2cd0c9d7fb7aea72 /testsuites/smptests/smpatomic01/init.c
parentarm/raspberrypi: add fbcons support for rpi bsp (diff)
downloadrtems-a9cc6a84c50c7745155192ca8fda2ba36e43dd69.tar.bz2
smptests/smpatomic01: New test cases
Demonstrate that a read-modify-write atomic operation may be necessary on some archtitectures to observe the latest value written.
Diffstat (limited to 'testsuites/smptests/smpatomic01/init.c')
-rw-r--r--testsuites/smptests/smpatomic01/init.c175
1 files changed, 173 insertions, 2 deletions
diff --git a/testsuites/smptests/smpatomic01/init.c b/testsuites/smptests/smpatomic01/init.c
index 5d0f665cca..673ff28d74 100644
--- a/testsuites/smptests/smpatomic01/init.c
+++ b/testsuites/smptests/smpatomic01/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2015 embedded brains GmbH. All rights reserved.
+ * Copyright (c) 2013, 2016 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
@@ -19,7 +19,9 @@
#endif
#include <rtems/score/atomic.h>
+#include <rtems/score/smpbarrier.h>
#include <rtems.h>
+#include <rtems/bsd.h>
#include <rtems/test.h>
#include <limits.h>
#include <string.h>
@@ -28,6 +30,8 @@
const char rtems_test_name[] = "SMPATOMIC 1";
+#define MS_PER_TICK 10
+
#define MASTER_PRIORITY 1
#define WORKER_PRIORITY 2
@@ -42,6 +46,14 @@ typedef struct {
char unused_space_for_cache_line_separation[128];
unsigned long second_value;
Atomic_Flag global_flag;
+ SMP_barrier_Control barrier;
+ SMP_barrier_State barrier_state[CPU_COUNT];
+ sbintime_t load_trigger_time;
+ sbintime_t load_change_time[CPU_COUNT];
+ int load_count[CPU_COUNT];
+ sbintime_t rmw_trigger_time;
+ sbintime_t rmw_change_time[CPU_COUNT];
+ int rmw_count[CPU_COUNT];
} smpatomic01_context;
static smpatomic01_context test_instance;
@@ -410,6 +422,159 @@ static void test_atomic_fence_fini(
);
}
+static rtems_interval test_atomic_store_load_rmw_init(
+ rtems_test_parallel_context *base,
+ void *arg,
+ size_t active_workers
+)
+{
+ smpatomic01_context *ctx = (smpatomic01_context *) base;
+ size_t i;
+
+ _Atomic_Init_ulong(&ctx->atomic_value, 0);
+
+ _SMP_barrier_Control_initialize(&ctx->barrier);
+
+ for (i = 0; i < active_workers; ++i) {
+ _SMP_barrier_State_initialize(&ctx->barrier_state[i]);
+ }
+
+ return 0;
+}
+
+static sbintime_t now(void)
+{
+ struct bintime bt;
+
+ rtems_bsd_binuptime(&bt);
+ return bttosbt(bt);
+}
+
+static void test_atomic_store_load_rmw_body(
+ rtems_test_parallel_context *base,
+ void *arg,
+ size_t active_workers,
+ size_t worker_index
+)
+{
+ smpatomic01_context *ctx = (smpatomic01_context *) base;
+ uint32_t cpu_self_index;
+ sbintime_t t;
+ int counter;
+
+ if (rtems_test_parallel_is_master_worker(worker_index)) {
+ rtems_status_code sc;
+
+ sc = rtems_task_wake_after(1);
+ rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+ t = now();
+ t += (MS_PER_TICK / 2) * SBT_1MS;
+ ctx->load_trigger_time = t;
+ t += MS_PER_TICK * SBT_1MS;
+ ctx->rmw_trigger_time = t;
+ }
+
+ _Atomic_Fence(ATOMIC_ORDER_SEQ_CST);
+
+ _SMP_barrier_Wait(
+ &ctx->barrier,
+ &ctx->barrier_state[worker_index],
+ active_workers
+ );
+
+ /*
+ * Use the physical processor index, to observe timing differences introduced
+ * by the system topology.
+ */
+ cpu_self_index = rtems_get_current_processor();
+
+ /* Store release and load acquire test case */
+
+ counter = 0;
+ t = ctx->load_trigger_time;
+
+ while (now() < t) {
+ /* Wait */
+ }
+
+ if (cpu_self_index == 0) {
+ _Atomic_Store_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELEASE);
+ } else {
+ while (_Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_ACQUIRE) == 0) {
+ ++counter;
+ }
+ }
+
+ ctx->load_change_time[cpu_self_index] = now();
+ ctx->load_count[cpu_self_index] = counter;
+
+ /* Read-modify-write test case */
+
+ if (cpu_self_index == 0) {
+ _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELAXED);
+ }
+
+ counter = 0;
+ t = ctx->rmw_trigger_time;
+
+ while (now() < t) {
+ /* Wait */
+ }
+
+ if (cpu_self_index == 0) {
+ _Atomic_Store_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
+ } else {
+ while (
+ (_Atomic_Fetch_or_ulong(&ctx->atomic_value, 2, ATOMIC_ORDER_RELAXED) & 1)
+ == 0
+ ) {
+ ++counter;
+ }
+ }
+
+ ctx->rmw_change_time[cpu_self_index] = now();
+ ctx->rmw_count[cpu_self_index] = counter;
+}
+
+static void test_atomic_store_load_rmw_fini(
+ rtems_test_parallel_context *base,
+ void *arg,
+ size_t active_workers
+)
+{
+ smpatomic01_context *ctx = (smpatomic01_context *) base;
+ size_t i;
+ struct bintime bt;
+ struct timespec ts;
+
+ printf("=== atomic store release and load acquire test case ===\n");
+
+ for (i = 0; i < active_workers; ++i) {
+ bt = sbttobt(ctx->load_change_time[i] - ctx->load_trigger_time);
+ bintime2timespec(&bt, &ts);
+ printf(
+ "processor %zu delta %lins, load count %i\n",
+ i,
+ ts.tv_nsec,
+ ctx->load_count[i]
+ );
+ }
+
+ printf("=== atomic read-modify-write test case ===\n");
+
+ for (i = 0; i < active_workers; ++i) {
+ bt = sbttobt(ctx->rmw_change_time[i] - ctx->rmw_trigger_time);
+ bintime2timespec(&bt, &ts);
+ printf(
+ "processor %zu delta %lins, read-modify-write count %i\n",
+ i,
+ ts.tv_nsec,
+ ctx->rmw_count[i]
+ );
+ }
+}
+
static const rtems_test_parallel_job test_jobs[] = {
{
.init = test_atomic_add_init,
@@ -435,7 +600,11 @@ static const rtems_test_parallel_job test_jobs[] = {
.init = test_atomic_fence_init,
.body = test_atomic_fence_body,
.fini = test_atomic_fence_fini
- },
+ }, {
+ .init = test_atomic_store_load_rmw_init,
+ .body = test_atomic_store_load_rmw_body,
+ .fini = test_atomic_store_load_rmw_fini
+ }
};
static void setup_worker(
@@ -471,6 +640,8 @@ static void Init(rtems_task_argument arg)
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_MICROSECONDS_PER_TICK (MS_PER_TICK * 1000)
+
#define CONFIGURE_SMP_APPLICATION
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT