aboutsummaryrefslogtreecommitdiff
path: root/cpuidle
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2012-04-05 14:03:08 +0200
committerzhanghongbo <hongbo.zhang@stericsson.com>2012-05-02 16:42:28 +0800
commit3dd53eedc22665ac9eee39cd62279294408b7c56 (patch)
treea1aa30f22cdc8b23007c6cbde3fb9daed5674444 /cpuidle
parent7c356293290656bd45b9b65a868dc22431dd4090 (diff)
add cpuidle_02 and cpuidle_03 tests
This patch provides a couple of tests for cpuidle in addition with a small program which behaves to sollicitate the cpuidle drivers especially when both cores needs to reach the same C-states. The program forks as many online processors present on the system and set the affinity to it. Then it runs, during 120 secs, small chunks of busy loops and idle loops. When there is something wrong with the cpuidle driver, this program often triggers the problem which results in a kernel panic, tasks hung warning or system hang. Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'cpuidle')
-rwxr-xr-xcpuidle/cpuidle_02.sh37
-rw-r--r--cpuidle/cpuidle_02.txt1
-rwxr-xr-xcpuidle/cpuidle_03.sh60
-rw-r--r--cpuidle/cpuidle_03.txt1
-rw-r--r--cpuidle/cpuidle_killer.c180
5 files changed, 279 insertions, 0 deletions
diff --git a/cpuidle/cpuidle_02.sh b/cpuidle/cpuidle_02.sh
new file mode 100755
index 0000000..1b155c1
--- /dev/null
+++ b/cpuidle/cpuidle_02.sh
@@ -0,0 +1,37 @@
+#!/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/Doc/QA/Scripts#cpuidle_02
+
+source ../include/functions.sh
+
+CPUIDLE_KILLER=./cpuidle_killer
+
+if [ $(id -u) != 0 ]; then
+ log_skip "run as non-root"
+ exit 0
+fi
+
+check "cpuidle program runs successfully (120 secs)" "./$CPUIDLE_KILLER"
diff --git a/cpuidle/cpuidle_02.txt b/cpuidle/cpuidle_02.txt
new file mode 100644
index 0000000..3f0b1ef
--- /dev/null
+++ b/cpuidle/cpuidle_02.txt
@@ -0,0 +1 @@
+Run a cpuidle program killer
diff --git a/cpuidle/cpuidle_03.sh b/cpuidle/cpuidle_03.sh
new file mode 100755
index 0000000..22bca10
--- /dev/null
+++ b/cpuidle/cpuidle_03.sh
@@ -0,0 +1,60 @@
+#!/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/Doc/QA/Scripts#cpuidle_03
+
+source ../include/functions.sh
+
+CPUIDLE_KILLER=./cpuidle_killer
+
+if [ $(id -u) != 0 ]; then
+ log_skip "run as non-root"
+ exit 0
+fi
+
+restore_cpus() {
+ for_each_cpu set_online
+}
+
+check_cpuidle_kill() {
+
+ if [ "$1" = "cpu0" ]; then
+ log_skip "skipping cpu0"
+ return 0
+ fi
+
+ set_offline $1
+ check "cpuidle program runs successfully (120 secs)" "./$CPUIDLE_KILLER"
+}
+
+if [ $(id -u) != 0 ]; then
+ log_skip "run as non-root"
+ exit 0
+fi
+
+trap "restore_cpus; sigtrap" SIGHUP SIGINT SIGTERM
+
+for_each_cpu check_cpuidle_kill
+restore_cpus
diff --git a/cpuidle/cpuidle_03.txt b/cpuidle/cpuidle_03.txt
new file mode 100644
index 0000000..1bf5c02
--- /dev/null
+++ b/cpuidle/cpuidle_03.txt
@@ -0,0 +1 @@
+Run a cpuidle program killer and unplug one by one the cpus (except cpu0)
diff --git a/cpuidle/cpuidle_killer.c b/cpuidle/cpuidle_killer.c
new file mode 100644
index 0000000..67a675e
--- /dev/null
+++ b/cpuidle/cpuidle_killer.c
@@ -0,0 +1,180 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sched.h>
+#include <signal.h>
+
+#define DURATION 120 /* seconds */
+#define SEC_TO_USEC(d) ((d) * 1000 * 1000)
+
+static int sigon;
+
+void sighandler(int sig)
+{
+ sigon = 1;
+}
+
+void timeout(int sig)
+{
+ printf("Test duration exceeded\n");
+ exit(1);
+}
+
+int tick_me(int nrsleeps, int delay, int cpu)
+{
+ int i;
+ cpu_set_t mask;
+ unsigned long counter = 0;
+ struct itimerval t = { };
+
+ CPU_ZERO(&mask);
+ CPU_SET(cpu, &mask);
+
+ /* stick on the specified cpu */
+ if (sched_setaffinity(getpid(), sizeof(mask), &mask)) {
+ fprintf(stderr, "sched_setaffinity (%d): %m", cpu);
+ return -1;
+ }
+
+ signal(SIGALRM, sighandler);
+
+ for (i = 0; i < nrsleeps / 2; i++) {
+ usleep(delay);
+
+ sigon = 0;
+ t.it_value.tv_sec = 0;
+ t.it_value.tv_usec = delay;
+
+ if (setitimer(ITIMER_REAL, &t, NULL)) {
+ perror("setitimer");
+ return 1;
+ }
+
+ while (!sigon)
+ counter++;
+ }
+
+ fprintf(stderr, "counter value %lu\n", counter);
+
+ return 0;
+}
+
+int isonline(int cpu)
+{
+ FILE *f;
+ char path[MAXPATHLEN];
+ int online;
+
+ if (!cpu)
+ return 1;
+
+ sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpu);
+
+ f = fopen(path, "r");
+ if (!f) {
+ perror("fopen");
+ return -1;
+ }
+
+ fscanf(f, "%d", &online);
+
+ fclose(f);
+
+ return online;
+}
+
+int main(int argc, char *argv[])
+{
+ int ret, i, nrcpus = 2;
+ int nrsleeps, delay;
+ pid_t pids[nrcpus];
+ struct timex timex = { 0 };
+
+ if (adjtimex(&timex) < 0) {
+ perror("adjtimex");
+ return 1;
+ }
+
+ fprintf(stderr, "jiffies are : %ld usecs\n", timex.tick);
+
+ nrcpus = sysconf(_SC_NPROCESSORS_CONF);
+ if (nrcpus < 0) {
+ perror("sysconf");
+ return 1;
+ }
+
+ fprintf(stderr, "found %d cpu(s)\n", nrcpus);
+
+ for (i = 0; i < nrcpus; i++) {
+
+ ret = isonline(i);
+ if (!ret) {
+ fprintf(stderr, "cpu%d is offline, ignoring\n", i);
+ continue;
+ }
+
+ pids[i] = fork();
+ if (pids[i] < 0) {
+ perror("fork");
+ return 1;
+ }
+
+ if (!pids[i]) {
+
+ struct timeval before, after;
+ long duration;
+ float deviation;
+
+ nrsleeps = SEC_TO_USEC(DURATION) / (timex.tick * 10);
+ delay = SEC_TO_USEC(DURATION) / nrsleeps;
+
+ fprintf(stderr, "duration: %d secs, #sleep: %d, delay: %d us\n",
+ DURATION, nrsleeps, delay);
+
+ gettimeofday(&before, NULL);
+ if (tick_me(nrsleeps, delay, i))
+ return 1;
+ gettimeofday(&after, NULL);
+
+ duration = SEC_TO_USEC(after.tv_sec - before.tv_sec) +
+ (after.tv_usec - before.tv_usec);
+
+ fprintf(stderr, "test duration: %f secs\n",
+ (float)(duration) / (float)SEC_TO_USEC(1));
+
+ deviation = ((float)duration - (float)SEC_TO_USEC(DURATION)) /
+ (float)SEC_TO_USEC(DURATION);
+
+ fprintf(stderr, "deviation %f\n", deviation);
+ if (deviation > 0.5) {
+ fprintf(stderr, "expected test duration too long\n");
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ ret = 0;
+
+ signal(SIGALRM, timeout);
+
+ alarm(DURATION + 5);
+
+ for (i = 0; i < nrcpus; i++) {
+ int status;
+
+ waitpid(pids[i], &status, 0);
+ if (status != 0) {
+ fprintf(stderr, "test for cpu %d has failed\n", i);
+ ret = 1;
+ }
+ }
+
+ return ret;
+}