source: rtems/testsuites/smptests/smplock01/init.c @ 05b7eec

5
Last change on this file since 05b7eec was 05b7eec, checked in by Sebastian Huber <sebastian.huber@…>, on 06/08/16 at 13:18:14

score: Add an SMP sequence lock implementation

  • Property mode set to 100644
File size: 12.3 KB
Line 
1/*
2 * Copyright (c) 2013, 2016 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.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/score/smplock.h>
20#include <rtems/score/smplockmcs.h>
21#include <rtems/score/smplockseq.h>
22#include <rtems/score/smpbarrier.h>
23#include <rtems/score/atomic.h>
24#include <rtems.h>
25
26#include "tmacros.h"
27
28const char rtems_test_name[] = "SMPLOCK 1";
29
30#define TASK_PRIORITY 1
31
32#define CPU_COUNT 32
33
34#define TEST_COUNT 11
35
36typedef enum {
37  INITIAL,
38  START_TEST,
39  STOP_TEST
40} states;
41
42typedef struct {
43  Atomic_Uint state;
44  SMP_barrier_Control barrier;
45  rtems_id timer_id;
46  rtems_interval timeout;
47  unsigned long counter[TEST_COUNT];
48  unsigned long test_counter[TEST_COUNT][CPU_COUNT];
49  SMP_lock_Control lock;
50#if defined(RTEMS_PROFILING)
51  SMP_lock_Stats mcs_stats;
52#endif
53  SMP_MCS_lock_Control mcs_lock;
54  SMP_sequence_lock_Control seq_lock;
55  char unused_space_for_cache_line_separation_0[128];
56  int a;
57  char unused_space_for_cache_line_separation_1[128];
58  int b;
59} global_context;
60
61static global_context context = {
62  .state = ATOMIC_INITIALIZER_UINT(INITIAL),
63  .barrier = SMP_BARRIER_CONTROL_INITIALIZER,
64  .lock = SMP_LOCK_INITIALIZER("global ticket"),
65#if defined(RTEMS_PROFILING)
66  .mcs_stats = SMP_LOCK_STATS_INITIALIZER("global MCS"),
67#endif
68  .mcs_lock = SMP_MCS_LOCK_INITIALIZER,
69  .seq_lock = SMP_SEQUENCE_LOCK_INITIALIZER
70};
71
72static const char * const test_names[TEST_COUNT] = {
73  "global ticket lock with local counter",
74  "global MCS lock with local counter",
75  "global ticket lock with global counter",
76  "global MCS lock with global counter",
77  "local ticket lock with local counter",
78  "local MCS lock with local counter",
79  "local ticket lock with global counter",
80  "local MCS lock with global counter",
81  "global ticket lock with busy section",
82  "global MCS lock with busy section",
83  "sequence lock"
84};
85
86static void stop_test_timer(rtems_id timer_id, void *arg)
87{
88  global_context *ctx = arg;
89
90  _Atomic_Store_uint(&ctx->state, STOP_TEST, ATOMIC_ORDER_RELEASE);
91}
92
93static void wait_for_state(global_context *ctx, int desired_state)
94{
95  while (
96    _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_ACQUIRE) != desired_state
97  ) {
98    /* Wait */
99  }
100}
101
102static bool assert_state(global_context *ctx, int desired_state)
103{
104  return _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED) == desired_state;
105}
106
107typedef void (*test_body)(
108  int test,
109  global_context *ctx,
110  SMP_barrier_State *bs,
111  unsigned int cpu_count,
112  unsigned int cpu_self
113);
114
115static void test_0_body(
116  int test,
117  global_context *ctx,
118  SMP_barrier_State *bs,
119  unsigned int cpu_count,
120  unsigned int cpu_self
121)
122{
123  unsigned long counter = 0;
124  SMP_lock_Context lock_context;
125
126  while (assert_state(ctx, START_TEST)) {
127    _SMP_lock_Acquire(&ctx->lock, &lock_context);
128    _SMP_lock_Release(&ctx->lock, &lock_context);
129    ++counter;
130  }
131
132  ctx->test_counter[test][cpu_self] = counter;
133}
134
135static void test_1_body(
136  int test,
137  global_context *ctx,
138  SMP_barrier_State *bs,
139  unsigned int cpu_count,
140  unsigned int cpu_self
141)
142{
143  unsigned long counter = 0;
144  SMP_MCS_lock_Context lock_context;
145
146  while (assert_state(ctx, START_TEST)) {
147    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
148    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
149    ++counter;
150  }
151
152  ctx->test_counter[test][cpu_self] = counter;
153}
154
155static void test_2_body(
156  int test,
157  global_context *ctx,
158  SMP_barrier_State *bs,
159  unsigned int cpu_count,
160  unsigned int cpu_self
161)
162{
163  unsigned long counter = 0;
164  SMP_lock_Context lock_context;
165
166  while (assert_state(ctx, START_TEST)) {
167    _SMP_lock_Acquire(&ctx->lock, &lock_context);
168    ++ctx->counter[test];
169    _SMP_lock_Release(&ctx->lock, &lock_context);
170    ++counter;
171  }
172
173  ctx->test_counter[test][cpu_self] = counter;
174}
175
176static void test_3_body(
177  int test,
178  global_context *ctx,
179  SMP_barrier_State *bs,
180  unsigned int cpu_count,
181  unsigned int cpu_self
182)
183{
184  unsigned long counter = 0;
185  SMP_MCS_lock_Context lock_context;
186
187  while (assert_state(ctx, START_TEST)) {
188    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
189    ++ctx->counter[test];
190    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
191    ++counter;
192  }
193
194  ctx->test_counter[test][cpu_self] = counter;
195}
196
197static void test_4_body(
198  int test,
199  global_context *ctx,
200  SMP_barrier_State *bs,
201  unsigned int cpu_count,
202  unsigned int cpu_self
203)
204{
205  unsigned long counter = 0;
206  SMP_lock_Control lock;
207  SMP_lock_Context lock_context;
208
209  _SMP_lock_Initialize(&lock, "local");
210
211  while (assert_state(ctx, START_TEST)) {
212    _SMP_lock_Acquire(&lock, &lock_context);
213    _SMP_lock_Release(&lock, &lock_context);
214    ++counter;
215  }
216
217  _SMP_lock_Destroy(&lock);
218
219  ctx->test_counter[test][cpu_self] = counter;
220}
221
222static void test_5_body(
223  int test,
224  global_context *ctx,
225  SMP_barrier_State *bs,
226  unsigned int cpu_count,
227  unsigned int cpu_self
228)
229{
230  unsigned long counter = 0;
231#if defined(RTEMS_PROFILING)
232  SMP_lock_Stats stats;
233#endif
234  SMP_MCS_lock_Control lock;
235  SMP_MCS_lock_Context lock_context;
236
237  _SMP_lock_Stats_initialize(&stats, "local");
238  _SMP_MCS_lock_Initialize(&lock);
239
240  while (assert_state(ctx, START_TEST)) {
241    _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);
242    _SMP_MCS_lock_Release(&lock, &lock_context);
243    ++counter;
244  }
245
246  _SMP_MCS_lock_Destroy(&lock);
247  _SMP_lock_Stats_destroy(&stats);
248
249  ctx->test_counter[test][cpu_self] = counter;
250}
251
252static void test_6_body(
253  int test,
254  global_context *ctx,
255  SMP_barrier_State *bs,
256  unsigned int cpu_count,
257  unsigned int cpu_self
258)
259{
260  unsigned long counter = 0;
261  SMP_lock_Control lock;
262  SMP_lock_Context lock_context;
263
264  _SMP_lock_Initialize(&lock, "local");
265
266  while (assert_state(ctx, START_TEST)) {
267    _SMP_lock_Acquire(&lock, &lock_context);
268
269    /* The counter value is not interesting, only the access to it */
270    ++ctx->counter[test];
271
272    _SMP_lock_Release(&lock, &lock_context);
273    ++counter;
274  }
275
276  _SMP_lock_Destroy(&lock);
277
278  ctx->test_counter[test][cpu_self] = counter;
279}
280
281static void test_7_body(
282  int test,
283  global_context *ctx,
284  SMP_barrier_State *bs,
285  unsigned int cpu_count,
286  unsigned int cpu_self
287)
288{
289  unsigned long counter = 0;
290#if defined(RTEMS_PROFILING)
291  SMP_lock_Stats stats;
292#endif
293  SMP_MCS_lock_Control lock;
294  SMP_MCS_lock_Context lock_context;
295
296  _SMP_lock_Stats_initialize(&stats, "local");
297  _SMP_MCS_lock_Initialize(&lock);
298
299  while (assert_state(ctx, START_TEST)) {
300    _SMP_MCS_lock_Acquire(&lock, &lock_context, &stats);
301
302    /* The counter value is not interesting, only the access to it */
303    ++ctx->counter[test];
304
305    _SMP_MCS_lock_Release(&lock, &lock_context);
306    ++counter;
307  }
308
309  _SMP_MCS_lock_Destroy(&lock);
310  _SMP_lock_Stats_destroy(&stats);
311
312  ctx->test_counter[test][cpu_self] = counter;
313}
314
315static void busy_section(void)
316{
317  int i;
318
319  for (i = 0; i < 101; ++i) {
320    RTEMS_COMPILER_MEMORY_BARRIER();
321  }
322}
323
324static void test_8_body(
325  int test,
326  global_context *ctx,
327  SMP_barrier_State *bs,
328  unsigned int cpu_count,
329  unsigned int cpu_self
330)
331{
332  unsigned long counter = 0;
333  SMP_lock_Context lock_context;
334
335  while (assert_state(ctx, START_TEST)) {
336    _SMP_lock_Acquire(&ctx->lock, &lock_context);
337    busy_section();
338    _SMP_lock_Release(&ctx->lock, &lock_context);
339    ++counter;
340  }
341
342  ctx->test_counter[test][cpu_self] = counter;
343}
344
345static void test_9_body(
346  int test,
347  global_context *ctx,
348  SMP_barrier_State *bs,
349  unsigned int cpu_count,
350  unsigned int cpu_self
351)
352{
353  unsigned long counter = 0;
354  SMP_MCS_lock_Context lock_context;
355
356  while (assert_state(ctx, START_TEST)) {
357    _SMP_MCS_lock_Acquire(&ctx->mcs_lock, &lock_context, &ctx->mcs_stats);
358    busy_section();
359    _SMP_MCS_lock_Release(&ctx->mcs_lock, &lock_context);
360    ++counter;
361  }
362
363  ctx->test_counter[test][cpu_self] = counter;
364}
365
366static void test_10_body(
367  int test,
368  global_context *ctx,
369  SMP_barrier_State *bs,
370  unsigned int cpu_count,
371  unsigned int cpu_self
372)
373{
374  unsigned long counter = 0;
375  unsigned long seq;
376
377  if (cpu_self == 0) {
378    while (assert_state(ctx, START_TEST)) {
379      seq = _SMP_sequence_lock_Write_begin(&ctx->seq_lock);
380
381      ctx->a = counter;
382      ctx->b = counter;
383
384      _SMP_sequence_lock_Write_end(&ctx->seq_lock, seq);
385
386      ++counter;
387    }
388  } else {
389    while (assert_state(ctx, START_TEST)) {
390      unsigned long a;
391      unsigned long b;
392
393      do {
394        seq = _SMP_sequence_lock_Read_begin(&ctx->seq_lock);
395
396        a = ctx->a;
397        b = ctx->b;
398
399      } while (_SMP_sequence_lock_Read_retry(&ctx->seq_lock, seq));
400
401      ++counter;
402      rtems_test_assert(a == b);
403    }
404  }
405
406  ctx->test_counter[test][cpu_self] = counter;
407}
408
409static const test_body test_bodies[TEST_COUNT] = {
410  test_0_body,
411  test_1_body,
412  test_2_body,
413  test_3_body,
414  test_4_body,
415  test_5_body,
416  test_6_body,
417  test_7_body,
418  test_8_body,
419  test_9_body,
420  test_10_body
421};
422
423static void run_tests(
424  global_context *ctx,
425  SMP_barrier_State *bs,
426  unsigned int cpu_count,
427  unsigned int cpu_self,
428  bool master
429)
430{
431  int test;
432
433  for (test = 0; test < TEST_COUNT; ++test) {
434    _SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
435
436    if (master) {
437      rtems_status_code sc = rtems_timer_fire_after(
438        ctx->timer_id,
439        ctx->timeout,
440        stop_test_timer,
441        ctx
442      );
443      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
444
445      _Atomic_Store_uint(&ctx->state, START_TEST, ATOMIC_ORDER_RELEASE);
446    }
447
448    wait_for_state(ctx, START_TEST);
449
450    (*test_bodies[test])(test, ctx, bs, cpu_count, cpu_self);
451  }
452
453  _SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
454}
455
456static void task(rtems_task_argument arg)
457{
458  global_context *ctx = (global_context *) arg;
459  uint32_t cpu_count = rtems_get_processor_count();
460  uint32_t cpu_self = rtems_get_current_processor();
461  rtems_status_code sc;
462  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
463
464  run_tests(ctx, &bs, cpu_count, cpu_self, false);
465
466  sc = rtems_task_suspend(RTEMS_SELF);
467  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
468}
469
470static void test(void)
471{
472  global_context *ctx = &context;
473  uint32_t cpu_count = rtems_get_processor_count();
474  uint32_t cpu_self = rtems_get_current_processor();
475  uint32_t cpu;
476  int test;
477  rtems_status_code sc;
478  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
479
480  for (cpu = 0; cpu < cpu_count; ++cpu) {
481    if (cpu != cpu_self) {
482      rtems_id task_id;
483
484      sc = rtems_task_create(
485        rtems_build_name('T', 'A', 'S', 'K'),
486        TASK_PRIORITY,
487        RTEMS_MINIMUM_STACK_SIZE,
488        RTEMS_DEFAULT_MODES,
489        RTEMS_DEFAULT_ATTRIBUTES,
490        &task_id
491      );
492      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
493
494      sc = rtems_task_start(task_id, task, (rtems_task_argument) ctx);
495      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
496    }
497  }
498
499  ctx->timeout = 5 * rtems_clock_get_ticks_per_second();
500
501  sc = rtems_timer_create(rtems_build_name('T', 'I', 'M', 'R'), &ctx->timer_id);
502  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
503
504  run_tests(ctx, &bs, cpu_count, cpu_self, true);
505
506  for (test = 0; test < TEST_COUNT; ++test) {
507    unsigned long sum = 0;
508
509    printf("%s\n", test_names[test]);
510
511    for (cpu = 0; cpu < cpu_count; ++cpu) {
512      unsigned long local_counter = ctx->test_counter[test][cpu];
513
514      sum += local_counter;
515
516      printf(
517        "\tprocessor %" PRIu32 ", local counter %lu\n",
518        cpu,
519        local_counter
520      );
521    }
522
523    printf(
524      "\tglobal counter %lu, sum of local counter %lu\n",
525      ctx->counter[test],
526      sum
527    );
528  }
529}
530
531static void Init(rtems_task_argument arg)
532{
533  TEST_BEGIN();
534
535  test();
536
537  TEST_END();
538  rtems_test_exit(0);
539}
540
541#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
542#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
543
544#define CONFIGURE_SMP_APPLICATION
545
546#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
547
548#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
549
550#define CONFIGURE_MAXIMUM_SEMAPHORES 1
551
552#define CONFIGURE_MAXIMUM_TIMERS 1
553
554#define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY
555#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
556#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
557
558#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
559
560#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
561
562#define CONFIGURE_INIT
563
564#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.