source: rtems/testsuites/smptests/smpatomic01/init.c @ 8b50a55

4.115
Last change on this file since 8b50a55 was 8b50a55, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 3, 2014 at 8:09:24 AM

score: Add _Atomic_Fence()

  • Property mode set to 100644
File size: 16.1 KB
Line 
1/*
2 * Copyright (c) 2013-2014 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 * Copyright (c) 2013 Deng Hengyi.
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.com/license/LICENSE.
15 */
16
17#ifdef HAVE_CONFIG_H
18  #include "config.h"
19#endif
20
21#include <rtems/score/atomic.h>
22#include <rtems/score/smpbarrier.h>
23#include <rtems.h>
24#include <limits.h>
25#include <string.h>
26
27#include "tmacros.h"
28
29#define MASTER_PRIORITY 1
30
31#define WORKER_PRIORITY 2
32
33#define CPU_COUNT 32
34
35typedef struct {
36  Atomic_Ulong stop;
37  SMP_barrier_Control barrier;
38  size_t worker_count;
39  rtems_id stop_worker_timer_id;
40  Atomic_Uint atomic_int_value;
41  Atomic_Ulong atomic_value;
42  unsigned long per_worker_value[CPU_COUNT];
43  unsigned long normal_value;
44  char unused_space_for_cache_line_separation[128];
45  unsigned long second_value;
46  Atomic_Flag global_flag;
47} test_context;
48
49typedef struct {
50  void (*init)(test_context *ctx);
51  void (*body)(test_context *ctx, size_t worker_index);
52  void (*fini)(test_context *ctx);
53} test_case;
54
55static test_context test_instance = {
56  .stop = ATOMIC_INITIALIZER_ULONG(0),
57  .barrier = SMP_BARRIER_CONTROL_INITIALIZER
58};
59
60static bool stop(test_context *ctx)
61{
62  return _Atomic_Load_ulong(&ctx->stop, ATOMIC_ORDER_RELAXED) != 0;
63}
64
65static bool is_master_worker(size_t worker_index)
66{
67  return worker_index == 0;
68}
69
70static void test_fini(
71  test_context *ctx,
72  const char *test,
73  bool atomic
74)
75{
76  unsigned long expected_value = 0;
77  unsigned long actual_value;
78  size_t worker_index;
79
80  printf("=== atomic %s test case ===\n", test);
81
82  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
83    unsigned long worker_value = ctx->per_worker_value[worker_index];
84
85    expected_value += worker_value;
86
87    printf(
88      "worker %zu value: %lu\n",
89      worker_index,
90      worker_value
91    );
92  }
93
94  if (atomic) {
95    actual_value = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
96  } else {
97    actual_value = ctx->normal_value;
98  }
99
100  printf(
101    "atomic value: expected = %lu, actual = %lu\n",
102    expected_value,
103    actual_value
104  );
105
106  rtems_test_assert(expected_value == actual_value);
107}
108
109static void test_atomic_add_init(test_context *ctx)
110{
111  _Atomic_Init_ulong(&ctx->atomic_value, 0);
112}
113
114static void test_atomic_add_body(test_context *ctx, size_t worker_index)
115{
116  unsigned long counter = 0;
117
118  while (!stop(ctx)) {
119    ++counter;
120    _Atomic_Fetch_add_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
121  }
122
123  ctx->per_worker_value[worker_index] = counter;
124}
125
126static void test_atomic_add_fini(test_context *ctx)
127{
128  test_fini(ctx, "add", true);
129}
130
131static void test_atomic_flag_init(test_context *ctx)
132{
133  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
134  ctx->normal_value = 0;
135}
136
137static void test_atomic_flag_body(test_context *ctx, size_t worker_index)
138{
139  unsigned long counter = 0;
140
141  while (!stop(ctx)) {
142    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
143      /* Wait */
144    }
145
146    ++counter;
147    ++ctx->normal_value;
148
149    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
150  }
151
152  ctx->per_worker_value[worker_index] = counter;
153}
154
155static void test_atomic_flag_fini(test_context *ctx)
156{
157  test_fini(ctx, "flag", false);
158}
159
160static void test_atomic_sub_init(test_context *ctx)
161{
162  _Atomic_Init_ulong(&ctx->atomic_value, 0);
163}
164
165static void test_atomic_sub_body(test_context *ctx, size_t worker_index)
166{
167  unsigned long counter = 0;
168
169  while (!stop(ctx)) {
170    --counter;
171    _Atomic_Fetch_sub_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
172  }
173
174  ctx->per_worker_value[worker_index] = counter;
175}
176
177static void test_atomic_sub_fini(test_context *ctx)
178{
179  test_fini(ctx, "sub", true);
180}
181
182static void test_atomic_compare_exchange_init(test_context *ctx)
183{
184  _Atomic_Init_ulong(&ctx->atomic_value, 0);
185  ctx->normal_value = 0;
186}
187
188static void test_atomic_compare_exchange_body(test_context *ctx, size_t worker_index)
189{
190  unsigned long counter = 0;
191
192  while (!stop(ctx)) {
193    bool success;
194
195    do {
196      unsigned long zero = 0;
197
198      success = _Atomic_Compare_exchange_ulong(
199        &ctx->atomic_value,
200        &zero,
201        1,
202        ATOMIC_ORDER_ACQUIRE,
203        ATOMIC_ORDER_RELAXED
204      );
205    } while (!success);
206
207    ++counter;
208    ++ctx->normal_value;
209
210    _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
211  }
212
213  ctx->per_worker_value[worker_index] = counter;
214}
215
216static void test_atomic_compare_exchange_fini(test_context *ctx)
217{
218  test_fini(ctx, "compare exchange", false);
219}
220
221static void test_atomic_or_and_init(test_context *ctx)
222{
223  _Atomic_Init_ulong(&ctx->atomic_value, 0);
224}
225
226static void test_atomic_or_and_body(test_context *ctx, size_t worker_index)
227{
228  unsigned long the_bit = 1UL << worker_index;
229  unsigned long current_bit = 0;
230
231  while (!stop(ctx)) {
232    unsigned long previous;
233
234    if (current_bit != 0) {
235      previous = _Atomic_Fetch_and_ulong(
236        &ctx->atomic_value,
237        ~the_bit,
238        ATOMIC_ORDER_RELAXED
239      );
240      current_bit = 0;
241    } else {
242      previous = _Atomic_Fetch_or_ulong(
243        &ctx->atomic_value,
244        the_bit,
245        ATOMIC_ORDER_RELAXED
246      );
247      current_bit = the_bit;
248    }
249
250    rtems_test_assert((previous & the_bit) != current_bit);
251  }
252
253  ctx->per_worker_value[worker_index] = current_bit;
254}
255
256static void test_atomic_or_and_fini(test_context *ctx)
257{
258  test_fini(ctx, "or/and", true);
259}
260
261static void test_atomic_fence_init(test_context *ctx)
262{
263  ctx->normal_value = 0;
264  ctx->second_value = 0;
265  _Atomic_Fence(ATOMIC_ORDER_RELEASE);
266}
267
268static void test_atomic_fence_body(test_context *ctx, size_t worker_index)
269{
270  if (is_master_worker(worker_index)) {
271    unsigned long counter = 0;
272
273    while (!stop(ctx)) {
274      ++counter;
275      ctx->normal_value = counter;
276      _Atomic_Fence(ATOMIC_ORDER_RELEASE);
277      ctx->second_value = counter;
278    }
279  } else {
280    while (!stop(ctx)) {
281      unsigned long n;
282      unsigned long s;
283
284      s = ctx->second_value;
285      _Atomic_Fence(ATOMIC_ORDER_ACQUIRE);
286      n = ctx->normal_value;
287
288      rtems_test_assert(n - s < LONG_MAX);
289    }
290  }
291}
292
293static void test_atomic_fence_fini(test_context *ctx)
294{
295  printf(
296    "=== atomic fence test case ===\n"
297    "normal value = %lu, second value = %lu\n",
298    ctx->normal_value,
299    ctx->second_value
300  );
301}
302
303static const test_case test_cases[] = {
304  {
305    test_atomic_add_init,
306    test_atomic_add_body,
307    test_atomic_add_fini
308  }, {
309    test_atomic_flag_init,
310    test_atomic_flag_body,
311    test_atomic_flag_fini
312  }, {
313    test_atomic_sub_init,
314    test_atomic_sub_body,
315    test_atomic_sub_fini
316  }, {
317    test_atomic_compare_exchange_init,
318    test_atomic_compare_exchange_body,
319    test_atomic_compare_exchange_fini
320  }, {
321    test_atomic_or_and_init,
322    test_atomic_or_and_body,
323    test_atomic_or_and_fini
324  }, {
325    test_atomic_fence_init,
326    test_atomic_fence_body,
327    test_atomic_fence_fini
328  },
329};
330
331#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
332
333static void stop_worker_timer(rtems_id timer_id, void *arg)
334{
335  test_context *ctx = arg;
336
337  _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
338}
339
340static void start_worker_stop_timer(test_context *ctx)
341{
342  rtems_status_code sc;
343
344  _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
345
346  sc = rtems_timer_fire_after(
347    ctx->stop_worker_timer_id,
348    rtems_clock_get_ticks_per_second(),
349    stop_worker_timer,
350    ctx
351  );
352  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
353}
354
355static void run_tests(test_context *ctx, size_t worker_index)
356{
357  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
358  size_t test;
359
360  for (test = 0; test < TEST_COUNT; ++test) {
361    const test_case *tc = &test_cases[test];
362
363    if (is_master_worker(worker_index)) {
364      start_worker_stop_timer(ctx);
365      (*tc->init)(ctx);
366    }
367
368    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
369
370    (*tc->body)(ctx, worker_index);
371
372    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
373
374    if (is_master_worker(worker_index)) {
375      (*tc->fini)(ctx);
376    }
377  }
378}
379
380static void worker_task(size_t worker_index)
381{
382  test_context *ctx = &test_instance;
383
384  run_tests(ctx, worker_index);
385
386  (void) rtems_task_suspend(RTEMS_SELF);
387  rtems_test_assert(0);
388}
389
390static void test_static_and_dynamic_initialization(void)
391{
392  static Atomic_Uint static_uint =
393    ATOMIC_INITIALIZER_UINT(0xc01dc0feU);
394  static Atomic_Ulong static_ulong =
395    ATOMIC_INITIALIZER_ULONG(0xdeadbeefUL);
396  static Atomic_Pointer static_ptr =
397    ATOMIC_INITIALIZER_PTR(&static_ptr);
398  static Atomic_Flag static_flag = ATOMIC_INITIALIZER_FLAG;
399
400  Atomic_Uint stack_uint;
401  Atomic_Ulong stack_ulong;
402  Atomic_Pointer stack_ptr;
403  Atomic_Flag stack_flag;
404
405  puts("=== static and dynamic initialization test case ===");
406
407  _Atomic_Init_uint(&stack_uint, 0xc01dc0feU);
408  _Atomic_Init_ulong(&stack_ulong, 0xdeadbeefUL);
409  _Atomic_Init_ptr(&stack_ptr, &static_ptr);
410  _Atomic_Flag_clear(&stack_flag, ATOMIC_ORDER_RELAXED);
411
412  rtems_test_assert(
413    memcmp(&stack_uint, &static_uint, sizeof(stack_uint)) == 0
414  );
415  rtems_test_assert(
416    memcmp(&stack_ulong, &static_ulong, sizeof(stack_ulong)) == 0
417  );
418  rtems_test_assert(
419    memcmp(&stack_ptr, &static_ptr, sizeof(stack_ptr)) == 0
420  );
421  rtems_test_assert(
422    memcmp(&stack_flag, &static_flag, sizeof(stack_flag)) == 0
423  );
424
425  rtems_test_assert(
426    _Atomic_Load_uint(&stack_uint, ATOMIC_ORDER_RELAXED) == 0xc01dc0feU
427  );
428  rtems_test_assert(
429    _Atomic_Load_ulong(&stack_ulong, ATOMIC_ORDER_RELAXED) == 0xdeadbeefUL
430  );
431  rtems_test_assert(
432    _Atomic_Load_ptr(&stack_ptr, ATOMIC_ORDER_RELAXED) == &static_ptr
433  );
434  rtems_test_assert(
435    !_Atomic_Flag_test_and_set(&stack_flag, ATOMIC_ORDER_RELAXED)
436  );
437}
438
439static void test(void)
440{
441  test_context *ctx = &test_instance;
442  rtems_status_code sc;
443  size_t worker_index;
444
445  test_static_and_dynamic_initialization();
446
447  ctx->worker_count = rtems_smp_get_processor_count();
448
449  sc = rtems_timer_create(
450    rtems_build_name('S', 'T', 'O', 'P'),
451    &ctx->stop_worker_timer_id
452  );
453  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
454
455  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
456    rtems_id worker_id;
457
458    sc = rtems_task_create(
459      rtems_build_name('W', 'O', 'R', 'K'),
460      WORKER_PRIORITY,
461      RTEMS_MINIMUM_STACK_SIZE,
462      RTEMS_DEFAULT_MODES,
463      RTEMS_DEFAULT_ATTRIBUTES,
464      &worker_id
465    );
466    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
467
468    sc = rtems_task_start(worker_id, worker_task, worker_index);
469    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
470  }
471
472  run_tests(ctx, 0);
473}
474
475typedef void (*simple_test_body)(test_context *ctx);
476
477static void test_simple_atomic_add_body(test_context *ctx)
478{
479  unsigned int ia = 8, ib = 4;
480  unsigned int ic;
481  unsigned long a = 2, b = 1;
482  unsigned long c;
483
484  puts("=== atomic simple add test case ===\n");
485
486  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
487  _Atomic_Fetch_add_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
488  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
489  rtems_test_assert(ic == (ia + ib));
490
491  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
492  _Atomic_Fetch_add_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
493  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
494  rtems_test_assert(c == (a + b));
495}
496
497static void test_simple_atomic_sub_body(test_context *ctx)
498{
499  unsigned int ia = 8, ib = 4;
500  unsigned int ic;
501  unsigned long a = 2, b = 1;
502  unsigned long c;
503
504  puts("=== atomic simple sub test case ===\n");
505
506  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
507  _Atomic_Fetch_sub_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
508  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
509  rtems_test_assert(ic == (ia - ib));
510
511  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
512  _Atomic_Fetch_sub_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
513  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
514  rtems_test_assert(c == (a - b));
515}
516
517static void test_simple_atomic_or_body(test_context *ctx)
518{
519  unsigned int ia = 8, ib = 4;
520  unsigned int ic;
521  unsigned long a = 2, b = 1;
522  unsigned long c;
523
524  puts("=== atomic simple or test case ===\n");
525
526  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
527  _Atomic_Fetch_or_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
528  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
529  rtems_test_assert(ic == (ia | ib));
530
531  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
532  _Atomic_Fetch_or_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
533  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
534  rtems_test_assert(c == (a | b));
535}
536
537static void test_simple_atomic_and_body(test_context *ctx)
538{
539  unsigned int ia = 8, ib = 4;
540  unsigned int ic;
541  unsigned long a = 2, b = 1;
542  unsigned long c;
543
544  puts("=== atomic simple and test case ===\n");
545
546  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
547  _Atomic_Fetch_and_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
548  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
549  rtems_test_assert(ic == (ia & ib));
550
551  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
552  _Atomic_Fetch_and_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
553  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
554  rtems_test_assert(c == (a & b));
555}
556
557static void test_simple_atomic_exchange_body(test_context *ctx)
558{
559  unsigned int ia = 8, ib = 4;
560  unsigned int ic;
561  unsigned long a = 2, b = 1;
562  unsigned long c;
563
564  puts("=== atomic simple exchange test case ===\n");
565
566  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
567  _Atomic_Exchange_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
568  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
569  rtems_test_assert(ic == ib);
570
571  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
572  _Atomic_Exchange_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
573  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
574  rtems_test_assert(c == b);
575}
576
577static void test_simple_atomic_compare_exchange_body(test_context *ctx)
578{
579  unsigned int ia = 8, ib = 4;
580  unsigned int ic;
581  unsigned long a = 2, b = 1;
582  unsigned long c;
583
584  puts("=== atomic simple compare exchange test case ===\n");
585
586  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
587  _Atomic_Compare_exchange_uint(&ctx->atomic_int_value, &ia, ib,
588    ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
589  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
590  rtems_test_assert(ic == ib);
591
592  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
593  _Atomic_Compare_exchange_ulong(&ctx->atomic_value, &a, b,
594    ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
595  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
596  rtems_test_assert(c == b);
597}
598
599static const simple_test_body simple_test_bodies[] = {
600  test_simple_atomic_add_body,
601  test_simple_atomic_sub_body,
602  test_simple_atomic_or_body,
603  test_simple_atomic_and_body,
604  test_simple_atomic_exchange_body,
605  test_simple_atomic_compare_exchange_body,
606};
607
608#define SIMPLE_TEST_COUNT RTEMS_ARRAY_SIZE(simple_test_bodies)
609
610static void simple_tests(void)
611{
612  test_context *ctx = &test_instance;
613  size_t test;
614
615  for (test = 0; test < SIMPLE_TEST_COUNT; ++test) {
616    const simple_test_body *test_body = &simple_test_bodies[test];
617
618    (*test_body)(ctx);
619  }
620}
621
622static void Init(rtems_task_argument arg)
623{
624  puts("\n\n*** TEST SMPATOMIC 1 ***");
625
626  simple_tests();
627
628  test();
629
630  puts("*** END OF TEST SMPATOMIC 1 ***");
631
632  rtems_test_exit(0);
633}
634
635#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
636#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
637
638#define CONFIGURE_SMP_APPLICATION
639
640#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
641
642#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
643
644#define CONFIGURE_MAXIMUM_TIMERS 1
645
646#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
647#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
648#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
649
650#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
651
652#define CONFIGURE_INIT
653
654#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.