[PATCH 1/2] spcache01: Add test for multiprocessor extensions

Ralf Kirchner ralf.kirchner at embedded-brains.de
Wed Apr 30 13:10:28 UTC 2014


Add test which ensures that a cache invalidate executed by one processor is seen by another processor
---
 testsuites/sptests/spcache01/init.c |  207 +++++++++++++++++++++++++++++++----
 1 Datei geändert, 183 Zeilen hinzugefügt(+), 24 Zeilen entfernt(-)

diff --git a/testsuites/sptests/spcache01/init.c b/testsuites/sptests/spcache01/init.c
index 303f7f6..1d3607a 100644
--- a/testsuites/sptests/spcache01/init.c
+++ b/testsuites/sptests/spcache01/init.c
@@ -21,6 +21,7 @@
 
 #include <rtems.h>
 #include <rtems/counter.h>
+#include <rtems/score/smpbarrier.h>
 
 #define TESTS_USE_PRINTF
 #include "tmacros.h"
@@ -35,7 +36,144 @@ const char rtems_test_name[] = "SPCACHE 1";
 
 #define I512() I64(); I64(); I64(); I64(); I64(); I64(); I64(); I64()
 
-CPU_STRUCTURE_ALIGNMENT static int data[1024];
+#if defined( RTEMS_SMP )
+  #define TEST_SMP_TASK_COUNT 1
+#else
+  #define TEST_SMP_TASK_COUNT 0
+#endif /* defined( RTEMS_SMP ) */
+
+#define TEST_SMP_PROCESSOR_COUNT 2
+
+#define TASK_PRIORITY 1
+
+
+typedef struct {
+#if defined( RTEMS_SMP )
+  SMP_barrier_Control barrier;
+#endif /* defined( RTEMS_SMP ) */
+  CPU_STRUCTURE_ALIGNMENT int data[1024];
+} test_context;
+
+static test_context test_instance;
+
+#if defined( RTEMS_SMP )
+static rtems_task test_multiprocessor_extensions_task( rtems_task_argument arg )
+{
+  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
+  rtems_interrupt_lock lock;
+  rtems_interrupt_lock_context lock_context;
+  int *data = &test_instance.data[0];
+  
+  (void)arg;
+
+  
+  rtems_interrupt_lock_initialize(&lock, "test");
+  rtems_interrupt_lock_acquire(&lock, &lock_context);
+
+  /* Wait for the other task to start it's initialization */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Make sure we don't have the cache line cached */
+  rtems_cache_invalidate_multiple_data_lines(
+    &data[0],
+    sizeof(data[0])
+  );
+
+  /* Wait for the other task to complete it's initialization */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Wait for the other task to complete preparations for the invalidation */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Now the other task should also get the cache line invalidated */
+  rtems_cache_invalidate_multiple_data_lines(
+    &data[0],
+    sizeof(data[0])
+  );
+
+  /* Signal that we have completed the invalidation */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  rtems_interrupt_lock_release(&lock, &lock_context);
+  rtems_interrupt_lock_destroy(&lock);
+
+  rtems_task_delete(RTEMS_SELF);
+}
+#endif /* defined( RTEMS_SMP ) */
+
+static void test_multiprocessor_extensions( void )
+{
+#if defined( RTEMS_SMP )
+  rtems_interrupt_lock lock;
+  rtems_interrupt_lock_context lock_context;
+  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
+  rtems_id id_work1 = RTEMS_ID_NONE;
+  int *tdata = &test_instance.data[0];
+  volatile int *vdata = &test_instance.data[0];
+  rtems_status_code sc;
+  const int PATTERN = 0x89ABCDEF;
+
+  printf("test for multiprocessor extensions handling\n");
+
+  _SMP_barrier_Control_initialize( &test_instance.barrier );
+  
+  rtems_interrupt_lock_initialize(&lock, "test");
+  rtems_interrupt_lock_acquire(&lock, &lock_context);
+
+  /* Create and start another task for our test. As we are under SMP conditions,
+   * this new task will be operating on another processor */
+  sc = rtems_task_create(
+    rtems_build_name('W', 'R', 'K', '1'),
+                         TASK_PRIORITY,
+                         RTEMS_MINIMUM_STACK_SIZE,
+                         RTEMS_DEFAULT_MODES,
+                         RTEMS_DEFAULT_ATTRIBUTES,
+                         &id_work1
+  );
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  sc = rtems_task_start(id_work1, test_multiprocessor_extensions_task, 0);
+  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
+
+  /* Permit the other task to start it's initialization */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Make sure we don't have the cache line cached */
+  rtems_cache_invalidate_multiple_data_lines(
+    &tdata[0],
+    sizeof(tdata[0])
+  );
+
+  /* Wait for the other task to complete it's initialization */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Initialize */
+  vdata[0] = PATTERN;
+
+  /* Flush initialized cache line to RAM */
+  rtems_cache_flush_multiple_data_lines(
+    &tdata[0],
+    sizeof(tdata[0])
+  );
+
+  /* Modify cache line in cache only */
+  vdata[0] = ~PATTERN;
+
+  /* Have the other task invalidate the cache line */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* Wait for the complation of the invalidation by the other task */
+  _SMP_barrier_Wait(&test_instance.barrier, &bs, TEST_SMP_PROCESSOR_COUNT);
+
+  /* The other task has invalidated the cache, thus we should read what was flushed to RAM */
+  rtems_test_assert(vdata[0] == PATTERN);
+
+  rtems_interrupt_lock_release(&lock, &lock_context);
+  rtems_interrupt_lock_destroy(&lock);
+
+  printf("test for multiprocessor extensions passed\n");
+#endif /* defined( RTEMS_SMP ) */
+}
 
 static void test_misalignment( const bool write_through )
 {
@@ -43,12 +181,20 @@ static void test_misalignment( const bool write_through )
     rtems_interrupt_lock lock;
     rtems_interrupt_lock_context lock_context;
     const uint32_t LINE_SIZE  = rtems_cache_get_data_line_size();
-    volatile int *vdata = &data[0]; /* Verification start address */
-    int *tdata = &data[LINE_SIZE / sizeof(data[0])]; /* test start address (first word in second cache line) */
+    int *data = &data[0];
+    /* Verification start address */
+    volatile int *vdata = data;
+    /* test start address (first word in second cache line) */
+    int *tdata = &data[LINE_SIZE / sizeof(data[0])];
     int tcount = 1; /* Words to be tested */
-    size_t tdata_bytes = tcount * sizeof(data[0]); /* Bytes to be tested */
-    size_t vdata_bytes = LINE_SIZE; /* Bytes expected to be affected by cache maintenance */
-    int vcount = (vdata_bytes / sizeof(data[0])) + (2 * LINE_SIZE / sizeof(data[0])); /* Words to be verified (Words affected + 2 adjacent cache lines) */
+    /* Bytes to be tested */
+    size_t tdata_bytes = tcount * sizeof(data[0]);
+    /* Bytes expected to be affected by cache maintenance */
+    size_t vdata_bytes = LINE_SIZE;
+    /* Words to be verified (Words affected + 2 adjacent cache lines) */
+    int vcount =
+      (vdata_bytes / sizeof(data[0]))
+      + (2 * LINE_SIZE / sizeof(data[0]));
     int i;
     int end;
 
@@ -174,7 +320,8 @@ static void test_misalignment( const bool write_through )
      * The modified line shall get invalidated/flushed entirely,
      * adjacent cache lines shall remain unchanged.
      */
-    tdata = &data[(LINE_SIZE / sizeof(data[0])) + ((LINE_SIZE / sizeof(data[0])) -1)];
+    tdata = &data[(LINE_SIZE / sizeof(data[0]))
+                  + ((LINE_SIZE / sizeof(data[0])) -1)];
 
     for (i = 0; i < vcount; ++i) {
       vdata[i] = i;
@@ -232,10 +379,12 @@ static void test_misalignment( const bool write_through )
      * The modified lines shall get invalidated/flushed entirely,
      * adjacent cache lines shall remain unchanged.
      */
-    tdata = &data[(LINE_SIZE / sizeof(data[0])) + ((LINE_SIZE / sizeof(data[0])) -1)];
+    tdata = &data[(LINE_SIZE / sizeof(data[0]))
+                  + ((LINE_SIZE / sizeof(data[0])) -1)];
     vdata_bytes = LINE_SIZE * 2;
     tcount = 2;
-    vcount = (vdata_bytes / sizeof(data[0])) + (2 * LINE_SIZE / sizeof(data[0]));
+    vcount = (vdata_bytes / sizeof(data[0]))
+             + (2 * LINE_SIZE / sizeof(data[0]));
     tdata_bytes = tcount * sizeof(data[0]);
 
     for (i = 0; i < vcount; ++i) {
@@ -292,13 +441,14 @@ static void test_misalignment( const bool write_through )
     rtems_interrupt_lock_destroy(&lock);
 
     printf(
-      "data cache operations with misaligned addresses passed the test (%s cache detected)\n",
-           write_through ? "write-through" : "copy-back"
+      "data cache operations with misaligned addresses passed the test "
+      "(%s cache detected)\n",
+      write_through ? "write-through" : "copy-back"
     );
   } else {
     printf(
-      "skip data cache flush and invalidate test with misaligned addresses"
-      " due to cache line size of zero\n"
+      "skip data cache flush and invalidate test with "
+      "misaligned addresses due to cache line size of zero\n"
     );
   }
 }
@@ -309,7 +459,8 @@ static bool test_data_flush_and_invalidate(void)
   if (rtems_cache_get_data_line_size() > 0) {
     rtems_interrupt_lock lock;
     rtems_interrupt_lock_context lock_context;
-    volatile int *vdata = &data[0];
+    int *data = &test_instance.data[0];
+    volatile int *vdata = data;
     int n = 32;
     int i;
     size_t data_size = n * sizeof(data[0]);
@@ -397,7 +548,8 @@ static uint64_t load(void)
   rtems_counter_ticks b;
   rtems_counter_ticks d;
   size_t i;
-  volatile int *vdata = &data[0];
+  int *data = &test_instance.data[0];
+  volatile int *vdata = data;
 
   a = rtems_counter_read();
   for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
@@ -416,10 +568,10 @@ static uint64_t store(void)
   rtems_counter_ticks b;
   rtems_counter_ticks d;
   size_t i;
-  volatile int *vdata = &data[0];
+  volatile int *vdata = &test_instance.data[0];
 
   a = rtems_counter_read();
-  for (i = 0; i < RTEMS_ARRAY_SIZE(data); ++i) {
+  for (i = 0; i < RTEMS_ARRAY_SIZE(test_instance.data); ++i) {
     vdata[i] = 0;
   }
   b = rtems_counter_read();
@@ -433,7 +585,8 @@ static void test_timing(void)
 {
   rtems_interrupt_lock lock;
   rtems_interrupt_lock_context lock_context;
-  size_t data_size = sizeof(data);
+  int *data = &test_instance.data[0];
+  size_t data_size = sizeof(test_instance.data);
   uint64_t d[3];
   uint32_t cache_level;
   size_t cache_size;
@@ -483,7 +636,7 @@ static void test_timing(void)
 
   d[0] = load();
   d[1] = load();
-  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
+  rtems_cache_flush_multiple_data_lines(data, sizeof(test_instance.data));
   d[2] = load();
 
   rtems_interrupt_lock_release(&lock, &lock_context);
@@ -503,7 +656,7 @@ static void test_timing(void)
 
   d[0] = load();
   d[1] = load();
-  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
+  rtems_cache_invalidate_multiple_data_lines(data, sizeof(test_instance.data));
   d[2] = load();
 
   rtems_interrupt_lock_release(&lock, &lock_context);
@@ -543,7 +696,7 @@ static void test_timing(void)
 
   d[0] = store();
   d[1] = store();
-  rtems_cache_flush_multiple_data_lines(&data[0], sizeof(data));
+  rtems_cache_flush_multiple_data_lines(data, sizeof(test_instance.data));
   d[2] = store();
 
   rtems_interrupt_lock_release(&lock, &lock_context);
@@ -563,7 +716,7 @@ static void test_timing(void)
 
   d[0] = store();
   d[1] = store();
-  rtems_cache_invalidate_multiple_data_lines(&data[0], sizeof(data));
+  rtems_cache_invalidate_multiple_data_lines(data, sizeof(test_instance.data));
   d[2] = store();
 
   rtems_interrupt_lock_release(&lock, &lock_context);
@@ -647,18 +800,24 @@ static void Init(rtems_task_argument arg)
   write_through = test_data_flush_and_invalidate();
   test_misalignment( write_through );
   test_timing();
+  test_multiprocessor_extensions();
 
   TEST_END();
 
   rtems_test_exit(0);
 }
 
-#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#if defined( RTEMS_SMP )
+  #define CONFIGURE_SMP_APPLICATION
+  #define CONFIGURE_SMP_MAXIMUM_PROCESSORS 32
+#endif /* defined( RTEMS_SMP ) */
+#define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
 #define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
 
 #define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
 
-#define CONFIGURE_MAXIMUM_TASKS 1
+#define CONFIGURE_MAXIMUM_TASKS (1 + TEST_SMP_TASK_COUNT)
 
 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
 
-- 
1.7.10.4




More information about the devel mailing list