[PATCH 02/12] spcache01: Add test for multiprocessor extensions
Ralf Kirchner
ralf.kirchner at embedded-brains.de
Tue May 27 14:44:35 UTC 2014
Add test which ensures that a cache invalidate executed by one processor is seen by another processor
---
testsuites/sptests/spcache01/init.c | 209 +++++++++++++++++++++++++++++++----
1 Datei geändert, 185 Zeilen hinzugefügt(+), 24 Zeilen entfernt(-)
diff --git a/testsuites/sptests/spcache01/init.c b/testsuites/sptests/spcache01/init.c
index 303f7f6..99f5ec4 100644
--- a/testsuites/sptests/spcache01/init.c
+++ b/testsuites/sptests/spcache01/init.c
@@ -21,6 +21,8 @@
#include <rtems.h>
#include <rtems/counter.h>
+#include <rtems/score/smpbarrier.h>
+#include <rtems/rtems/smp.h>
#define TESTS_USE_PRINTF
#include "tmacros.h"
@@ -35,7 +37,145 @@ 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( const bool write_through )
+{
+#if defined( RTEMS_SMP )
+ if( ( ! write_through ) && ( rtems_get_processor_count() > 1 ) ) {
+ 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 +183,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 +322,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 +381,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 +443,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 +461,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 +550,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 +570,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 +587,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 +638,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 +658,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 +698,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 +718,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 +802,24 @@ static void Init(rtems_task_argument arg)
write_through = test_data_flush_and_invalidate();
test_misalignment( write_through );
test_timing();
+ test_multiprocessor_extensions(write_through);
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