As pointed by Lorenzo, when a cpu powers down, the L1 cache must be flushed
before, otherwise:

 * data cachelines are not empty and the other cpu may fetch data
 * cpu will lost some data leading to a memory corruption

Note this bug is very difficult to reproduce and this test will not spot the
issue everytime.

Signed-off-by: Daniel Lezcano <daniel.lezc...@linaro.org>
---
 cpuidle/cpuidle-l1.c   |   72 ++++++++++++++++++++++++++++++++++++++++++++++++
 cpuidle/cpuidle_05.sh  |   42 ++++++++++++++++++++++++++++
 cpuidle/cpuidle_05.txt |    1 +
 3 files changed, 115 insertions(+)
 create mode 100644 cpuidle/cpuidle-l1.c
 create mode 100755 cpuidle/cpuidle_05.sh
 create mode 100644 cpuidle/cpuidle_05.txt

diff --git a/cpuidle/cpuidle-l1.c b/cpuidle/cpuidle-l1.c
new file mode 100644
index 0000000..bbcde28
--- /dev/null
+++ b/cpuidle/cpuidle-l1.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <pthread.h>
+#define BUFSIZE (4*1024)
+#define DEADBEEF 0xDEADBEEF
+static int buffer[BUFSIZE];
+
+static pthread_t threads[64];
+
+void *thread_routine(void *arg)
+{
+       int i, display = *(int *)arg;
+       int dummy;
+
+       for (i = 0; i < 100; i++) {
+
+               int j;
+               
+               for (j = 0; j < BUFSIZE * 1000; j++) {
+                       dummy = buffer[j % BUFSIZE];
+                       dummy++;
+               }
+       
+               usleep(200000);
+               
+               if (buffer[i] != DEADBEEF) {
+                       fprintf(stderr, "memory corruption\n");
+                       return (void *)-1;
+               }
+
+               if (display == 0)
+                       printf("%d%%%s", i, i < 10 ? "\b\b" : "\b\b\b");
+       }
+
+       if (display == 0)
+               printf("    \b\b\b\b");
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       int i, ret = 0;
+       int nrcpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       for (i = 0; i < BUFSIZE; i++)
+               buffer[i] = DEADBEEF;
+
+       setbuf(stdout, NULL);
+
+       for(i = 0; i < nrcpus; i++) {
+
+               if (pthread_create(&threads[i], NULL, thread_routine, &i)) {
+                       perror("pthread_create");
+                       return 1;
+               }
+
+       }
+
+       for (i = 0; i < nrcpus; i++) {
+               void *result;
+               pthread_join(threads[i], &result);
+
+               if (result == (void *)-1)
+                       ret = 1;
+       }
+
+       return ret;     
+}
diff --git a/cpuidle/cpuidle_05.sh b/cpuidle/cpuidle_05.sh
new file mode 100755
index 0000000..679439d
--- /dev/null
+++ b/cpuidle/cpuidle_05.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# PM-QA validation test suite for the power management on Linux
+#
+# Copyright (C) 2011, Linaro Limited.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
+#
+# Contributors:
+#     Daniel Lezcano <daniel.lezc...@linaro.org> (IBM Corporation)
+#       - initial API and implementation
+#
+
+# URL : 
https://wiki.linaro.org/WorkingGroups/PowerManagement/Resources/TestSuite/PmQaSpecification#cpuidle_05
+
+source ../include/functions.sh
+
+CPUIDLE_L1=./cpuidle-l1
+
+if [ $(id -u) -ne 0 ]; then
+    log_skip "run as non-root"
+    exit 0
+fi
+
+check_cpuidle_l1() {
+    check "Fill L1 cache and sleep" "./$CPUIDLE_L1"
+}
+
+check_cpuidle_l1
+test_status_show
diff --git a/cpuidle/cpuidle_05.txt b/cpuidle/cpuidle_05.txt
new file mode 100644
index 0000000..1f80e36
--- /dev/null
+++ b/cpuidle/cpuidle_05.txt
@@ -0,0 +1 @@
+Run cpuidle L1 test program to catch L1 flush missing vs cpu power down
-- 
1.7.9.5


_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to