source: rtems/testsuites/smptests/smpatomic01/init.c @ 6b5df95

5
Last change on this file since 6b5df95 was 8d296cd5, checked in by Sebastian Huber <sebastian.huber@…>, on 09/26/15 at 11:03:16

score: Use uintptr_t for atomic pointer operations

Do not obfuscate the standard API.

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * Copyright (c) 2013-2015 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.org/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 <rtems/test.h>
24#include <limits.h>
25#include <string.h>
26
27#include "tmacros.h"
28
29const char rtems_test_name[] = "SMPATOMIC 1";
30
31#define MASTER_PRIORITY 1
32
33#define WORKER_PRIORITY 2
34
35#define CPU_COUNT 32
36
37typedef struct {
38  rtems_test_parallel_context base;
39  Atomic_Ulong atomic_value;
40  unsigned long per_worker_value[CPU_COUNT];
41  unsigned long normal_value;
42  char unused_space_for_cache_line_separation[128];
43  unsigned long second_value;
44  Atomic_Flag global_flag;
45} smpatomic01_context;
46
47static smpatomic01_context test_instance;
48
49static rtems_interval test_duration(void)
50{
51  return rtems_clock_get_ticks_per_second();
52}
53
54static void test_fini(
55  smpatomic01_context *ctx,
56  const char *test,
57  bool atomic
58)
59{
60  unsigned long expected_value = 0;
61  unsigned long actual_value;
62  size_t worker_index;
63
64  printf("=== atomic %s test case ===\n", test);
65
66  for (
67    worker_index = 0;
68    worker_index < ctx->base.worker_count;
69    ++worker_index
70  ) {
71    unsigned long worker_value = ctx->per_worker_value[worker_index];
72
73    expected_value += worker_value;
74
75    printf(
76      "worker %zu value: %lu\n",
77      worker_index,
78      worker_value
79    );
80  }
81
82  if (atomic) {
83    actual_value = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
84  } else {
85    actual_value = ctx->normal_value;
86  }
87
88  printf(
89    "atomic value: expected = %lu, actual = %lu\n",
90    expected_value,
91    actual_value
92  );
93
94  rtems_test_assert(expected_value == actual_value);
95}
96
97
98static rtems_interval test_atomic_add_init(
99  rtems_test_parallel_context *base,
100  void *arg,
101  size_t active_workers
102)
103{
104  smpatomic01_context *ctx = (smpatomic01_context *) base;
105
106  _Atomic_Init_ulong(&ctx->atomic_value, 0);
107
108  return test_duration();
109}
110
111static void test_atomic_add_body(
112  rtems_test_parallel_context *base,
113  void *arg,
114  size_t active_workers,
115  size_t worker_index
116)
117{
118  smpatomic01_context *ctx = (smpatomic01_context *) base;
119  unsigned long counter = 0;
120
121  while (!rtems_test_parallel_stop_job(&ctx->base)) {
122    ++counter;
123    _Atomic_Fetch_add_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
124  }
125
126  ctx->per_worker_value[worker_index] = counter;
127}
128
129static void test_atomic_add_fini(
130  rtems_test_parallel_context *base,
131  void *arg,
132  size_t active_workers
133)
134{
135  smpatomic01_context *ctx = (smpatomic01_context *) base;
136
137  test_fini(ctx, "add", true);
138}
139
140static rtems_interval test_atomic_flag_init(
141  rtems_test_parallel_context *base,
142  void *arg,
143  size_t active_workers
144)
145{
146  smpatomic01_context *ctx = (smpatomic01_context *) base;
147
148  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
149  ctx->normal_value = 0;
150
151  return test_duration();
152}
153
154static void test_atomic_flag_body(
155  rtems_test_parallel_context *base,
156  void *arg,
157  size_t active_workers,
158  size_t worker_index
159)
160{
161  smpatomic01_context *ctx = (smpatomic01_context *) base;
162  unsigned long counter = 0;
163
164  while (!rtems_test_parallel_stop_job(&ctx->base)) {
165    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
166      /* Wait */
167    }
168
169    ++counter;
170    ++ctx->normal_value;
171
172    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
173  }
174
175  ctx->per_worker_value[worker_index] = counter;
176}
177
178static void test_atomic_flag_fini(
179  rtems_test_parallel_context *base,
180  void *arg,
181  size_t active_workers
182  )
183{
184  smpatomic01_context *ctx = (smpatomic01_context *) base;
185
186  test_fini(ctx, "flag", false);
187}
188
189static rtems_interval test_atomic_sub_init(
190  rtems_test_parallel_context *base,
191  void *arg,
192  size_t active_workers
193)
194{
195  smpatomic01_context *ctx = (smpatomic01_context *) base;
196
197  _Atomic_Init_ulong(&ctx->atomic_value, 0);
198
199  return test_duration();
200}
201
202static void test_atomic_sub_body(
203  rtems_test_parallel_context *base,
204  void *arg,
205  size_t active_workers,
206  size_t worker_index
207)
208{
209  smpatomic01_context *ctx = (smpatomic01_context *) base;
210  unsigned long counter = 0;
211
212  while (!rtems_test_parallel_stop_job(&ctx->base)) {
213    --counter;
214    _Atomic_Fetch_sub_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
215  }
216
217  ctx->per_worker_value[worker_index] = counter;
218}
219
220static void test_atomic_sub_fini(
221  rtems_test_parallel_context *base,
222  void *arg,
223  size_t active_workers
224)
225{
226  smpatomic01_context *ctx = (smpatomic01_context *) base;
227
228  test_fini(ctx, "sub", true);
229}
230
231static rtems_interval test_atomic_compare_exchange_init(
232  rtems_test_parallel_context *base,
233  void *arg,
234  size_t active_workers
235)
236{
237  smpatomic01_context *ctx = (smpatomic01_context *) base;
238
239  _Atomic_Init_ulong(&ctx->atomic_value, 0);
240  ctx->normal_value = 0;
241
242  return test_duration();
243}
244
245static void test_atomic_compare_exchange_body(
246  rtems_test_parallel_context *base,
247  void *arg,
248  size_t active_workers,
249  size_t worker_index
250)
251{
252  smpatomic01_context *ctx = (smpatomic01_context *) base;
253  unsigned long counter = 0;
254
255  while (!rtems_test_parallel_stop_job(&ctx->base)) {
256    bool success;
257
258    do {
259      unsigned long zero = 0;
260
261      success = _Atomic_Compare_exchange_ulong(
262        &ctx->atomic_value,
263        &zero,
264        1,
265        ATOMIC_ORDER_ACQUIRE,
266        ATOMIC_ORDER_RELAXED
267      );
268    } while (!success);
269
270    ++counter;
271    ++ctx->normal_value;
272
273    _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
274  }
275
276  ctx->per_worker_value[worker_index] = counter;
277}
278
279static void test_atomic_compare_exchange_fini(
280  rtems_test_parallel_context *base,
281  void *arg,
282  size_t active_workers
283)
284{
285  smpatomic01_context *ctx = (smpatomic01_context *) base;
286
287  test_fini(ctx, "compare exchange", false);
288}
289
290static rtems_interval test_atomic_or_and_init(
291  rtems_test_parallel_context *base,
292  void *arg,
293  size_t active_workers
294)
295{
296  smpatomic01_context *ctx = (smpatomic01_context *) base;
297
298  _Atomic_Init_ulong(&ctx->atomic_value, 0);
299
300  return test_duration();
301}
302
303static void test_atomic_or_and_body(
304  rtems_test_parallel_context *base,
305  void *arg,
306  size_t active_workers,
307  size_t worker_index
308)
309{
310  smpatomic01_context *ctx = (smpatomic01_context *) base;
311  unsigned long the_bit = 1UL << worker_index;
312  unsigned long current_bit = 0;
313
314  while (!rtems_test_parallel_stop_job(&ctx->base)) {
315    unsigned long previous;
316
317    if (current_bit != 0) {
318      previous = _Atomic_Fetch_and_ulong(
319        &ctx->atomic_value,
320        ~the_bit,
321        ATOMIC_ORDER_RELAXED
322      );
323      current_bit = 0;
324    } else {
325      previous = _Atomic_Fetch_or_ulong(
326        &ctx->atomic_value,
327        the_bit,
328        ATOMIC_ORDER_RELAXED
329      );
330      current_bit = the_bit;
331    }
332
333    rtems_test_assert((previous & the_bit) != current_bit);
334  }
335
336  ctx->per_worker_value[worker_index] = current_bit;
337}
338
339static void test_atomic_or_and_fini(
340  rtems_test_parallel_context *base,
341  void *arg,
342  size_t active_workers
343)
344{
345  smpatomic01_context *ctx = (smpatomic01_context *) base;
346
347  test_fini(ctx, "or/and", true);
348}
349
350static rtems_interval test_atomic_fence_init(
351  rtems_test_parallel_context *base,
352  void *arg,
353  size_t active_workers
354)
355{
356  smpatomic01_context *ctx = (smpatomic01_context *) base;
357
358  ctx->normal_value = 0;
359  ctx->second_value = 0;
360  _Atomic_Fence(ATOMIC_ORDER_RELEASE);
361
362  return test_duration();
363}
364
365static void test_atomic_fence_body(
366  rtems_test_parallel_context *base,
367  void *arg,
368  size_t active_workers,
369  size_t worker_index
370)
371{
372  smpatomic01_context *ctx = (smpatomic01_context *) base;
373
374  if (rtems_test_parallel_is_master_worker(worker_index)) {
375    unsigned long counter = 0;
376
377    while (!rtems_test_parallel_stop_job(&ctx->base)) {
378      ++counter;
379      ctx->normal_value = counter;
380      _Atomic_Fence(ATOMIC_ORDER_RELEASE);
381      ctx->second_value = counter;
382    }
383  } else {
384    while (!rtems_test_parallel_stop_job(&ctx->base)) {
385      unsigned long n;
386      unsigned long s;
387
388      s = ctx->second_value;
389      _Atomic_Fence(ATOMIC_ORDER_ACQUIRE);
390      n = ctx->normal_value;
391
392      rtems_test_assert(n - s < LONG_MAX);
393    }
394  }
395}
396
397static void test_atomic_fence_fini(
398  rtems_test_parallel_context *base,
399  void *arg,
400  size_t active_workers
401)
402{
403  smpatomic01_context *ctx = (smpatomic01_context *) base;
404
405  printf(
406    "=== atomic fence test case ===\n"
407    "normal value = %lu, second value = %lu\n",
408    ctx->normal_value,
409    ctx->second_value
410  );
411}
412
413static const rtems_test_parallel_job test_jobs[] = {
414  {
415    .init = test_atomic_add_init,
416    .body = test_atomic_add_body,
417    .fini = test_atomic_add_fini
418  }, {
419    .init = test_atomic_flag_init,
420    .body = test_atomic_flag_body,
421    .fini = test_atomic_flag_fini
422  }, {
423    .init = test_atomic_sub_init,
424    .body = test_atomic_sub_body,
425    .fini = test_atomic_sub_fini
426  }, {
427    .init = test_atomic_compare_exchange_init,
428    .body = test_atomic_compare_exchange_body,
429    .fini = test_atomic_compare_exchange_fini
430  }, {
431    .init = test_atomic_or_and_init,
432    .body = test_atomic_or_and_body,
433    .fini = test_atomic_or_and_fini
434  }, {
435    .init = test_atomic_fence_init,
436    .body = test_atomic_fence_body,
437    .fini = test_atomic_fence_fini
438  },
439};
440
441static void setup_worker(
442  rtems_test_parallel_context *base,
443  size_t worker_index,
444  rtems_id worker_id
445)
446{
447  rtems_status_code sc;
448  rtems_task_priority prio;
449
450  sc = rtems_task_set_priority(worker_id, WORKER_PRIORITY, &prio);
451  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
452}
453
454static void Init(rtems_task_argument arg)
455{
456  smpatomic01_context *ctx = &test_instance;
457
458  TEST_BEGIN();
459
460  rtems_test_parallel(
461    &ctx->base,
462    setup_worker,
463    &test_jobs[0],
464    RTEMS_ARRAY_SIZE(test_jobs)
465  );
466
467  TEST_END();
468  rtems_test_exit(0);
469}
470
471#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
472#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
473
474#define CONFIGURE_SMP_APPLICATION
475
476#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
477
478#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
479
480#define CONFIGURE_MAXIMUM_TIMERS 1
481
482#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
483#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
484#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
485
486#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
487
488#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
489
490#define CONFIGURE_INIT
491
492#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.