source: rtems/testsuites/smptests/smpatomic01/init.c @ a418b2f

4.115
Last change on this file since a418b2f was ad7292f, checked in by Sebastian Huber <sebastian.huber@…>, on 02/14/14 at 11:57:53

score: Add SMP barrier

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