source: rtems/testsuites/smptests/smpatomic08/init.c @ 382f714

4.115
Last change on this file since 382f714 was 4a8c334, checked in by Sebastian Huber <sebastian.huber@…>, on 09/03/13 at 09:06:46

smptests/smpatomic08: Add initialization test case

  • Property mode set to 100644
File size: 10.6 KB
Line 
1/*
2 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.com/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/score/atomic.h>
20#include <rtems.h>
21#include <string.h>
22
23#include "tmacros.h"
24
25/* FIXME: Add barrier to Score */
26
27typedef struct {
28        Atomic_Ulong value;
29        Atomic_Ulong sense;
30} SMP_barrier_Control;
31
32typedef struct {
33        unsigned long sense;
34} SMP_barrier_State;
35
36#define SMP_BARRIER_CONTROL_INITIALIZER \
37  { ATOMIC_INITIALIZER_ULONG( 0 ), ATOMIC_INITIALIZER_ULONG( 0 ) }
38
39#define SMP_BARRIER_STATE_INITIALIZER { 0 }
40
41static void _SMP_barrier_Wait(
42  SMP_barrier_Control *control,
43  SMP_barrier_State *state,
44  unsigned long count
45)
46{
47  unsigned long sense = ~state->sense;
48  unsigned long previous_value;
49
50  state->sense = sense;
51
52  previous_value = _Atomic_Fetch_add_ulong(
53    &control->value,
54    1,
55    ATOMIC_ORDER_RELAXED
56  );
57
58  if ( previous_value + 1 == count ) {
59    _Atomic_Store_ulong( &control->value, 0, ATOMIC_ORDER_RELAXED );
60    _Atomic_Store_ulong( &control->sense, sense, ATOMIC_ORDER_RELEASE );
61  } else {
62    while (
63      _Atomic_Load_ulong( &control->sense, ATOMIC_ORDER_ACQUIRE ) != sense
64    ) {
65      /* Wait */
66    }
67  }
68}
69
70#define MASTER_PRIORITY 1
71
72#define WORKER_PRIORITY 2
73
74#define CPU_COUNT 32
75
76typedef struct {
77  Atomic_Ulong stop;
78  SMP_barrier_Control barrier;
79  size_t worker_count;
80  rtems_id stop_worker_timer_id;
81  Atomic_Ulong atomic_value;
82  unsigned long per_worker_value[CPU_COUNT];
83  unsigned long normal_value;
84  Atomic_Flag global_flag;
85} test_context;
86
87typedef struct {
88  void (*init)(test_context *ctx);
89  void (*body)(test_context *ctx, size_t worker_index);
90  void (*fini)(test_context *ctx);
91} test_case;
92
93static test_context test_instance = {
94  .stop = ATOMIC_INITIALIZER_ULONG(0),
95  .barrier = SMP_BARRIER_CONTROL_INITIALIZER
96};
97
98static bool stop(test_context *ctx)
99{
100  return _Atomic_Load_ulong(&ctx->stop, ATOMIC_ORDER_RELAXED) != 0;
101}
102
103static bool is_master_worker(size_t worker_index)
104{
105  return worker_index == 0;
106}
107
108static void test_fini(
109  test_context *ctx,
110  const char *test,
111  bool atomic
112)
113{
114  unsigned long expected_value = 0;
115  unsigned long actual_value;
116  size_t worker_index;
117
118  printf("=== atomic %s test case ==\n", test);
119
120  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
121    unsigned long worker_value = ctx->per_worker_value[worker_index];
122
123    expected_value += worker_value;
124
125    printf(
126      "worker %zu value: %lu\n",
127      worker_index,
128      worker_value
129    );
130  }
131
132  if (atomic) {
133    actual_value = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
134  } else {
135    actual_value = ctx->normal_value;
136  }
137
138  printf(
139    "atomic value: expected = %lu, actual = %lu\n",
140    expected_value,
141    actual_value
142  );
143
144  rtems_test_assert(expected_value == actual_value);
145}
146
147static void test_atomic_add_init(test_context *ctx)
148{
149  _Atomic_Init_ulong(&ctx->atomic_value, 0);
150}
151
152static void test_atomic_add_body(test_context *ctx, size_t worker_index)
153{
154  unsigned long counter = 0;
155
156  while (!stop(ctx)) {
157    ++counter;
158    _Atomic_Fetch_add_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
159  }
160
161  ctx->per_worker_value[worker_index] = counter;
162}
163
164static void test_atomic_add_fini(test_context *ctx)
165{
166  test_fini(ctx, "add", true);
167}
168
169static void test_atomic_flag_init(test_context *ctx)
170{
171  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
172  ctx->normal_value = 0;
173}
174
175static void test_atomic_flag_body(test_context *ctx, size_t worker_index)
176{
177  unsigned long counter = 0;
178
179  while (!stop(ctx)) {
180    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
181      /* Wait */
182    }
183
184    ++counter;
185    ++ctx->normal_value;
186
187    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
188  }
189
190  ctx->per_worker_value[worker_index] = counter;
191}
192
193static void test_atomic_flag_fini(test_context *ctx)
194{
195  test_fini(ctx, "flag", false);
196}
197
198static void test_atomic_sub_init(test_context *ctx)
199{
200  _Atomic_Init_ulong(&ctx->atomic_value, 0);
201}
202
203static void test_atomic_sub_body(test_context *ctx, size_t worker_index)
204{
205  unsigned long counter = 0;
206
207  while (!stop(ctx)) {
208    --counter;
209    _Atomic_Fetch_sub_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
210  }
211
212  ctx->per_worker_value[worker_index] = counter;
213}
214
215static void test_atomic_sub_fini(test_context *ctx)
216{
217  test_fini(ctx, "sub", true);
218}
219
220static void test_atomic_compare_exchange_init(test_context *ctx)
221{
222  _Atomic_Init_ulong(&ctx->atomic_value, 0);
223  ctx->normal_value = 0;
224}
225
226static void test_atomic_compare_exchange_body(test_context *ctx, size_t worker_index)
227{
228  unsigned long counter = 0;
229
230  while (!stop(ctx)) {
231    bool success;
232
233    do {
234      unsigned long zero = 0;
235
236      success = _Atomic_Compare_exchange_ulong(
237        &ctx->atomic_value,
238        &zero,
239        1,
240        ATOMIC_ORDER_ACQUIRE,
241        ATOMIC_ORDER_RELAXED
242      );
243    } while (!success);
244
245    ++counter;
246    ++ctx->normal_value;
247
248    _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
249  }
250
251  ctx->per_worker_value[worker_index] = counter;
252}
253
254static void test_atomic_compare_exchange_fini(test_context *ctx)
255{
256  test_fini(ctx, "compare exchange", false);
257}
258
259static void test_atomic_or_and_init(test_context *ctx)
260{
261  _Atomic_Init_ulong(&ctx->atomic_value, 0);
262}
263
264static void test_atomic_or_and_body(test_context *ctx, size_t worker_index)
265{
266  unsigned long the_bit = 1UL << worker_index;
267  unsigned long current_bit = 0;
268
269  while (!stop(ctx)) {
270    unsigned long previous;
271
272    if (current_bit != 0) {
273      previous = _Atomic_Fetch_and_ulong(
274        &ctx->atomic_value,
275        ~the_bit,
276        ATOMIC_ORDER_RELAXED
277      );
278      current_bit = 0;
279    } else {
280      previous = _Atomic_Fetch_or_ulong(
281        &ctx->atomic_value,
282        the_bit,
283        ATOMIC_ORDER_RELAXED
284      );
285      current_bit = the_bit;
286    }
287
288    rtems_test_assert((previous & the_bit) != current_bit);
289  }
290
291  ctx->per_worker_value[worker_index] = current_bit;
292}
293
294static void test_atomic_or_and_fini(test_context *ctx)
295{
296  test_fini(ctx, "or/and", true);
297}
298
299static const test_case test_cases[] = {
300  {
301    test_atomic_add_init,
302    test_atomic_add_body,
303    test_atomic_add_fini
304  }, {
305    test_atomic_flag_init,
306    test_atomic_flag_body,
307    test_atomic_flag_fini
308  }, {
309    test_atomic_sub_init,
310    test_atomic_sub_body,
311    test_atomic_sub_fini
312  }, {
313    test_atomic_compare_exchange_init,
314    test_atomic_compare_exchange_body,
315    test_atomic_compare_exchange_fini
316  }, {
317    test_atomic_or_and_init,
318    test_atomic_or_and_body,
319    test_atomic_or_and_fini
320  },
321};
322
323#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
324
325static void stop_worker_timer(rtems_id timer_id, void *arg)
326{
327  test_context *ctx = arg;
328
329  _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
330}
331
332static void start_worker_stop_timer(test_context *ctx)
333{
334  rtems_status_code sc;
335
336  _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
337
338  sc = rtems_timer_fire_after(
339    ctx->stop_worker_timer_id,
340    rtems_clock_get_ticks_per_second(),
341    stop_worker_timer,
342    ctx
343  );
344  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
345}
346
347static void run_tests(test_context *ctx, size_t worker_index)
348{
349  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
350  size_t test;
351
352  for (test = 0; test < TEST_COUNT; ++test) {
353    const test_case *tc = &test_cases[test];
354
355    if (is_master_worker(worker_index)) {
356      start_worker_stop_timer(ctx);
357      (*tc->init)(ctx);
358    }
359
360    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
361
362    (*tc->body)(ctx, worker_index);
363
364    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
365
366    if (is_master_worker(worker_index)) {
367      (*tc->fini)(ctx);
368    }
369  }
370}
371
372static void worker_task(size_t worker_index)
373{
374  test_context *ctx = &test_instance;
375
376  run_tests(ctx, worker_index);
377
378  (void) rtems_task_suspend(RTEMS_SELF);
379  rtems_test_assert(0);
380}
381
382static void test_static_and_dynamic_initialization(void)
383{
384  static Atomic_Ulong static_ulong =
385    ATOMIC_INITIALIZER_ULONG(0xdeadbeefUL);
386  static Atomic_Pointer static_ptr =
387    ATOMIC_INITIALIZER_PTR(&static_ptr);
388  static Atomic_Flag static_flag = ATOMIC_INITIALIZER_FLAG;
389
390  Atomic_Ulong stack_ulong;
391  Atomic_Pointer stack_ptr;
392  Atomic_Flag stack_flag;
393
394  puts("=== static and dynamic initialization test case ===");
395
396  _Atomic_Init_ulong(&stack_ulong, 0xdeadbeefUL);
397  _Atomic_Init_ptr(&stack_ptr, &static_ptr);
398  _Atomic_Flag_clear(&stack_flag, ATOMIC_ORDER_RELAXED);
399
400  rtems_test_assert(
401    memcmp(&stack_ulong, &static_ulong, sizeof(stack_ulong)) == 0
402  );
403  rtems_test_assert(
404    memcmp(&stack_ptr, &static_ptr, sizeof(stack_ptr)) == 0
405  );
406  rtems_test_assert(
407    memcmp(&stack_flag, &static_flag, sizeof(stack_flag)) == 0
408  );
409
410  rtems_test_assert(
411    _Atomic_Load_ulong(&stack_ulong, ATOMIC_ORDER_RELAXED) == 0xdeadbeefUL
412  );
413  rtems_test_assert(
414    _Atomic_Load_ptr(&stack_ptr, ATOMIC_ORDER_RELAXED) == &static_ptr
415  );
416  rtems_test_assert(
417    !_Atomic_Flag_test_and_set(&stack_flag, ATOMIC_ORDER_RELAXED)
418  );
419}
420
421static void test(void)
422{
423  test_context *ctx = &test_instance;
424  rtems_status_code sc;
425  size_t worker_index;
426
427  test_static_and_dynamic_initialization();
428
429  ctx->worker_count = rtems_smp_get_processor_count();
430
431  sc = rtems_timer_create(
432    rtems_build_name('S', 'T', 'O', 'P'),
433    &ctx->stop_worker_timer_id
434  );
435  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
436
437  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
438    rtems_id worker_id;
439
440    sc = rtems_task_create(
441      rtems_build_name('W', 'O', 'R', 'K'),
442      WORKER_PRIORITY,
443      RTEMS_MINIMUM_STACK_SIZE,
444      RTEMS_DEFAULT_MODES,
445      RTEMS_DEFAULT_ATTRIBUTES,
446      &worker_id
447    );
448    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
449
450    sc = rtems_task_start(worker_id, worker_task, worker_index);
451    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
452  }
453
454  run_tests(ctx, 0);
455}
456
457static void Init(rtems_task_argument arg)
458{
459  puts("\n\n*** TEST SMPATOMIC 8 ***");
460
461  test();
462
463  puts("*** END OF TEST SMPATOMIC 8 ***");
464
465  rtems_test_exit(0);
466}
467
468#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
469#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
470
471#define CONFIGURE_SMP_APPLICATION
472
473#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
474
475#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
476
477#define CONFIGURE_MAXIMUM_TIMERS 1
478
479#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
480#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
481#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
482
483#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
484
485#define CONFIGURE_INIT
486
487#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.