source: rtems/testsuites/sptests/spcache01/init.c @ 7e5c9b89

4.11
Last change on this file since 7e5c9b89 was 7e5c9b89, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 25, 2014 at 1:58:13 PM

rtems: Move rtems_cache_aligned_malloc()

Make sure also the size is cache aligned since otherwise we may have
some overlap with the next allocation block. A cache invalidate on this
area would be fatal.

  • Property mode set to 100644
File size: 9.9 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.org/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <inttypes.h>
22
23#include <rtems.h>
24#include <rtems/counter.h>
25
26#define TESTS_USE_PRINTF
27#include "tmacros.h"
28
29const char rtems_test_name[] = "SPCACHE 1";
30
31#ifdef __or1k__
32  #define I() __asm__ volatile ("l.nop")
33#else
34  #define I() __asm__ volatile ("nop")
35#endif
36
37#define I8() I(); I(); I(); I(); I(); I(); I(); I()
38
39#define I64() I8(); I8(); I8(); I8(); I8(); I8(); I8(); I8()
40
41#define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64()
42
43CPU_STRUCTURE_ALIGNMENT static int data[1024];
44
45static void test_data_flush_and_invalidate(void)
46{
47  if (rtems_cache_get_data_line_size() > 0) {
48    rtems_interrupt_lock lock;
49    rtems_interrupt_lock_context lock_context;
50    volatile int *vdata = &data[0];
51    int n = 32;
52    int i;
53    size_t data_size = n * sizeof(data[0]);
54    bool write_through;
55
56    printf("data cache flush and invalidate test\n");
57
58    rtems_interrupt_lock_initialize(&lock, "test");
59    rtems_interrupt_lock_acquire(&lock, &lock_context);
60
61    for (i = 0; i < n; ++i) {
62      vdata[i] = i;
63    }
64
65    rtems_cache_flush_multiple_data_lines(&data[0], data_size);
66
67    for (i = 0; i < n; ++i) {
68      rtems_test_assert(vdata[i] == i);
69    }
70
71    for (i = 0; i < n; ++i) {
72      vdata[i] = ~i;
73    }
74
75    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
76
77    write_through = vdata[0] == ~0;
78    if (write_through) {
79      for (i = 0; i < n; ++i) {
80        rtems_test_assert(vdata[i] == ~i);
81      }
82    } else {
83      for (i = 0; i < n; ++i) {
84        rtems_test_assert(vdata[i] == i);
85      }
86    }
87
88    for (i = 0; i < n; ++i) {
89      vdata[i] = ~i;
90    }
91
92    rtems_cache_flush_multiple_data_lines(&data[0], data_size);
93    rtems_cache_invalidate_multiple_data_lines(&data[0], data_size);
94
95    for (i = 0; i < n; ++i) {
96      rtems_test_assert(vdata[i] == ~i);
97    }
98
99    rtems_interrupt_lock_release(&lock, &lock_context);
100    rtems_interrupt_lock_destroy(&lock);
101
102    printf(
103      "data cache operations by line passed the test (%s cache detected)\n",
104      write_through ? "write-through" : "copy-back"
105    );
106  } else {
107    printf(
108      "skip data cache flush and invalidate test"
109        " due to cache line size of zero\n"
110    );
111  }
112
113  /* Make sure these are nops */
114  rtems_cache_flush_multiple_data_lines(NULL, 0);
115  rtems_cache_invalidate_multiple_data_lines(NULL, 0);
116}
117
118static uint64_t do_some_work(void)
119{
120  rtems_counter_ticks a;
121  rtems_counter_ticks b;
122  rtems_counter_ticks d;
123
124  /* This gives 1024 nop instructions */
125  a = rtems_counter_read();
126  I512();
127  I512();
128  b = rtems_counter_read();
129
130  d = rtems_counter_difference(b, a);
131
132  return rtems_counter_ticks_to_nanoseconds(d);
133}
134
135static uint64_t load(void)
136{
137  rtems_counter_ticks a;
138  rtems_counter_ticks b;
139  rtems_counter_ticks d;
140  size_t i;
141  volatile int *vdata = &data[0];
142
143  a = rtems_counter_read();
144  for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
145    vdata[i];
146  }
147  b = rtems_counter_read();
148
149  d = rtems_counter_difference(b, a);
150
151  return rtems_counter_ticks_to_nanoseconds(d);
152}
153
154static uint64_t store(void)
155{
156  rtems_counter_ticks a;
157  rtems_counter_ticks b;
158  rtems_counter_ticks d;
159  size_t i;
160  volatile int *vdata = &data[0];
161
162  a = rtems_counter_read();
163  for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
164    vdata[i] = 0;
165  }
166  b = rtems_counter_read();
167
168  d = rtems_counter_difference(b, a);
169
170  return rtems_counter_ticks_to_nanoseconds(d);
171}
172
173static void test_timing(void)
174{
175  rtems_interrupt_lock lock;
176  rtems_interrupt_lock_context lock_context;
177  size_t data_size = sizeof(data);
178  uint64_t d[3];
179  uint32_t cache_level;
180  size_t cache_size;
181
182  rtems_interrupt_lock_initialize(&lock, "test");
183
184  printf(
185    "data cache line size %zi bytes\n"
186    "data cache size %zi bytes\n",
187    rtems_cache_get_data_line_size(),
188    rtems_cache_get_data_cache_size(0)
189  );
190
191  cache_level = 1;
192  cache_size = rtems_cache_get_data_cache_size(cache_level);
193  while (cache_size > 0) {
194    printf(
195      "data cache level %" PRIu32 " size %zi bytes\n",
196      cache_level,
197      cache_size
198    );
199    ++cache_level;
200    cache_size = rtems_cache_get_data_cache_size(cache_level);
201  }
202
203  rtems_interrupt_lock_acquire(&lock, &lock_context);
204
205  d[0] = load();
206  d[1] = load();
207  rtems_cache_flush_entire_data();
208  d[2] = load();
209
210  rtems_interrupt_lock_release(&lock, &lock_context);
211
212  printf(
213    "load %zi bytes with flush entire data\n"
214    "  duration with normal cache %" PRIu64 " ns\n"
215    "  duration with warm cache %" PRIu64 " ns\n"
216    "  duration with flushed cache %" PRIu64 " ns\n",
217    data_size,
218    d[0],
219    d[1],
220    d[2]
221  );
222
223  rtems_interrupt_lock_acquire(&lock, &lock_context);
224
225  d[0] = load();
226  d[1] = load();
227  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
228  d[2] = load();
229
230  rtems_interrupt_lock_release(&lock, &lock_context);
231
232  printf(
233    "load %zi bytes with flush multiple data\n"
234    "  duration with normal cache %" PRIu64 " ns\n"
235    "  duration with warm cache %" PRIu64 " ns\n"
236    "  duration with flushed cache %" PRIu64 " ns\n",
237    data_size,
238    d[0],
239    d[1],
240    d[2]
241  );
242
243  rtems_interrupt_lock_acquire(&lock, &lock_context);
244
245  d[0] = load();
246  d[1] = load();
247  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
248  d[2] = load();
249
250  rtems_interrupt_lock_release(&lock, &lock_context);
251
252  printf(
253    "load %zi bytes with invalidate multiple data\n"
254    "  duration with normal cache %" PRIu64 " ns\n"
255    "  duration with warm cache %" PRIu64 " ns\n"
256    "  duration with invalidated cache %" PRIu64 " ns\n",
257    data_size,
258    d[0],
259    d[1],
260    d[2]
261  );
262
263  rtems_interrupt_lock_acquire(&lock, &lock_context);
264
265  d[0] = store();
266  d[1] = store();
267  rtems_cache_flush_entire_data();
268  d[2] = store();
269
270  rtems_interrupt_lock_release(&lock, &lock_context);
271
272  printf(
273    "store %zi bytes with flush entire data\n"
274    "  duration with normal cache %" PRIu64 " ns\n"
275    "  duration with warm cache %" PRIu64 " ns\n"
276    "  duration with flushed cache %" PRIu64 " ns\n",
277    data_size,
278    d[0],
279    d[1],
280    d[2]
281  );
282
283  rtems_interrupt_lock_acquire(&lock, &lock_context);
284
285  d[0] = store();
286  d[1] = store();
287  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
288  d[2] = store();
289
290  rtems_interrupt_lock_release(&lock, &lock_context);
291
292  printf(
293    "store %zi bytes with flush multiple data\n"
294    "  duration with normal cache %" PRIu64 " ns\n"
295    "  duration with warm cache %" PRIu64 " ns\n"
296    "  duration with flushed cache %" PRIu64 " ns\n",
297    data_size,
298    d[0],
299    d[1],
300    d[2]
301  );
302
303  rtems_interrupt_lock_acquire(&lock, &lock_context);
304
305  d[0] = store();
306  d[1] = store();
307  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
308  d[2] = store();
309
310  rtems_interrupt_lock_release(&lock, &lock_context);
311
312  printf(
313    "store %zi bytes with invalidate multiple data\n"
314    "  duration with normal cache %" PRIu64 " ns\n"
315    "  duration with warm cache %" PRIu64 " ns\n"
316    "  duration with invalidated cache %" PRIu64 " ns\n",
317    data_size,
318    d[0],
319    d[1],
320    d[2]
321  );
322
323  printf(
324    "instruction cache line size %zi bytes\n"
325    "instruction cache size %zi bytes\n",
326    rtems_cache_get_instruction_line_size(),
327    rtems_cache_get_instruction_cache_size(0)
328  );
329
330  cache_level = 1;
331  cache_size = rtems_cache_get_instruction_cache_size(cache_level);
332  while (cache_size > 0) {
333    printf(
334      "instruction cache level %" PRIu32 " size %zi bytes\n",
335      cache_level,
336      cache_size
337    );
338    ++cache_level;
339    cache_size = rtems_cache_get_instruction_cache_size(cache_level);
340  }
341
342  rtems_interrupt_lock_acquire(&lock, &lock_context);
343
344  d[0] = do_some_work();
345  d[1] = do_some_work();
346  rtems_cache_invalidate_entire_instruction();
347  d[2] = do_some_work();
348
349  rtems_interrupt_lock_release(&lock, &lock_context);
350
351  printf(
352    "invalidate entire instruction\n"
353    "  duration with normal cache %" PRIu64 " ns\n"
354    "  duration with warm cache %" PRIu64 " ns\n"
355    "  duration with invalidated cache %" PRIu64 " ns\n",
356    d[0],
357    d[1],
358    d[2]
359  );
360
361  rtems_interrupt_lock_acquire(&lock, &lock_context);
362
363  d[0] = do_some_work();
364  d[1] = do_some_work();
365  rtems_cache_invalidate_multiple_instruction_lines(do_some_work, 4096);
366  d[2] = do_some_work();
367
368  rtems_interrupt_lock_release(&lock, &lock_context);
369
370  printf(
371    "invalidate multiple instruction\n"
372    "  duration with normal cache %" PRIu64 " ns\n"
373    "  duration with warm cache %" PRIu64 " ns\n"
374    "  duration with invalidated cache %" PRIu64 " ns\n",
375    d[0],
376    d[1],
377    d[2]
378  );
379
380  rtems_interrupt_lock_destroy(&lock);
381}
382
383static void test_cache_aligned_alloc(void)
384{
385  void *p0;
386  void *p1;
387  size_t cls;
388
389  printf("test rtems_cache_aligned_malloc()\n");
390
391  p0 = rtems_cache_aligned_malloc(1);
392  p1 = rtems_cache_aligned_malloc(1);
393
394  rtems_test_assert(p0 != NULL);
395  rtems_test_assert(p1 != NULL);
396
397  cls = rtems_cache_get_data_line_size();
398  if (cls > 0) {
399    size_t m = cls - 1;
400    uintptr_t a0 = (uintptr_t) p0;
401    uintptr_t a1 = (uintptr_t) p1;
402
403    rtems_test_assert(a1 - a0 > cls);
404    rtems_test_assert((a0 & m) == 0);
405    rtems_test_assert((a1 & m) == 0);
406  }
407
408  free(p0);
409  free(p1);
410}
411
412static void Init(rtems_task_argument arg)
413{
414  TEST_BEGIN();
415
416  test_data_flush_and_invalidate();
417  test_timing();
418  test_cache_aligned_alloc();
419
420  TEST_END();
421
422  rtems_test_exit(0);
423}
424
425#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
426#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
427
428#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
429
430#define CONFIGURE_MAXIMUM_TASKS 1
431
432#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
433
434#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
435
436#define CONFIGURE_INIT
437
438#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.