source: rtems/testsuites/smptests/smpatomic08/init.c @ fee154be

4.11
Last change on this file since fee154be was fee154be, checked in by WeiY <wei.a.yang@…>, on Sep 28, 2013 at 6:54:36 AM

add simple atomic test cases into smpatomic08

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