source: rtems/testsuites/smptests/smplock01/init.c @ 41ce30a

5
Last change on this file since 41ce30a was 41ce30a, checked in by Sebastian Huber <sebastian.huber@…>, on 05/18/16 at 12:34:26

SMP: Add Mellor-Crummey and Scott (MCS) lock

Added only for evaluation purposes. We have to compare the performance
against the ticket lock on the interesting platforms via
smptests/smplock01.

The following GCC shortcoming affects the MCS lock:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66867

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