This test program increase the frequency for each cpu and launch the cpucycle program.
A computation is made to check the deviation of the ratio (counter / frequency) is consistent between the frequencies.
More informations can be found at:
https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/QA/Scripts#test_06
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- cpufreq/test_06.sh | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++ utils/Makefile | 14 +--- utils/cpucycle.c | 102 ++++++++++++++++++++++ 3 files changed, 341 insertions(+), 11 deletions(-) create mode 100644 cpufreq/test_06.sh create mode 100644 utils/cpucycle.c
diff --git a/cpufreq/test_06.sh b/cpufreq/test_06.sh new file mode 100644 index 0000000..e12487f --- /dev/null +++ b/cpufreq/test_06.sh @@ -0,0 +1,236 @@ +#!/bin/bash +#/******************************************************************************* +# Copyright (C) 2011, Linaro Limited. +# +# This file is part of PM QA. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Daniel Lezcano daniel.lezcano@linaro.org (IBM Corporation) +# - initial API and implementation +#******************************************************************************/ + +# URL : https://wiki.linaro.org/WorkingGroups/PowerManagement/Doc/QA/Scripts#test_06 +CPU_PATH="/sys/devices/system/cpu" +CPUCYCLE=../utils/cpucycle +oldfreqs= +oldgovs= + +save_frequencies() { + index=0 + for i in $(ls $CPU_PATH | grep "cpu[0-9].*"); do + printf "%-70s" "saving frequency for $i ... " + oldfreqs[$index]=$(cat $CPU_PATH/$i/cpufreq/scaling_cur_speed) + printf "DONE\n" + index=$((index + 1)) + done +} + +restore_frequencies() { + index=0 + for i in $(ls $CPU_PATH | grep "cpu[0-9].*"); do + oldfreq=${oldfreqs[$index]} + printf "%-70s" "restoring frequency '$oldfreq' for $i ... " + echo $oldfreq > $CPU_PATH/$i/cpufreq/scaling_setspeed + printf "DONE\n" + index=$((index + 1)) + done +} + +save_governors() { + index=0 + for i in $(ls $CPU_PATH | grep "cpu[0-9].*"); do + printf "%-70s" "saving governor for $i ... " + oldgovs[$index]=$(cat $CPU_PATH/$i/cpufreq/scaling_governor) + printf "DONE\n" + index=$((index + 1)) + done +} + +restore_governors() { + index=0 + for i in $(ls $CPU_PATH | grep "cpu[0-9].*"); do + oldgov=${oldgovs[$index]} + printf "%-70s" "restoring governor '$oldgov' for $i ... " + echo $oldgov > $CPU_PATH/$i/cpufreq/scaling_governor + printf "DONE\n" + index=$((index + 1)) + done +} + +switch_governor() { + + newgov=$2 + oldgov=$(cat $1/scaling_governor) + + printf "%-70s" "setting governor to '$newgov' ... " + echo $newgov > $1/scaling_governor + curgov=$(cat $1/scaling_governor) + if [ "$curgov" != "$newgov" ]; then + printf "FAIL\n" + echo $oldgov > $1/scaling_governor + return 1 + fi + + printf "PASS\n" + + return 0 +} + +check_frequency_perf() { + + frequencies=$(cat $1/scaling_available_frequencies) + index=0 + cpu=$2 + + # for each frequency check a change of performances + for i in $frequencies; do + + switch_frequency $1 $i || return 1 + + printf "%-70s" "running 'cpucycle' on $cpu at '$i' KHz ... " + + result=$($CPUCYCLE $cpu) + if [ $? != 0 ]; then + printf "FAIL\n" + return 1 + fi + + printf "PASS\n" + + results[$index]=$(echo "scale=3;($result / $i)" | bc -l) + index=$((index + 1)) + + done + + index=0 + sum=0 + + for i in $frequencies; do + res=${results[$index]} + sum=$(echo "($sum + $res)" | bc -l) + index=$((index + 1)) + done + + avg=$(echo "scale=3;($sum / $index)" | bc -l) + + index=0 + + for i in $frequencies; do + + res=${results[$index]} + + # compute deviation + dev=$(echo "scale=3;((( $res - $avg ) / $avg) * 100 )" | bc -l) + + # change to absolute + dev=$(echo $dev | awk '{ print ($1 >= 0) ? $1 : 0 - $1}') + + index=$((index + 1)) + + printf "%-70s" "deviation $dev % for $i is ... " + + res=$(echo "($dev <= 0.5)" | bc -l) + if [ "$res" = "1" ]; then + printf "VERY GOOD\n" + continue + fi + + res=$(echo "($dev <= 1.0)" | bc -l) + if [ "$res" = "1" ]; then + printf "GOOD\n" + continue + fi + + res=$(echo "($dev <= 2.0)" | bc -l) + if [ "$res" = "1" ]; then + printf "BAD\n" + continue + fi + + res=$(echo "($dev <= 5.0)" | bc -l) + if [ "$res" = "1" ]; then + printf "VERY BAD\n" + continue + fi + + res=$(echo "($dev <= 6.0)" | bc -l) + if [ "$res" = "1" ]; then + printf "SUSPECT\n" + continue + fi + + res=$(echo "($dev > 6.0)" | bc -l) + if [ "$res" = "1" ]; then + printf "BOGUS\n" + return 1 + fi + done + + return 0 +} + +switch_frequency() { + + oldfreq=$(cat $1/scaling_cur_freq) + newfreq=$2 + + nrfreqs=$(cat $1/scaling_available_frequencies | wc -w) + latency=$(cat $1/cpuinfo_transition_latency) + + printf "%-70s" "setting frequency to $2 KHz ... " + echo $2 > $1/scaling_setspeed + + # wait the latency period + ../utils/nanosleep $((nrfreqs * latency)) + + curfreq=$(cat $1/scaling_cur_freq) + if [ "$curfreq" != "$2" ]; then + printf "FAIL\n" + echo $oldfreq > $1/scaling_setspeed + return 1 + fi + + printf "PASS\n" + + return 0 +} + +exit_fail() { + restore_governors + exit 1 +} + +check_root() { + + printf "%-70s" "checking if we are root ... " + + if [ "$(id -u)" != "0" ]; then + printf "FAIL\n" + return 1 + fi + + printf "PASS\n" + + return 0 +} + +check_root || exit 1 + +save_governors || exit 1 + +trap exit_fail SIGHUP SIGINT SIGTERM + +for i in $(ls $CPU_PATH | grep "cpu[0-9].*"); do + + printf "for '$i':\n" + switch_governor $CPU_PATH/$i/cpufreq userspace || exit_fail + check_frequency_perf $CPU_PATH/$i/cpufreq $i || exit_fail + +done + +restore_governors || exit 1 diff --git a/utils/Makefile b/utils/Makefile index ebe9856..b3e206c 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -1,19 +1,11 @@ CFLAGS?=-g -Wall CC?=gcc -EXEC=nanosleep SRC=$(wildcard *.c) -OBJ= $(SRC:.c=.o) +EXEC=$(SRC:%.c=%)
check: $(EXEC)
-nanosleep: $(OBJ) - @$(CC) -o $@ $^ $(LDFLAGS) - -%.o: %.c - $(CC) -o $@ -c $< $(CFLAGS) +all: $(EXEC)
clean: - rm *.o - -mrproper: clean - rm $(EXEC) + rm -f *.o $(EXEC) diff --git a/utils/cpucycle.c b/utils/cpucycle.c new file mode 100644 index 0000000..e092c0a --- /dev/null +++ b/utils/cpucycle.c @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (C) 2011, Linaro Limited. + * + * This file is part of PM QA + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Daniel Lezcano daniel.lezcano@linaro.org (IBM Corporation) + * - initial API and implementation + *******************************************************************************/ +#define _GNU_SOURCE +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <signal.h> +#include <unistd.h> +#include <regex.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> + +static bool intr; + +void sigalarm(int sig) +{ + intr = true; +} + +int main(int argc, char *argv[]) +{ + regex_t reg; + const char *regex = "cpu[0-9].*"; + char **aargv = NULL; + regmatch_t m[1]; + cpu_set_t cpuset; + long counter = 0; + int i; + + if (argc == 1) { + fprintf(stderr, "%s <cpuN> [cpuM] ... \n", argv[0]); + return 1; + } + + aargv = &argv[1]; + + if (regcomp(®, regex, 0)) { + fprintf(stderr, "failed to compile the regex\n"); + return 1; + } + + CPU_ZERO(&cpuset); + + for (i = 0; i < (argc - 1); i++) { + + char *aux; + int cpu; + + if (regexec(®, aargv[i], 1, m, 0)) { + fprintf(stderr, "'%s' parameter not recognized, " \ + "should be cpu[0-9]\n", aargv[i]); + return 1; + } + + aux = aargv[i] + 3; + cpu = atoi(aux); + + CPU_SET(cpu, &cpuset); + } + + if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { + perror("sched_setaffinity"); + return 1; + } + + if (setpriority(PRIO_PROCESS, 0, -20) < 0) { + perror("setpriority"); + return 1; + } + + signal(SIGALRM, sigalarm); + + alarm(1); + /* warmup */ + for (; !intr ;) + counter++; + + counter = 0; + intr = false; + + alarm(1); + for (; !intr ;) + counter++; + + printf("%ld\n", counter); + + return 0; +}