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

4.11
Last change on this file since d39ccd69 was d39ccd69, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 1, 2013 at 12:34:31 PM

smptests/smpatomic08: Fix compare and exchange

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