source: rtems/testsuites/tmtests/tmcontext01/init.c @ d50acdbb

4.11
Last change on this file since d50acdbb was d50acdbb, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 10, 2014 at 7:25:32 AM

score: Add local context to SMP lock API

Add a local context structure to the SMP lock API for acquire and
release pairs. This context can be used to store the ISR level and
profiling information. It may be later used to enable more
sophisticated lock algorithms, e.g. MCS locks.

There is only one lock that cannot be used with a local context. This
is the per-CPU lock since here we would have to transfer the local
context through a context switch which is very complicated.

  • Property mode set to 100644
File size: 5.5 KB
Line 
1/*
2 * Copyright (c) 2014 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/counter.h>
20#include <rtems.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <inttypes.h>
25#include <alloca.h>
26
27#include "tmacros.h"
28
29#define FUNCTION_LEVELS 16
30
31#define SAMPLES 123
32
33#define CPU_COUNT 32
34
35static rtems_counter_ticks t[SAMPLES];
36
37static volatile bool always_true = true;
38
39static size_t data_size;
40
41static volatile int *main_data;
42
43static Context_Control ctx;
44
45static void dirty_data_cache(volatile int *d)
46{
47  size_t n = data_size / sizeof(*d);
48  size_t i;
49
50  for (i = 0; i < n; ++i) {
51    d[i] = i;
52  }
53}
54
55static int prevent_opt_func(int m, int n)
56{
57  if (m == 0) {
58    return n + 1;
59  } else if (m > 0 && n == 0) {
60    return prevent_opt_func(m - 1, 1);
61  } else {
62    return prevent_opt_func(m - 1, prevent_opt_func(m, n - 1));
63  }
64}
65
66static int call_at_level(int start, int fl, int s, bool dirty)
67{
68  if (fl == start) {
69    /*
70     * Some architectures like the SPARC have register windows.  A side-effect
71     * of this context switch is that we start with a fresh window set.  On
72     * architectures like ARM or PowerPC this context switch has no effect.
73     */
74    _Context_Switch(&ctx, &ctx);
75  }
76
77  if (fl > 0) {
78    if (always_true) {
79      return call_at_level(start, fl - 1, s, dirty);
80    } else {
81      return prevent_opt_func(fl - 1, fl - 2);
82    }
83  } else {
84    char *volatile space;
85    rtems_counter_ticks a;
86    rtems_counter_ticks b;
87
88    if (dirty) {
89      dirty_data_cache(main_data);
90      rtems_cache_invalidate_entire_instruction();
91    }
92
93    a = rtems_counter_read();
94
95    /* Ensure that we use an untouched stack area */
96    space = alloca(1024);
97    (void) space;
98
99    _Context_Switch(&ctx, &ctx);
100
101    b = rtems_counter_read();
102    t[s] = rtems_counter_difference(b, a);
103
104    return 0;
105  }
106}
107
108static void load_task(rtems_task_argument arg)
109{
110  volatile int *load_data = (volatile int *) arg;
111
112  while (true) {
113    dirty_data_cache(load_data);
114  }
115}
116
117static int cmp(const void *ap, const void *bp)
118{
119  const rtems_counter_ticks *a = ap;
120  const rtems_counter_ticks *b = bp;
121
122  return *a - *b;
123}
124
125static void sort_t(void)
126{
127  qsort(&t[0], SAMPLES, sizeof(t[0]), cmp);
128}
129
130static void test_by_function_level(int fl, bool dirty)
131{
132  rtems_interrupt_lock lock = RTEMS_INTERRUPT_LOCK_INITIALIZER;
133  rtems_interrupt_lock_context lock_context;
134  int s;
135  uint64_t min;
136  uint64_t q1;
137  uint64_t q2;
138  uint64_t q3;
139  uint64_t max;
140
141  rtems_interrupt_lock_acquire(&lock, &lock_context);
142
143  for (s = 0; s < SAMPLES; ++s) {
144    call_at_level(fl, fl, s, dirty);
145  }
146
147  rtems_interrupt_lock_release(&lock, &lock_context);
148
149  sort_t();
150
151  min = t[0];
152  q1 = t[(1 * SAMPLES) / 4];
153  q2 = t[SAMPLES / 2];
154  q3 = t[(3 * SAMPLES) / 4];
155  max = t[SAMPLES - 1];
156
157  printf(
158    "    <Sample functionNestLevel=\"%i\">\n"
159    "      <Min unit=\"ns\">%" PRIu64 "</Min>"
160      "<Q1 unit=\"ns\">%" PRIu64 "</Q1>"
161      "<Q2 unit=\"ns\">%" PRIu64 "</Q2>"
162      "<Q3 unit=\"ns\">%" PRIu64 "</Q3>"
163      "<Max unit=\"ns\">%" PRIu64 "</Max>\n"
164    "    </Sample>\n",
165    fl,
166    rtems_counter_ticks_to_nanoseconds(min),
167    rtems_counter_ticks_to_nanoseconds(q1),
168    rtems_counter_ticks_to_nanoseconds(q2),
169    rtems_counter_ticks_to_nanoseconds(q3),
170    rtems_counter_ticks_to_nanoseconds(max)
171  );
172}
173
174static void test(bool dirty, uint32_t load)
175{
176  int fl;
177
178  printf(
179    "  <ContextSwitchTest environment=\"%s\"",
180    dirty ? "dirty" : "normal"
181  );
182
183  if (load > 0) {
184    printf(" load=\"%" PRIu32 "\"", load);
185  }
186
187  printf(">\n");
188
189  for (fl = 0; fl < FUNCTION_LEVELS; ++fl) {
190    test_by_function_level(fl, dirty);
191  }
192
193  printf("  </ContextSwitchTest>\n");
194}
195
196static void Init(rtems_task_argument arg)
197{
198  uint32_t load = 0;
199
200  printf(
201    "\n"
202    "\n"
203    "<?xml version=\"1.0\"?>\n"
204    "<!-- *** TEST TMCONTEXT 1 *** -->\n"
205    "<Test>\n"
206  );
207
208  data_size = rtems_cache_get_data_cache_size(0);
209  if (data_size > 0) {
210    main_data = malloc(data_size);
211    rtems_test_assert(main_data != NULL);
212  }
213
214  test(false, load);
215  test(true, load);
216
217  for (load = 1; load < rtems_smp_get_processor_count(); ++load) {
218    rtems_status_code sc;
219    rtems_id id;
220    volatile int *load_data = NULL;
221
222    if (data_size > 0) {
223      load_data = malloc(data_size);
224      if (load_data == NULL) {
225        load_data = main_data;
226      }
227    }
228
229    sc = rtems_task_create(
230      rtems_build_name('L', 'O', 'A', 'D'),
231      1,
232      RTEMS_MINIMUM_STACK_SIZE,
233      RTEMS_DEFAULT_MODES,
234      RTEMS_DEFAULT_ATTRIBUTES,
235      &id
236    );
237    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
238
239    sc = rtems_task_start(id, load_task, (rtems_task_argument) load_data);
240    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
241
242    test(true, load);
243  }
244
245  printf(
246    "</Test>\n"
247    "<!-- *** END OF TEST TMCONTEXT 1 *** -->\n"
248  );
249
250  rtems_test_exit(0);
251}
252
253/*
254 * Do not use a clock driver, since this will disturb the test in the "normal"
255 * environment.
256 */
257#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
258
259#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
260
261#define CONFIGURE_MAXIMUM_TASKS (1 + CPU_COUNT)
262
263#define CONFIGURE_INIT_TASK_STACK_SIZE (32 * 1024)
264
265#define CONFIGURE_SMP_APPLICATION
266
267#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
268
269#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
270
271#define CONFIGURE_INIT
272
273#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.