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.lezcano@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.lezcano@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