source: rtems/testsuites/smptests/smpatomic01/init.c @ 4bc8d2e

4.115
Last change on this file since 4bc8d2e was 4bc8d2e, checked in by Sebastian Huber <sebastian.huber@…>, on 04/10/14 at 08:58:27

rtems: Rename rtems_smp_get_processor_count()

Rename rtems_smp_get_processor_count() in rtems_get_processor_count().
Make rtems_get_processor_count() a function in uni-processor
configurations to enable ABI compatibility with SMP configurations.

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