/* * Copyright (C) 2006, Intel Corporation * * This file is part of the Linux-ready Firmware Developer Kit * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation;version 2.1 of the License. * * This library 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include struct cstates { int counts[16]; int used[16]; }; int statecount = -1; static void keep_busy_for_one_second(int cpunr) { cpu_set_t mask, oldset; time_t current; unsigned long loopcount = 0; /* First, go to the right cpu */ sched_getaffinity(0, sizeof(oldset), &oldset); CPU_ZERO(&mask); CPU_SET(cpunr, &mask); sched_setaffinity(0, sizeof(mask), &mask); current = time(NULL); do { double A, B; int i; A = 1.234567; B = 3.121213; for (i=0; i<100; i++) { A = A * B; B = A * A; A = A - B + sqrt(A); A = A * B; B = A * A; A = A - B + sqrt(A); A = A * B; B = A * A; A = A - B + sqrt(A); A = A * B; B = A * A; A = A - B + sqrt(A); } loopcount++; } while (current == time(NULL)); sched_setaffinity(0, sizeof(oldset), &oldset); } static void get_cstates(char *dir, struct cstates *state) { char path[PATH_MAX]; char line[4096]; FILE *file; int i; memset(state, 0, sizeof(struct cstates)); for (i=0; i<16; i++) state->used[i] = -1; sprintf(path, "%s/power", dir); file = fopen(path, "r"); if (file == NULL) { return; } while (!feof(file)) { char *c; int nr=0, count=0, active=0; memset(line, 0, 4096); if (fgets(line, 4095, file)==NULL) continue; c = strchr(line, 'C'); if (!c) continue; nr = strtoull(c+1, NULL, 10); c = strstr(line, "usage["); if (!c) continue; count = strtoull(c+6, NULL, 10); c = strchr(line, '*'); if (c) active=1; if (nr>=0 && nr <16) { state->counts[nr] = count; state->used[nr] = active; } } fclose(file); } static void do_cpu(int cpunr, char *dir) { struct cstates initial, current; int ti, count; char buffer[4096]; int keepgoing = 1; int warned = 1; int first = 1; get_cstates(dir, &initial); ti = 0; while (ti < 30 && keepgoing) { int i; if (ti<5) keep_busy_for_one_second(cpunr); else sleep(1); get_cstates(dir, ¤t); for (i=2; i<16;i++) if (current.used[i]>0) { if (initial.counts[i] == current.counts[i] && !warned) { /* sprintf(buffer,"Processor %i doesn't increment C-state count in C%i", cpunr,i); report_result("cstates", FAIL, buffer,NULL,NULL); */ /* Disabled due to Linux kernel bug */ warned = 1; } initial.counts[i] = current.counts[i]; initial.used[i] = 1; } keepgoing = 0; for (i=2; i<16; i++) if (initial.used[i]==0) keepgoing = 1; report_testrun_progress(10+ti*3); ti++; } sprintf(buffer,"Processor %i has not reached ", cpunr); for (ti=2; ti<16;ti++) { char b2[64]; sprintf(b2, "C%i ", ti); if (initial.used[ti]==0) strcat(buffer, b2); } strcat(buffer, "during tests."); if (keepgoing) report_result("cstates", INFO, buffer, NULL, NULL); sprintf(buffer,"Processor %i has reached all C-states", cpunr); for (ti=2; ti<16;ti++) { char b2[64]; sprintf(b2, "C%i ", ti); if (initial.used[ti]==0) { if (first) strcat(buffer, ": "); first = 0; strcat(buffer, b2); } } if (!keepgoing) report_result("cstates", PASS, buffer, NULL, NULL); count = 0; for (ti=1; ti<16; ti++) if (initial.used[ti]>=0) count ++; if (statecount==-1) statecount = count; if (statecount != count) { sprintf(buffer,"Processor %i is expected to have %i C-states but has %i", cpunr, statecount, count); report_result("cstates", FAIL, buffer, NULL, NULL); } } int main(int argc, char **argv) { DIR *dir; struct dirent *entry; start_test("cstates", "Processor C state support", "This test checks if all processors have the same number of C-states, " "if the C-state counter works and if C-state transitions happen." ); dir = opendir("/proc/acpi/processor"); if (!dir) { printf("FATAL: cstates: proc not mounted\n"); return 0; } do { int cpunr; char cpupath[2048]; entry = readdir(dir); if (entry && strlen(entry->d_name)>3) { sprintf(cpupath, "/proc/acpi/processor/%s", entry->d_name); cpunr = strtoul(entry->d_name+3,NULL,10); do_cpu(cpunr, cpupath); } } while (entry); finish_test("cstates"); return 0; }