source: rtems/testsuites/smptests/smpatomic08/init.c @ 4238aff

4.11
Last change on this file since 4238aff was 4238aff, checked in by WeiY <wei.a.yang@…>, on Sep 1, 2013 at 10:28:35 AM

add atomic sub, and, or, compare_exchange test cases into smpatomic08

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