source: rtems/testsuites/smptests/smpatomic08/init.c @ 7136d7f

4.11
Last change on this file since 7136d7f was 7136d7f, checked in by Sebastian Huber <sebastian.huber@…>, on Sep 1, 2013 at 1:01:42 PM

smptests/smpatomic08: Simplify or/and test case

Renamed and use common integer variables.

  • Property mode set to 100644
File size: 12.0 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 atomic_value;
81  uint_fast32_t per_worker_value[CPU_COUNT];
82  uint32_t normal_value;
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->atomic_value, 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->atomic_value, 1, ATOMIC_ORDER_RELAXED);
119  }
120
121  ctx->per_worker_value[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_value[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->atomic_value, 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->normal_value = 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->normal_value;
172
173    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
174  }
175
176  ctx->per_worker_value[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_value[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->normal_value;
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->atomic_value, 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->atomic_value, 1, ATOMIC_ORDER_RELAXED);
222  }
223
224  ctx->per_worker_value[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_value[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->atomic_value, 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->atomic_value, 0);
262  ctx->normal_value = 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->atomic_value,
277        &zero,
278        1,
279        ATOMIC_ORDER_ACQUIRE,
280        ATOMIC_ORDER_RELAXED
281      );
282    } while (!success);
283
284    ++counter;
285    ++ctx->normal_value;
286
287    _Atomic_Store_uint(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
288  }
289
290  ctx->per_worker_value[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_value[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->normal_value;
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->atomic_value, 0);
327}
328
329static void test_atomic_or_and_body(test_context *ctx, size_t worker_index)
330{
331  uint_fast32_t the_bit = 1UL << worker_index;
332  uint_fast32_t current_bit = 0;
333
334  while (!stop(ctx)) {
335    uint_fast32_t previous;
336
337    if (current_bit != 0) {
338      previous = _Atomic_Fetch_and_uint(
339        &ctx->atomic_value,
340        ~the_bit,
341        ATOMIC_ORDER_RELAXED
342      );
343      current_bit = 0;
344    } else {
345      previous = _Atomic_Fetch_or_uint(
346        &ctx->atomic_value,
347        the_bit,
348        ATOMIC_ORDER_RELAXED
349      );
350      current_bit = the_bit;
351    }
352
353    rtems_test_assert((previous & the_bit) != current_bit);
354  }
355
356  ctx->per_worker_value[worker_index] = current_bit;
357}
358
359static void test_atomic_or_and_fini(test_context *ctx)
360{
361  uint_fast32_t expected_counter = 0;
362  uint_fast32_t actual_counter;
363  size_t worker_index;
364
365  printf("=== atomic or_and test case ==\n");
366
367  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
368    uint_fast32_t worker_counter = ctx->per_worker_value[worker_index];
369
370    expected_counter += worker_counter;
371
372    printf(
373      "atomic or_and worker %zu counter: %" PRIuFAST32 "\n",
374      worker_index,
375      worker_counter
376    );
377  }
378
379  actual_counter = _Atomic_Load_uint(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
380
381  printf(
382    "global counter: expected = %" PRIuFAST32 ", actual = %" PRIuFAST32 "\n",
383    expected_counter,
384    actual_counter
385  );
386
387  rtems_test_assert(expected_counter == actual_counter);
388}
389
390static const test_case test_cases[] = {
391  { test_atomic_add_init, test_atomic_add_body, test_atomic_add_fini },
392  { test_atomic_flag_init, test_atomic_flag_body, test_atomic_flag_fini },
393  { test_atomic_sub_init, test_atomic_sub_body, test_atomic_sub_fini },
394  { test_atomic_compare_exchange_init, test_atomic_compare_exchange_body,
395    test_atomic_compare_exchange_fini },
396  { test_atomic_or_and_init, test_atomic_or_and_body, test_atomic_or_and_fini },
397};
398
399#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
400
401static void stop_worker_timer(rtems_id timer_id, void *arg)
402{
403  test_context *ctx = arg;
404
405  _Atomic_Store_uint(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
406}
407
408static void start_worker_stop_timer(test_context *ctx)
409{
410  rtems_status_code sc;
411
412  _Atomic_Store_uint(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
413
414  sc = rtems_timer_fire_after(
415    ctx->stop_worker_timer_id,
416    rtems_clock_get_ticks_per_second(),
417    stop_worker_timer,
418    ctx
419  );
420  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
421}
422
423static void run_tests(test_context *ctx, size_t worker_index)
424{
425  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
426  size_t test;
427
428  for (test = 0; test < TEST_COUNT; ++test) {
429    const test_case *tc = &test_cases[test];
430
431    if (is_master_worker(worker_index)) {
432      start_worker_stop_timer(ctx);
433      (*tc->init)(ctx);
434    }
435
436    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
437
438    (*tc->body)(ctx, worker_index);
439
440    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
441
442    if (is_master_worker(worker_index)) {
443      (*tc->fini)(ctx);
444    }
445  }
446}
447
448static void worker_task(size_t worker_index)
449{
450  test_context *ctx = &test_instance;
451
452  run_tests(ctx, worker_index);
453
454  (void) rtems_task_suspend(RTEMS_SELF);
455  rtems_test_assert(0);
456}
457
458static void test(void)
459{
460  test_context *ctx = &test_instance;
461  rtems_status_code sc;
462  size_t worker_index;
463
464  ctx->worker_count = rtems_smp_get_processor_count();
465
466  sc = rtems_timer_create(
467    rtems_build_name('S', 'T', 'O', 'P'),
468    &ctx->stop_worker_timer_id
469  );
470  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
471
472  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
473    rtems_id worker_id;
474
475    sc = rtems_task_create(
476      rtems_build_name('W', 'O', 'R', 'K'),
477      WORKER_PRIORITY,
478      RTEMS_MINIMUM_STACK_SIZE,
479      RTEMS_DEFAULT_MODES,
480      RTEMS_DEFAULT_ATTRIBUTES,
481      &worker_id
482    );
483    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
484
485    sc = rtems_task_start(worker_id, worker_task, worker_index);
486    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
487  }
488
489  run_tests(ctx, 0);
490}
491
492static void Init(rtems_task_argument arg)
493{
494  puts("\n\n*** TEST SMPATOMIC 8 ***");
495
496  test();
497
498  puts("*** END OF TEST SMPATOMIC 8 ***");
499
500  rtems_test_exit(0);
501}
502
503#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
504#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
505
506#define CONFIGURE_SMP_APPLICATION
507
508#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
509
510#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
511
512#define CONFIGURE_MAXIMUM_TIMERS 1
513
514#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
515#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
516#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
517
518#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
519
520#define CONFIGURE_INIT
521
522#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.