diff --git a/cpupower-3.19.tar.bz2 b/cpupower-3.19.tar.bz2 deleted file mode 100644 index 8bbee6a..0000000 --- a/cpupower-3.19.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fc866551e33bca8b6c2398335d93ed3e0db7487566b873197bf68a104c14ef81 -size 70536 diff --git a/cpupower-4.6.tar.bz2 b/cpupower-4.6.tar.bz2 new file mode 100644 index 0000000..bfbe4d9 --- /dev/null +++ b/cpupower-4.6.tar.bz2 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d3ce942da463f4e99f7ae32f258666af07489d2b42e2d34c5b8cfddbd76dfb22 +size 71387 diff --git a/cpupower.changes b/cpupower.changes index 8faa62f..37b96a2 100644 --- a/cpupower.changes +++ b/cpupower.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Wed Apr 20 13:16:43 UTC 2016 - trenn@suse.de + +- Add cpuidle functions to public libcpupower +*Add library_cleanup.patch + ------------------------------------------------------------------- Tue Jan 26 17:29:27 UTC 2016 - trenn@suse.de diff --git a/cpupower.spec b/cpupower.spec index a09c07c..ba336b0 100644 --- a/cpupower.spec +++ b/cpupower.spec @@ -20,16 +20,19 @@ Name: cpupower # Use this as version when things are in mainline kernel %define version %(rpm -q --qf '%{VERSION}' kernel-source) -Version: 3.19 +Version: 4.6 Release: 0 %define tsversion 4.8 Summary: Tools to determine and set CPU Power related Settings License: GPL-2.0 Group: System/Base +Url: https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git Source: %{name}-%{version}.tar.bz2 Source1: turbostat-%{tsversion}.tar.bz2 Source2: cpupower_export_tarball_from_git.sh Source3: msr-index.h + +Patch1: library_cleanup.patch Patch20: turbostat_fix_man_perm.patch Patch21: make_header_file_passable_from_outside.patch Patch22: turbostat_set_asm_header_fixed.patch @@ -80,6 +83,7 @@ powersave module. %prep %setup -D -b 1 +%patch1 -p1 cd ../turbostat-%{tsversion} %patch20 -p1 %patch21 -p1 @@ -148,6 +152,7 @@ make install -e DESTDIR="$RPM_BUILD_ROOT" %files devel %defattr(-,root,root) /usr/include/cpufreq.h +/usr/include/cpuidle.h %{_libdir}/libcpu*.so %changelog diff --git a/cpupower_export_tarball_from_git.sh b/cpupower_export_tarball_from_git.sh index 0d2d00e..5120e1a 100644 --- a/cpupower_export_tarball_from_git.sh +++ b/cpupower_export_tarball_from_git.sh @@ -60,7 +60,7 @@ set -x git archive --format=tar $GIT_TAG tools/power/x86/turbostat |tar -x mv tools/power/x86/turbostat turbostat${VERSION} mkdir turbostat${VERSION}/asm -[ ! -e "$GIT_DIR"/../arch/x86/include/uapi/asm/msr-index.h ] && echo "msr-index.h does not exist" && exit 1 +[ ! -e "$GIT_DIR"/../arch/x86/include/asm/msr-index.h ] && echo "msr-index.h does not exist" && exit 1 cp "$GIT_DIR"/../arch/x86/include/uapi/asm/msr-index.h turbostat${VERSION}/asm tar -cvjf turbostat${VERSION}.tar.bz2 turbostat${VERSION} popd diff --git a/library_cleanup.patch b/library_cleanup.patch new file mode 100644 index 0000000..065c761 --- /dev/null +++ b/library_cleanup.patch @@ -0,0 +1,2871 @@ +cpupower: Add cpuidle parts into library + +cpupower was built from cpufrequtils and enhanced by quite some neat cpuidle +userspace tools. + +Now the cpu idle functions have been separated and added to the cpupower.so +library. + +Here again pasted for better review of the interfaces: + +====================================== +int cpuidle_is_state_disabled(unsigned int cpu, + unsigned int idlestate); +int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate, + unsigned int disable); +unsigned long cpuidle_state_latency(unsigned int cpu, + unsigned int idlestate); +unsigned long cpuidle_state_usage(unsigned int cpu, + unsigned int idlestate); +unsigned long long cpuidle_state_time(unsigned int cpu, + unsigned int idlestate); +char *cpuidle_state_name(unsigned int cpu, + unsigned int idlestate); +char *cpuidle_state_desc(unsigned int cpu, + unsigned int idlestate); +unsigned int cpuidle_state_count(unsigned int cpu); + +char *cpuidle_get_governor(void); +char *cpuidle_get_driver(void); + +====================================== + + +Signed-off-by: Thomas Renninger + +diff --git a/Makefile b/Makefile +index 2e2ba2e..1ca525d 100644 +--- a/Makefile ++++ b/Makefile +@@ -58,7 +58,7 @@ DESTDIR ?= + # and _should_ modify the PACKAGE_BUGREPORT definition + + VERSION= $(shell ./utils/version-gen.sh) +-LIB_MAJ= 0.0.0 ++LIB_MAJ= 0.0.1 + LIB_MIN= 0 + + PACKAGE = cpupower +@@ -124,7 +124,7 @@ WARNINGS += -Wshadow + CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ + -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE + +-UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ ++UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \ + utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ + utils/helpers/pci.o utils/helpers/bitmask.o \ + utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ +@@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ + utils/helpers/bitmask.h \ + utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def + +-LIB_HEADERS = lib/cpufreq.h lib/sysfs.h +-LIB_SRC = lib/cpufreq.c lib/sysfs.c +-LIB_OBJS = lib/cpufreq.o lib/sysfs.o ++LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h ++LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c ++LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o + LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) + + CFLAGS += -pipe +@@ -265,6 +265,7 @@ install-lib: + $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ + $(INSTALL) -d $(DESTDIR)${includedir} + $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h ++ $(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h + + install-tools: + $(INSTALL) -d $(DESTDIR)${bindir} +@@ -296,6 +297,7 @@ install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENC + uninstall: + - rm -f $(DESTDIR)${libdir}/libcpupower.* + - rm -f $(DESTDIR)${includedir}/cpufreq.h ++ - rm -f $(DESTDIR)${includedir}/cpuidle.h + - rm -f $(DESTDIR)${bindir}/utils/cpupower + - rm -f $(DESTDIR)${mandir}/man1/cpupower.1 + - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 +diff --git a/bench/system.c b/bench/system.c +index f01e3f4..c25a74a 100644 +--- a/bench/system.c ++++ b/bench/system.c +@@ -26,6 +26,7 @@ + #include + + #include ++#include + + #include "config.h" + #include "system.h" +@@ -60,7 +61,7 @@ int set_cpufreq_governor(char *governor, unsigned int cpu) + + dprintf("set %s as cpufreq governor\n", governor); + +- if (cpufreq_cpu_exists(cpu) != 0) { ++ if (cpupower_is_cpu_online(cpu) != 0) { + perror("cpufreq_cpu_exists"); + fprintf(stderr, "error: cpu %u does not exist\n", cpu); + return -1; +diff --git a/lib/cpufreq.c b/lib/cpufreq.c +index d961101..1b993fe 100644 +--- a/lib/cpufreq.c ++++ b/lib/cpufreq.c +@@ -9,28 +9,190 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + + #include "cpufreq.h" +-#include "sysfs.h" ++#include "cpupower_intern.h" + +-int cpufreq_cpu_exists(unsigned int cpu) ++/* CPUFREQ sysfs access **************************************************/ ++ ++/* helper function to read file from /sys into given buffer */ ++/* fname is a relative path under "cpuX/cpufreq" dir */ ++static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, ++ char *buf, size_t buflen) + { +- return sysfs_cpu_exists(cpu); ++ char path[SYSFS_PATH_MAX]; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", ++ cpu, fname); ++ return sysfs_read_file(path, buf, buflen); + } + ++/* helper function to write a new value to a /sys file */ ++/* fname is a relative path under "cpuX/cpufreq" dir */ ++static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, ++ const char *fname, ++ const char *value, size_t len) ++{ ++ char path[SYSFS_PATH_MAX]; ++ int fd; ++ ssize_t numwrite; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", ++ cpu, fname); ++ ++ fd = open(path, O_WRONLY); ++ if (fd == -1) ++ return 0; ++ ++ numwrite = write(fd, value, len); ++ if (numwrite < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ close(fd); ++ ++ return (unsigned int) numwrite; ++} ++ ++/* read access to files which contain one numeric value */ ++ ++enum cpufreq_value { ++ CPUINFO_CUR_FREQ, ++ CPUINFO_MIN_FREQ, ++ CPUINFO_MAX_FREQ, ++ CPUINFO_LATENCY, ++ SCALING_CUR_FREQ, ++ SCALING_MIN_FREQ, ++ SCALING_MAX_FREQ, ++ STATS_NUM_TRANSITIONS, ++ MAX_CPUFREQ_VALUE_READ_FILES ++}; ++ ++static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { ++ [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", ++ [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", ++ [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", ++ [CPUINFO_LATENCY] = "cpuinfo_transition_latency", ++ [SCALING_CUR_FREQ] = "scaling_cur_freq", ++ [SCALING_MIN_FREQ] = "scaling_min_freq", ++ [SCALING_MAX_FREQ] = "scaling_max_freq", ++ [STATS_NUM_TRANSITIONS] = "stats/total_trans" ++}; ++ ++ ++static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, ++ enum cpufreq_value which) ++{ ++ unsigned long value; ++ unsigned int len; ++ char linebuf[MAX_LINE_LEN]; ++ char *endp; ++ ++ if (which >= MAX_CPUFREQ_VALUE_READ_FILES) ++ return 0; ++ ++ len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], ++ linebuf, sizeof(linebuf)); ++ ++ if (len == 0) ++ return 0; ++ ++ value = strtoul(linebuf, &endp, 0); ++ ++ if (endp == linebuf || errno == ERANGE) ++ return 0; ++ ++ return value; ++} ++ ++/* read access to files which contain one string */ ++ ++enum cpufreq_string { ++ SCALING_DRIVER, ++ SCALING_GOVERNOR, ++ MAX_CPUFREQ_STRING_FILES ++}; ++ ++static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { ++ [SCALING_DRIVER] = "scaling_driver", ++ [SCALING_GOVERNOR] = "scaling_governor", ++}; ++ ++ ++static char *sysfs_cpufreq_get_one_string(unsigned int cpu, ++ enum cpufreq_string which) ++{ ++ char linebuf[MAX_LINE_LEN]; ++ char *result; ++ unsigned int len; ++ ++ if (which >= MAX_CPUFREQ_STRING_FILES) ++ return NULL; ++ ++ len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ result = strdup(linebuf); ++ if (result == NULL) ++ return NULL; ++ ++ if (result[strlen(result) - 1] == '\n') ++ result[strlen(result) - 1] = '\0'; ++ ++ return result; ++} ++ ++/* write access */ ++ ++enum cpufreq_write { ++ WRITE_SCALING_MIN_FREQ, ++ WRITE_SCALING_MAX_FREQ, ++ WRITE_SCALING_GOVERNOR, ++ WRITE_SCALING_SET_SPEED, ++ MAX_CPUFREQ_WRITE_FILES ++}; ++ ++static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { ++ [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", ++ [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", ++ [WRITE_SCALING_GOVERNOR] = "scaling_governor", ++ [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", ++}; ++ ++static int sysfs_cpufreq_write_one_value(unsigned int cpu, ++ enum cpufreq_write which, ++ const char *new_value, size_t len) ++{ ++ if (which >= MAX_CPUFREQ_WRITE_FILES) ++ return 0; ++ ++ if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], ++ new_value, len) != len) ++ return -ENODEV; ++ ++ return 0; ++}; ++ + unsigned long cpufreq_get_freq_kernel(unsigned int cpu) + { +- return sysfs_get_freq_kernel(cpu); ++ return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); + } + + unsigned long cpufreq_get_freq_hardware(unsigned int cpu) + { +- return sysfs_get_freq_hardware(cpu); ++ return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); + } + + unsigned long cpufreq_get_transition_latency(unsigned int cpu) + { +- return sysfs_get_freq_transition_latency(cpu); ++ return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); + } + + int cpufreq_get_hardware_limits(unsigned int cpu, +@@ -39,12 +201,21 @@ int cpufreq_get_hardware_limits(unsigned int cpu, + { + if ((!min) || (!max)) + return -EINVAL; +- return sysfs_get_freq_hardware_limits(cpu, min, max); ++ ++ *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); ++ if (!*min) ++ return -ENODEV; ++ ++ *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); ++ if (!*max) ++ return -ENODEV; ++ ++ return 0; + } + + char *cpufreq_get_driver(unsigned int cpu) + { +- return sysfs_get_freq_driver(cpu); ++ return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); + } + + void cpufreq_put_driver(char *ptr) +@@ -56,7 +227,26 @@ void cpufreq_put_driver(char *ptr) + + struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) + { +- return sysfs_get_freq_policy(cpu); ++ struct cpufreq_policy *policy; ++ ++ policy = malloc(sizeof(struct cpufreq_policy)); ++ if (!policy) ++ return NULL; ++ ++ policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); ++ if (!policy->governor) { ++ free(policy); ++ return NULL; ++ } ++ policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); ++ policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); ++ if ((!policy->min) || (!policy->max)) { ++ free(policy->governor); ++ free(policy); ++ return NULL; ++ } ++ ++ return policy; + } + + void cpufreq_put_policy(struct cpufreq_policy *policy) +@@ -72,7 +262,57 @@ void cpufreq_put_policy(struct cpufreq_policy *policy) + struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned + int cpu) + { +- return sysfs_get_freq_available_governors(cpu); ++ struct cpufreq_available_governors *first = NULL; ++ struct cpufreq_available_governors *current = NULL; ++ char linebuf[MAX_LINE_LEN]; ++ unsigned int pos, i; ++ unsigned int len; ++ ++ len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ pos = 0; ++ for (i = 0; i < len; i++) { ++ if (linebuf[i] == ' ' || linebuf[i] == '\n') { ++ if (i - pos < 2) ++ continue; ++ if (current) { ++ current->next = malloc(sizeof(*current)); ++ if (!current->next) ++ goto error_out; ++ current = current->next; ++ } else { ++ first = malloc(sizeof(*first)); ++ if (!first) ++ goto error_out; ++ current = first; ++ } ++ current->first = first; ++ current->next = NULL; ++ ++ current->governor = malloc(i - pos + 1); ++ if (!current->governor) ++ goto error_out; ++ ++ memcpy(current->governor, linebuf + pos, i - pos); ++ current->governor[i - pos] = '\0'; ++ pos = i + 1; ++ } ++ } ++ ++ return first; ++ ++ error_out: ++ while (first) { ++ current = first->next; ++ if (first->governor) ++ free(first->governor); ++ free(first); ++ first = current; ++ } ++ return NULL; + } + + void cpufreq_put_available_governors(struct cpufreq_available_governors *any) +@@ -96,7 +336,57 @@ void cpufreq_put_available_governors(struct cpufreq_available_governors *any) + struct cpufreq_available_frequencies + *cpufreq_get_available_frequencies(unsigned int cpu) + { +- return sysfs_get_available_frequencies(cpu); ++ struct cpufreq_available_frequencies *first = NULL; ++ struct cpufreq_available_frequencies *current = NULL; ++ char one_value[SYSFS_PATH_MAX]; ++ char linebuf[MAX_LINE_LEN]; ++ unsigned int pos, i; ++ unsigned int len; ++ ++ len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ pos = 0; ++ for (i = 0; i < len; i++) { ++ if (linebuf[i] == ' ' || linebuf[i] == '\n') { ++ if (i - pos < 2) ++ continue; ++ if (i - pos >= SYSFS_PATH_MAX) ++ goto error_out; ++ if (current) { ++ current->next = malloc(sizeof(*current)); ++ if (!current->next) ++ goto error_out; ++ current = current->next; ++ } else { ++ first = malloc(sizeof(*first)); ++ if (!first) ++ goto error_out; ++ current = first; ++ } ++ current->first = first; ++ current->next = NULL; ++ ++ memcpy(one_value, linebuf + pos, i - pos); ++ one_value[i - pos] = '\0'; ++ if (sscanf(one_value, "%lu", ¤t->frequency) != 1) ++ goto error_out; ++ ++ pos = i + 1; ++ } ++ } ++ ++ return first; ++ ++ error_out: ++ while (first) { ++ current = first->next; ++ free(first); ++ first = current; ++ } ++ return NULL; + } + + void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies +@@ -114,10 +404,65 @@ void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies + } + } + ++static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, ++ const char *file) ++{ ++ struct cpufreq_affected_cpus *first = NULL; ++ struct cpufreq_affected_cpus *current = NULL; ++ char one_value[SYSFS_PATH_MAX]; ++ char linebuf[MAX_LINE_LEN]; ++ unsigned int pos, i; ++ unsigned int len; ++ ++ len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ pos = 0; ++ for (i = 0; i < len; i++) { ++ if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { ++ if (i - pos < 1) ++ continue; ++ if (i - pos >= SYSFS_PATH_MAX) ++ goto error_out; ++ if (current) { ++ current->next = malloc(sizeof(*current)); ++ if (!current->next) ++ goto error_out; ++ current = current->next; ++ } else { ++ first = malloc(sizeof(*first)); ++ if (!first) ++ goto error_out; ++ current = first; ++ } ++ current->first = first; ++ current->next = NULL; ++ ++ memcpy(one_value, linebuf + pos, i - pos); ++ one_value[i - pos] = '\0'; ++ ++ if (sscanf(one_value, "%u", ¤t->cpu) != 1) ++ goto error_out; ++ ++ pos = i + 1; ++ } ++ } ++ ++ return first; ++ ++ error_out: ++ while (first) { ++ current = first->next; ++ free(first); ++ first = current; ++ } ++ return NULL; ++} + + struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) + { +- return sysfs_get_freq_affected_cpus(cpu); ++ return sysfs_get_cpu_list(cpu, "affected_cpus"); + } + + void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) +@@ -138,7 +483,7 @@ void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) + + struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) + { +- return sysfs_get_freq_related_cpus(cpu); ++ return sysfs_get_cpu_list(cpu, "related_cpus"); + } + + void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) +@@ -146,45 +491,208 @@ void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) + cpufreq_put_affected_cpus(any); + } + ++static int verify_gov(char *new_gov, char *passed_gov) ++{ ++ unsigned int i, j = 0; ++ ++ if (!passed_gov || (strlen(passed_gov) > 19)) ++ return -EINVAL; ++ ++ strncpy(new_gov, passed_gov, 20); ++ for (i = 0; i < 20; i++) { ++ if (j) { ++ new_gov[i] = '\0'; ++ continue; ++ } ++ if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) ++ continue; ++ ++ if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) ++ continue; ++ ++ if (new_gov[i] == '-') ++ continue; ++ ++ if (new_gov[i] == '_') ++ continue; ++ ++ if (new_gov[i] == '\0') { ++ j = 1; ++ continue; ++ } ++ return -EINVAL; ++ } ++ new_gov[19] = '\0'; ++ return 0; ++} + + int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) + { ++ char min[SYSFS_PATH_MAX]; ++ char max[SYSFS_PATH_MAX]; ++ char gov[SYSFS_PATH_MAX]; ++ int ret; ++ unsigned long old_min; ++ int write_max_first; ++ + if (!policy || !(policy->governor)) + return -EINVAL; + +- return sysfs_set_freq_policy(cpu, policy); ++ if (policy->max < policy->min) ++ return -EINVAL; ++ ++ if (verify_gov(gov, policy->governor)) ++ return -EINVAL; ++ ++ snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); ++ snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); ++ ++ old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); ++ write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); ++ ++ if (write_max_first) { ++ ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, ++ max, strlen(max)); ++ if (ret) ++ return ret; ++ } ++ ++ ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, ++ strlen(min)); ++ if (ret) ++ return ret; ++ ++ if (!write_max_first) { ++ ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, ++ max, strlen(max)); ++ if (ret) ++ return ret; ++ } ++ ++ return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, ++ gov, strlen(gov)); + } + + + int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) + { +- return sysfs_modify_freq_policy_min(cpu, min_freq); ++ char value[SYSFS_PATH_MAX]; ++ ++ snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); ++ ++ return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, ++ value, strlen(value)); + } + + + int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) + { +- return sysfs_modify_freq_policy_max(cpu, max_freq); +-} ++ char value[SYSFS_PATH_MAX]; ++ ++ snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); + ++ return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, ++ value, strlen(value)); ++} + + int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) + { ++ char new_gov[SYSFS_PATH_MAX]; ++ + if ((!governor) || (strlen(governor) > 19)) + return -EINVAL; + +- return sysfs_modify_freq_policy_governor(cpu, governor); ++ if (verify_gov(new_gov, governor)) ++ return -EINVAL; ++ ++ return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, ++ new_gov, strlen(new_gov)); + } + + int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) + { +- return sysfs_set_frequency(cpu, target_frequency); ++ struct cpufreq_policy *pol = cpufreq_get_policy(cpu); ++ char userspace_gov[] = "userspace"; ++ char freq[SYSFS_PATH_MAX]; ++ int ret; ++ ++ if (!pol) ++ return -ENODEV; ++ ++ if (strncmp(pol->governor, userspace_gov, 9) != 0) { ++ ret = cpufreq_modify_policy_governor(cpu, userspace_gov); ++ if (ret) { ++ cpufreq_put_policy(pol); ++ return ret; ++ } ++ } ++ ++ cpufreq_put_policy(pol); ++ ++ snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); ++ ++ return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, ++ freq, strlen(freq)); + } + + struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, + unsigned long long *total_time) + { +- return sysfs_get_freq_stats(cpu, total_time); ++ struct cpufreq_stats *first = NULL; ++ struct cpufreq_stats *current = NULL; ++ char one_value[SYSFS_PATH_MAX]; ++ char linebuf[MAX_LINE_LEN]; ++ unsigned int pos, i; ++ unsigned int len; ++ ++ len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ *total_time = 0; ++ pos = 0; ++ for (i = 0; i < len; i++) { ++ if (i == strlen(linebuf) || linebuf[i] == '\n') { ++ if (i - pos < 2) ++ continue; ++ if ((i - pos) >= SYSFS_PATH_MAX) ++ goto error_out; ++ if (current) { ++ current->next = malloc(sizeof(*current)); ++ if (!current->next) ++ goto error_out; ++ current = current->next; ++ } else { ++ first = malloc(sizeof(*first)); ++ if (!first) ++ goto error_out; ++ current = first; ++ } ++ current->first = first; ++ current->next = NULL; ++ ++ memcpy(one_value, linebuf + pos, i - pos); ++ one_value[i - pos] = '\0'; ++ if (sscanf(one_value, "%lu %llu", ++ ¤t->frequency, ++ ¤t->time_in_state) != 2) ++ goto error_out; ++ ++ *total_time = *total_time + current->time_in_state; ++ pos = i + 1; ++ } ++ } ++ ++ return first; ++ ++ error_out: ++ while (first) { ++ current = first->next; ++ free(first); ++ first = current; ++ } ++ return NULL; + } + + void cpufreq_put_stats(struct cpufreq_stats *any) +@@ -204,5 +712,5 @@ void cpufreq_put_stats(struct cpufreq_stats *any) + + unsigned long cpufreq_get_transitions(unsigned int cpu) + { +- return sysfs_get_freq_transitions(cpu); ++ return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); + } +diff --git a/lib/cpufreq.h b/lib/cpufreq.h +index 3aae8e7..3b005c3 100644 +--- a/lib/cpufreq.h ++++ b/lib/cpufreq.h +@@ -17,8 +17,8 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +-#ifndef _CPUFREQ_H +-#define _CPUFREQ_H 1 ++#ifndef __CPUPOWER_CPUFREQ_H__ ++#define __CPUPOWER_CPUFREQ_H__ + + struct cpufreq_policy { + unsigned long min; +@@ -58,13 +58,6 @@ struct cpufreq_stats { + extern "C" { + #endif + +-/* +- * returns 0 if the specified CPU is present (it doesn't say +- * whether it is online!), and an error value if not. +- */ +- +-extern int cpufreq_cpu_exists(unsigned int cpu); +- + /* determine current CPU frequency + * - _kernel variant means kernel's opinion of CPU frequency + * - _hardware variant means actual hardware CPU frequency, +@@ -73,9 +66,9 @@ extern int cpufreq_cpu_exists(unsigned int cpu); + * returns 0 on failure, else frequency in kHz. + */ + +-extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu); ++unsigned long cpufreq_get_freq_kernel(unsigned int cpu); + +-extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); ++unsigned long cpufreq_get_freq_hardware(unsigned int cpu); + + #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); + +@@ -84,7 +77,7 @@ extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); + * + * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds + */ +-extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); ++unsigned long cpufreq_get_transition_latency(unsigned int cpu); + + + /* determine hardware CPU frequency limits +@@ -93,7 +86,7 @@ extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); + * considerations by cpufreq policy notifiers in the kernel. + */ + +-extern int cpufreq_get_hardware_limits(unsigned int cpu, ++int cpufreq_get_hardware_limits(unsigned int cpu, + unsigned long *min, + unsigned long *max); + +@@ -104,9 +97,9 @@ extern int cpufreq_get_hardware_limits(unsigned int cpu, + * to avoid memory leakage, please. + */ + +-extern char *cpufreq_get_driver(unsigned int cpu); ++char *cpufreq_get_driver(unsigned int cpu); + +-extern void cpufreq_put_driver(char *ptr); ++void cpufreq_put_driver(char *ptr); + + + /* determine CPUfreq policy currently used +@@ -116,9 +109,9 @@ extern void cpufreq_put_driver(char *ptr); + */ + + +-extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); ++struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); + +-extern void cpufreq_put_policy(struct cpufreq_policy *policy); ++void cpufreq_put_policy(struct cpufreq_policy *policy); + + + /* determine CPUfreq governors currently available +@@ -129,10 +122,10 @@ extern void cpufreq_put_policy(struct cpufreq_policy *policy); + */ + + +-extern struct cpufreq_available_governors ++struct cpufreq_available_governors + *cpufreq_get_available_governors(unsigned int cpu); + +-extern void cpufreq_put_available_governors( ++void cpufreq_put_available_governors( + struct cpufreq_available_governors *first); + + +@@ -143,10 +136,10 @@ extern void cpufreq_put_available_governors( + * cpufreq_put_available_frequencies after use. + */ + +-extern struct cpufreq_available_frequencies ++struct cpufreq_available_frequencies + *cpufreq_get_available_frequencies(unsigned int cpu); + +-extern void cpufreq_put_available_frequencies( ++void cpufreq_put_available_frequencies( + struct cpufreq_available_frequencies *first); + + +@@ -156,10 +149,10 @@ extern void cpufreq_put_available_frequencies( + * to avoid memory leakage, please. + */ + +-extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned ++struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned + int cpu); + +-extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); ++void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); + + + /* determine related CPUs +@@ -168,10 +161,10 @@ extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); + * to avoid memory leakage, please. + */ + +-extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned ++struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned + int cpu); + +-extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); ++void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); + + + /* determine stats for cpufreq subsystem +@@ -179,12 +172,12 @@ extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); + * This is not available in all kernel versions or configurations. + */ + +-extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, ++struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, + unsigned long long *total_time); + +-extern void cpufreq_put_stats(struct cpufreq_stats *stats); ++void cpufreq_put_stats(struct cpufreq_stats *stats); + +-extern unsigned long cpufreq_get_transitions(unsigned int cpu); ++unsigned long cpufreq_get_transitions(unsigned int cpu); + + + /* set new cpufreq policy +@@ -193,7 +186,7 @@ extern unsigned long cpufreq_get_transitions(unsigned int cpu); + * but results may differ depending e.g. on governors being available. + */ + +-extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); ++int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); + + + /* modify a policy by only changing min/max freq or governor +@@ -201,9 +194,9 @@ extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); + * Does not check whether result is what was intended. + */ + +-extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); +-extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); +-extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); ++int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); ++int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); ++int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); + + + /* set a specific frequency +@@ -213,7 +206,7 @@ extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); + * occurs. Also does not work on ->range() cpufreq drivers. + */ + +-extern int cpufreq_set_frequency(unsigned int cpu, ++int cpufreq_set_frequency(unsigned int cpu, + unsigned long target_frequency); + + #ifdef __cplusplus +diff --git a/lib/cpuidle.c b/lib/cpuidle.c +new file mode 100644 +index 0000000..5b1928a +--- /dev/null ++++ b/lib/cpuidle.c +@@ -0,0 +1,380 @@ ++/* ++ * (C) 2004-2009 Dominik Brodowski ++ * (C) 2011 Thomas Renninger Novell Inc. ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpuidle.h" ++#include "cpupower_intern.h" ++ ++/* ++ * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir ++ * exists. ++ * For example the functionality to disable c-states was introduced in later ++ * kernel versions, this function can be used to explicitly check for this ++ * feature. ++ * ++ * returns 1 if the file exists, 0 otherwise. ++ */ ++static ++unsigned int cpuidle_state_file_exists(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname) ++{ ++ char path[SYSFS_PATH_MAX]; ++ struct stat statbuf; ++ ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", ++ cpu, idlestate, fname); ++ if (stat(path, &statbuf) != 0) ++ return 0; ++ return 1; ++} ++ ++/* ++ * helper function to read file from /sys into given buffer ++ * fname is a relative path under "cpuX/cpuidle/stateX/" dir ++ * cstates starting with 0, C0 is not counted as cstate. ++ * This means if you want C1 info, pass 0 as idlestate param ++ */ ++static ++unsigned int cpuidle_state_read_file(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname, char *buf, ++ size_t buflen) ++{ ++ char path[SYSFS_PATH_MAX]; ++ int fd; ++ ssize_t numread; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", ++ cpu, idlestate, fname); ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ numread = read(fd, buf, buflen - 1); ++ if (numread < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ buf[numread] = '\0'; ++ close(fd); ++ ++ return (unsigned int) numread; ++} ++ ++/* ++ * helper function to write a new value to a /sys file ++ * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir ++ * ++ * Returns the number of bytes written or 0 on error ++ */ ++static ++unsigned int cpuidle_state_write_file(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname, ++ const char *value, size_t len) ++{ ++ char path[SYSFS_PATH_MAX]; ++ int fd; ++ ssize_t numwrite; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", ++ cpu, idlestate, fname); ++ ++ fd = open(path, O_WRONLY); ++ if (fd == -1) ++ return 0; ++ ++ numwrite = write(fd, value, len); ++ if (numwrite < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ close(fd); ++ ++ return (unsigned int) numwrite; ++} ++ ++/* read access to files which contain one numeric value */ ++ ++enum idlestate_value { ++ IDLESTATE_USAGE, ++ IDLESTATE_POWER, ++ IDLESTATE_LATENCY, ++ IDLESTATE_TIME, ++ IDLESTATE_DISABLE, ++ MAX_IDLESTATE_VALUE_FILES ++}; ++ ++static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { ++ [IDLESTATE_USAGE] = "usage", ++ [IDLESTATE_POWER] = "power", ++ [IDLESTATE_LATENCY] = "latency", ++ [IDLESTATE_TIME] = "time", ++ [IDLESTATE_DISABLE] = "disable", ++}; ++ ++static ++unsigned long long cpuidle_state_get_one_value(unsigned int cpu, ++ unsigned int idlestate, ++ enum idlestate_value which) ++{ ++ unsigned long long value; ++ unsigned int len; ++ char linebuf[MAX_LINE_LEN]; ++ char *endp; ++ ++ if (which >= MAX_IDLESTATE_VALUE_FILES) ++ return 0; ++ ++ len = cpuidle_state_read_file(cpu, idlestate, ++ idlestate_value_files[which], ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return 0; ++ ++ value = strtoull(linebuf, &endp, 0); ++ ++ if (endp == linebuf || errno == ERANGE) ++ return 0; ++ ++ return value; ++} ++ ++/* read access to files which contain one string */ ++ ++enum idlestate_string { ++ IDLESTATE_DESC, ++ IDLESTATE_NAME, ++ MAX_IDLESTATE_STRING_FILES ++}; ++ ++static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { ++ [IDLESTATE_DESC] = "desc", ++ [IDLESTATE_NAME] = "name", ++}; ++ ++ ++static char *cpuidle_state_get_one_string(unsigned int cpu, ++ unsigned int idlestate, ++ enum idlestate_string which) ++{ ++ char linebuf[MAX_LINE_LEN]; ++ char *result; ++ unsigned int len; ++ ++ if (which >= MAX_IDLESTATE_STRING_FILES) ++ return NULL; ++ ++ len = cpuidle_state_read_file(cpu, idlestate, ++ idlestate_string_files[which], ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ result = strdup(linebuf); ++ if (result == NULL) ++ return NULL; ++ ++ if (result[strlen(result) - 1] == '\n') ++ result[strlen(result) - 1] = '\0'; ++ ++ return result; ++} ++ ++/* ++ * Returns: ++ * 1 if disabled ++ * 0 if enabled ++ * -1 if idlestate is not available ++ * -2 if disabling is not supported by the kernel ++ */ ++int cpuidle_is_state_disabled(unsigned int cpu, ++ unsigned int idlestate) ++{ ++ if (cpuidle_state_count(cpu) <= idlestate) ++ return -1; ++ ++ if (!cpuidle_state_file_exists(cpu, idlestate, ++ idlestate_value_files[IDLESTATE_DISABLE])) ++ return -2; ++ return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); ++} ++ ++/* ++ * Pass 1 as last argument to disable or 0 to enable the state ++ * Returns: ++ * 0 on success ++ * negative values on error, for example: ++ * -1 if idlestate is not available ++ * -2 if disabling is not supported by the kernel ++ * -3 No write access to disable/enable C-states ++ */ ++int cpuidle_state_disable(unsigned int cpu, ++ unsigned int idlestate, ++ unsigned int disable) ++{ ++ char value[SYSFS_PATH_MAX]; ++ int bytes_written; ++ ++ if (cpuidle_state_count(cpu) <= idlestate) ++ return -1; ++ ++ if (!cpuidle_state_file_exists(cpu, idlestate, ++ idlestate_value_files[IDLESTATE_DISABLE])) ++ return -2; ++ ++ snprintf(value, SYSFS_PATH_MAX, "%u", disable); ++ ++ bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable", ++ value, sizeof(disable)); ++ if (bytes_written) ++ return 0; ++ return -3; ++} ++ ++unsigned long cpuidle_state_latency(unsigned int cpu, ++ unsigned int idlestate) ++{ ++ return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); ++} ++ ++unsigned long cpuidle_state_usage(unsigned int cpu, ++ unsigned int idlestate) ++{ ++ return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE); ++} ++ ++unsigned long long cpuidle_state_time(unsigned int cpu, ++ unsigned int idlestate) ++{ ++ return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME); ++} ++ ++char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate) ++{ ++ return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME); ++} ++ ++char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate) ++{ ++ return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC); ++} ++ ++/* ++ * Returns number of supported C-states of CPU core cpu ++ * Negativ in error case ++ * Zero if cpuidle does not export any C-states ++ */ ++unsigned int cpuidle_state_count(unsigned int cpu) ++{ ++ char file[SYSFS_PATH_MAX]; ++ struct stat statbuf; ++ int idlestates = 1; ++ ++ ++ snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); ++ if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) ++ return 0; ++ ++ snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); ++ if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) ++ return 0; ++ ++ while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { ++ snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU ++ "cpu%u/cpuidle/state%d", cpu, idlestates); ++ idlestates++; ++ } ++ idlestates--; ++ return idlestates; ++} ++ ++/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ ++ ++/* ++ * helper function to read file from /sys into given buffer ++ * fname is a relative path under "cpu/cpuidle/" dir ++ */ ++static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, ++ size_t buflen) ++{ ++ char path[SYSFS_PATH_MAX]; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); ++ ++ return sysfs_read_file(path, buf, buflen); ++} ++ ++ ++ ++/* read access to files which contain one string */ ++ ++enum cpuidle_string { ++ CPUIDLE_GOVERNOR, ++ CPUIDLE_GOVERNOR_RO, ++ CPUIDLE_DRIVER, ++ MAX_CPUIDLE_STRING_FILES ++}; ++ ++static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { ++ [CPUIDLE_GOVERNOR] = "current_governor", ++ [CPUIDLE_GOVERNOR_RO] = "current_governor_ro", ++ [CPUIDLE_DRIVER] = "current_driver", ++}; ++ ++ ++static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) ++{ ++ char linebuf[MAX_LINE_LEN]; ++ char *result; ++ unsigned int len; ++ ++ if (which >= MAX_CPUIDLE_STRING_FILES) ++ return NULL; ++ ++ len = sysfs_cpuidle_read_file(cpuidle_string_files[which], ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return NULL; ++ ++ result = strdup(linebuf); ++ if (result == NULL) ++ return NULL; ++ ++ if (result[strlen(result) - 1] == '\n') ++ result[strlen(result) - 1] = '\0'; ++ ++ return result; ++} ++ ++char *cpuidle_get_governor(void) ++{ ++ char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); ++ if (!tmp) ++ return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); ++ else ++ return tmp; ++} ++ ++char *cpuidle_get_driver(void) ++{ ++ return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); ++} ++/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ +diff --git a/lib/cpuidle.h b/lib/cpuidle.h +new file mode 100644 +index 0000000..04eb3cf +--- /dev/null ++++ b/lib/cpuidle.h +@@ -0,0 +1,23 @@ ++#ifndef __CPUPOWER_CPUIDLE_H__ ++#define __CPUPOWER_CPUIDLE_H__ ++ ++int cpuidle_is_state_disabled(unsigned int cpu, ++ unsigned int idlestate); ++int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate, ++ unsigned int disable); ++unsigned long cpuidle_state_latency(unsigned int cpu, ++ unsigned int idlestate); ++unsigned long cpuidle_state_usage(unsigned int cpu, ++ unsigned int idlestate); ++unsigned long long cpuidle_state_time(unsigned int cpu, ++ unsigned int idlestate); ++char *cpuidle_state_name(unsigned int cpu, ++ unsigned int idlestate); ++char *cpuidle_state_desc(unsigned int cpu, ++ unsigned int idlestate); ++unsigned int cpuidle_state_count(unsigned int cpu); ++ ++char *cpuidle_get_governor(void); ++char *cpuidle_get_driver(void); ++ ++#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */ +diff --git a/lib/cpupower.c b/lib/cpupower.c +new file mode 100644 +index 0000000..9c395ec9 +--- /dev/null ++++ b/lib/cpupower.c +@@ -0,0 +1,192 @@ ++/* ++ * (C) 2004-2009 Dominik Brodowski ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "cpupower.h" ++#include "cpupower_intern.h" ++ ++unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) ++{ ++ int fd; ++ ssize_t numread; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ numread = read(fd, buf, buflen - 1); ++ if (numread < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ buf[numread] = '\0'; ++ close(fd); ++ ++ return (unsigned int) numread; ++} ++ ++/* ++ * Detect whether a CPU is online ++ * ++ * Returns: ++ * 1 -> if CPU is online ++ * 0 -> if CPU is offline ++ * negative errno values in error case ++ */ ++int cpupower_is_cpu_online(unsigned int cpu) ++{ ++ char path[SYSFS_PATH_MAX]; ++ int fd; ++ ssize_t numread; ++ unsigned long long value; ++ char linebuf[MAX_LINE_LEN]; ++ char *endp; ++ struct stat statbuf; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); ++ ++ if (stat(path, &statbuf) != 0) ++ return 0; ++ ++ /* ++ * kernel without CONFIG_HOTPLUG_CPU ++ * -> cpuX directory exists, but not cpuX/online file ++ */ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); ++ if (stat(path, &statbuf) != 0) ++ return 1; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return -errno; ++ ++ numread = read(fd, linebuf, MAX_LINE_LEN - 1); ++ if (numread < 1) { ++ close(fd); ++ return -EIO; ++ } ++ linebuf[numread] = '\0'; ++ close(fd); ++ ++ value = strtoull(linebuf, &endp, 0); ++ if (value > 1) ++ return -EINVAL; ++ ++ return value; ++} ++ ++/* returns -1 on failure, 0 on success */ ++static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) ++{ ++ char linebuf[MAX_LINE_LEN]; ++ char *endp; ++ char path[SYSFS_PATH_MAX]; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", ++ cpu, fname); ++ if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) ++ return -1; ++ *result = strtol(linebuf, &endp, 0); ++ if (endp == linebuf || errno == ERANGE) ++ return -1; ++ return 0; ++} ++ ++static int __compare(const void *t1, const void *t2) ++{ ++ struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; ++ struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; ++ if (top1->pkg < top2->pkg) ++ return -1; ++ else if (top1->pkg > top2->pkg) ++ return 1; ++ else if (top1->core < top2->core) ++ return -1; ++ else if (top1->core > top2->core) ++ return 1; ++ else if (top1->cpu < top2->cpu) ++ return -1; ++ else if (top1->cpu > top2->cpu) ++ return 1; ++ else ++ return 0; ++} ++ ++/* ++ * Returns amount of cpus, negative on error, cpu_top must be ++ * passed to cpu_topology_release to free resources ++ * ++ * Array is sorted after ->pkg, ->core, then ->cpu ++ */ ++int get_cpu_topology(struct cpupower_topology *cpu_top) ++{ ++ int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); ++ ++ cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); ++ if (cpu_top->core_info == NULL) ++ return -ENOMEM; ++ cpu_top->pkgs = cpu_top->cores = 0; ++ for (cpu = 0; cpu < cpus; cpu++) { ++ cpu_top->core_info[cpu].cpu = cpu; ++ cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu); ++ if(sysfs_topology_read_file( ++ cpu, ++ "physical_package_id", ++ &(cpu_top->core_info[cpu].pkg)) < 0) { ++ cpu_top->core_info[cpu].pkg = -1; ++ cpu_top->core_info[cpu].core = -1; ++ continue; ++ } ++ if(sysfs_topology_read_file( ++ cpu, ++ "core_id", ++ &(cpu_top->core_info[cpu].core)) < 0) { ++ cpu_top->core_info[cpu].pkg = -1; ++ cpu_top->core_info[cpu].core = -1; ++ continue; ++ } ++ } ++ ++ qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), ++ __compare); ++ ++ /* Count the number of distinct pkgs values. This works ++ because the primary sort of the core_info struct was just ++ done by pkg value. */ ++ last_pkg = cpu_top->core_info[0].pkg; ++ for(cpu = 1; cpu < cpus; cpu++) { ++ if (cpu_top->core_info[cpu].pkg != last_pkg && ++ cpu_top->core_info[cpu].pkg != -1) { ++ ++ last_pkg = cpu_top->core_info[cpu].pkg; ++ cpu_top->pkgs++; ++ } ++ } ++ if (!(cpu_top->core_info[0].pkg == -1)) ++ cpu_top->pkgs++; ++ ++ /* Intel's cores count is not consecutively numbered, there may ++ * be a core_id of 3, but none of 2. Assume there always is 0 ++ * Get amount of cores by counting duplicates in a package ++ for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { ++ if (cpu_top->core_info[cpu].core == 0) ++ cpu_top->cores++; ++ */ ++ return cpus; ++} ++ ++void cpu_topology_release(struct cpupower_topology cpu_top) ++{ ++ free(cpu_top.core_info); ++} +diff --git a/lib/cpupower.h b/lib/cpupower.h +new file mode 100644 +index 0000000..fa031fc +--- /dev/null ++++ b/lib/cpupower.h +@@ -0,0 +1,35 @@ ++#ifndef __CPUPOWER_CPUPOWER_H__ ++#define __CPUPOWER_CPUPOWER_H__ ++ ++struct cpupower_topology { ++ /* Amount of CPU cores, packages and threads per core in the system */ ++ unsigned int cores; ++ unsigned int pkgs; ++ unsigned int threads; /* per core */ ++ ++ /* Array gets mallocated with cores entries, holding per core info */ ++ struct cpuid_core_info *core_info; ++}; ++ ++struct cpuid_core_info { ++ int pkg; ++ int core; ++ int cpu; ++ ++ /* flags */ ++ unsigned int is_online:1; ++}; ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++int get_cpu_topology(struct cpupower_topology *cpu_top); ++void cpu_topology_release(struct cpupower_topology cpu_top); ++int cpupower_is_cpu_online(unsigned int cpu); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/lib/cpupower_intern.h b/lib/cpupower_intern.h +new file mode 100644 +index 0000000..f8ec400 +--- /dev/null ++++ b/lib/cpupower_intern.h +@@ -0,0 +1,5 @@ ++#define PATH_TO_CPU "/sys/devices/system/cpu/" ++#define MAX_LINE_LEN 4096 ++#define SYSFS_PATH_MAX 255 ++ ++unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); +diff --git a/lib/sysfs.c b/lib/sysfs.c +deleted file mode 100644 +index 870713a..0000000 +--- a/lib/sysfs.c ++++ /dev/null +@@ -1,672 +0,0 @@ +-/* +- * (C) 2004-2009 Dominik Brodowski +- * +- * Licensed under the terms of the GNU GPL License version 2. +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "cpufreq.h" +- +-#define PATH_TO_CPU "/sys/devices/system/cpu/" +-#define MAX_LINE_LEN 4096 +-#define SYSFS_PATH_MAX 255 +- +- +-static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) +-{ +- int fd; +- ssize_t numread; +- +- fd = open(path, O_RDONLY); +- if (fd == -1) +- return 0; +- +- numread = read(fd, buf, buflen - 1); +- if (numread < 1) { +- close(fd); +- return 0; +- } +- +- buf[numread] = '\0'; +- close(fd); +- +- return (unsigned int) numread; +-} +- +- +-/* CPUFREQ sysfs access **************************************************/ +- +-/* helper function to read file from /sys into given buffer */ +-/* fname is a relative path under "cpuX/cpufreq" dir */ +-static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, +- char *buf, size_t buflen) +-{ +- char path[SYSFS_PATH_MAX]; +- +- snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", +- cpu, fname); +- return sysfs_read_file(path, buf, buflen); +-} +- +-/* helper function to write a new value to a /sys file */ +-/* fname is a relative path under "cpuX/cpufreq" dir */ +-static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, +- const char *fname, +- const char *value, size_t len) +-{ +- char path[SYSFS_PATH_MAX]; +- int fd; +- ssize_t numwrite; +- +- snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", +- cpu, fname); +- +- fd = open(path, O_WRONLY); +- if (fd == -1) +- return 0; +- +- numwrite = write(fd, value, len); +- if (numwrite < 1) { +- close(fd); +- return 0; +- } +- +- close(fd); +- +- return (unsigned int) numwrite; +-} +- +-/* read access to files which contain one numeric value */ +- +-enum cpufreq_value { +- CPUINFO_CUR_FREQ, +- CPUINFO_MIN_FREQ, +- CPUINFO_MAX_FREQ, +- CPUINFO_LATENCY, +- SCALING_CUR_FREQ, +- SCALING_MIN_FREQ, +- SCALING_MAX_FREQ, +- STATS_NUM_TRANSITIONS, +- MAX_CPUFREQ_VALUE_READ_FILES +-}; +- +-static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { +- [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", +- [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", +- [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", +- [CPUINFO_LATENCY] = "cpuinfo_transition_latency", +- [SCALING_CUR_FREQ] = "scaling_cur_freq", +- [SCALING_MIN_FREQ] = "scaling_min_freq", +- [SCALING_MAX_FREQ] = "scaling_max_freq", +- [STATS_NUM_TRANSITIONS] = "stats/total_trans" +-}; +- +- +-static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, +- enum cpufreq_value which) +-{ +- unsigned long value; +- unsigned int len; +- char linebuf[MAX_LINE_LEN]; +- char *endp; +- +- if (which >= MAX_CPUFREQ_VALUE_READ_FILES) +- return 0; +- +- len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], +- linebuf, sizeof(linebuf)); +- +- if (len == 0) +- return 0; +- +- value = strtoul(linebuf, &endp, 0); +- +- if (endp == linebuf || errno == ERANGE) +- return 0; +- +- return value; +-} +- +-/* read access to files which contain one string */ +- +-enum cpufreq_string { +- SCALING_DRIVER, +- SCALING_GOVERNOR, +- MAX_CPUFREQ_STRING_FILES +-}; +- +-static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { +- [SCALING_DRIVER] = "scaling_driver", +- [SCALING_GOVERNOR] = "scaling_governor", +-}; +- +- +-static char *sysfs_cpufreq_get_one_string(unsigned int cpu, +- enum cpufreq_string which) +-{ +- char linebuf[MAX_LINE_LEN]; +- char *result; +- unsigned int len; +- +- if (which >= MAX_CPUFREQ_STRING_FILES) +- return NULL; +- +- len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], +- linebuf, sizeof(linebuf)); +- if (len == 0) +- return NULL; +- +- result = strdup(linebuf); +- if (result == NULL) +- return NULL; +- +- if (result[strlen(result) - 1] == '\n') +- result[strlen(result) - 1] = '\0'; +- +- return result; +-} +- +-/* write access */ +- +-enum cpufreq_write { +- WRITE_SCALING_MIN_FREQ, +- WRITE_SCALING_MAX_FREQ, +- WRITE_SCALING_GOVERNOR, +- WRITE_SCALING_SET_SPEED, +- MAX_CPUFREQ_WRITE_FILES +-}; +- +-static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { +- [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", +- [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", +- [WRITE_SCALING_GOVERNOR] = "scaling_governor", +- [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", +-}; +- +-static int sysfs_cpufreq_write_one_value(unsigned int cpu, +- enum cpufreq_write which, +- const char *new_value, size_t len) +-{ +- if (which >= MAX_CPUFREQ_WRITE_FILES) +- return 0; +- +- if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], +- new_value, len) != len) +- return -ENODEV; +- +- return 0; +-}; +- +-unsigned long sysfs_get_freq_kernel(unsigned int cpu) +-{ +- return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); +-} +- +-unsigned long sysfs_get_freq_hardware(unsigned int cpu) +-{ +- return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); +-} +- +-unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) +-{ +- return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); +-} +- +-int sysfs_get_freq_hardware_limits(unsigned int cpu, +- unsigned long *min, +- unsigned long *max) +-{ +- if ((!min) || (!max)) +- return -EINVAL; +- +- *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); +- if (!*min) +- return -ENODEV; +- +- *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); +- if (!*max) +- return -ENODEV; +- +- return 0; +-} +- +-char *sysfs_get_freq_driver(unsigned int cpu) +-{ +- return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); +-} +- +-struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) +-{ +- struct cpufreq_policy *policy; +- +- policy = malloc(sizeof(struct cpufreq_policy)); +- if (!policy) +- return NULL; +- +- policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); +- if (!policy->governor) { +- free(policy); +- return NULL; +- } +- policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); +- policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); +- if ((!policy->min) || (!policy->max)) { +- free(policy->governor); +- free(policy); +- return NULL; +- } +- +- return policy; +-} +- +-struct cpufreq_available_governors * +-sysfs_get_freq_available_governors(unsigned int cpu) { +- struct cpufreq_available_governors *first = NULL; +- struct cpufreq_available_governors *current = NULL; +- char linebuf[MAX_LINE_LEN]; +- unsigned int pos, i; +- unsigned int len; +- +- len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", +- linebuf, sizeof(linebuf)); +- if (len == 0) +- return NULL; +- +- pos = 0; +- for (i = 0; i < len; i++) { +- if (linebuf[i] == ' ' || linebuf[i] == '\n') { +- if (i - pos < 2) +- continue; +- if (current) { +- current->next = malloc(sizeof(*current)); +- if (!current->next) +- goto error_out; +- current = current->next; +- } else { +- first = malloc(sizeof(*first)); +- if (!first) +- goto error_out; +- current = first; +- } +- current->first = first; +- current->next = NULL; +- +- current->governor = malloc(i - pos + 1); +- if (!current->governor) +- goto error_out; +- +- memcpy(current->governor, linebuf + pos, i - pos); +- current->governor[i - pos] = '\0'; +- pos = i + 1; +- } +- } +- +- return first; +- +- error_out: +- while (first) { +- current = first->next; +- if (first->governor) +- free(first->governor); +- free(first); +- first = current; +- } +- return NULL; +-} +- +- +-struct cpufreq_available_frequencies * +-sysfs_get_available_frequencies(unsigned int cpu) { +- struct cpufreq_available_frequencies *first = NULL; +- struct cpufreq_available_frequencies *current = NULL; +- char one_value[SYSFS_PATH_MAX]; +- char linebuf[MAX_LINE_LEN]; +- unsigned int pos, i; +- unsigned int len; +- +- len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", +- linebuf, sizeof(linebuf)); +- if (len == 0) +- return NULL; +- +- pos = 0; +- for (i = 0; i < len; i++) { +- if (linebuf[i] == ' ' || linebuf[i] == '\n') { +- if (i - pos < 2) +- continue; +- if (i - pos >= SYSFS_PATH_MAX) +- goto error_out; +- if (current) { +- current->next = malloc(sizeof(*current)); +- if (!current->next) +- goto error_out; +- current = current->next; +- } else { +- first = malloc(sizeof(*first)); +- if (!first) +- goto error_out; +- current = first; +- } +- current->first = first; +- current->next = NULL; +- +- memcpy(one_value, linebuf + pos, i - pos); +- one_value[i - pos] = '\0'; +- if (sscanf(one_value, "%lu", ¤t->frequency) != 1) +- goto error_out; +- +- pos = i + 1; +- } +- } +- +- return first; +- +- error_out: +- while (first) { +- current = first->next; +- free(first); +- first = current; +- } +- return NULL; +-} +- +-static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, +- const char *file) +-{ +- struct cpufreq_affected_cpus *first = NULL; +- struct cpufreq_affected_cpus *current = NULL; +- char one_value[SYSFS_PATH_MAX]; +- char linebuf[MAX_LINE_LEN]; +- unsigned int pos, i; +- unsigned int len; +- +- len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); +- if (len == 0) +- return NULL; +- +- pos = 0; +- for (i = 0; i < len; i++) { +- if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { +- if (i - pos < 1) +- continue; +- if (i - pos >= SYSFS_PATH_MAX) +- goto error_out; +- if (current) { +- current->next = malloc(sizeof(*current)); +- if (!current->next) +- goto error_out; +- current = current->next; +- } else { +- first = malloc(sizeof(*first)); +- if (!first) +- goto error_out; +- current = first; +- } +- current->first = first; +- current->next = NULL; +- +- memcpy(one_value, linebuf + pos, i - pos); +- one_value[i - pos] = '\0'; +- +- if (sscanf(one_value, "%u", ¤t->cpu) != 1) +- goto error_out; +- +- pos = i + 1; +- } +- } +- +- return first; +- +- error_out: +- while (first) { +- current = first->next; +- free(first); +- first = current; +- } +- return NULL; +-} +- +-struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) +-{ +- return sysfs_get_cpu_list(cpu, "affected_cpus"); +-} +- +-struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) +-{ +- return sysfs_get_cpu_list(cpu, "related_cpus"); +-} +- +-struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, +- unsigned long long *total_time) { +- struct cpufreq_stats *first = NULL; +- struct cpufreq_stats *current = NULL; +- char one_value[SYSFS_PATH_MAX]; +- char linebuf[MAX_LINE_LEN]; +- unsigned int pos, i; +- unsigned int len; +- +- len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", +- linebuf, sizeof(linebuf)); +- if (len == 0) +- return NULL; +- +- *total_time = 0; +- pos = 0; +- for (i = 0; i < len; i++) { +- if (i == strlen(linebuf) || linebuf[i] == '\n') { +- if (i - pos < 2) +- continue; +- if ((i - pos) >= SYSFS_PATH_MAX) +- goto error_out; +- if (current) { +- current->next = malloc(sizeof(*current)); +- if (!current->next) +- goto error_out; +- current = current->next; +- } else { +- first = malloc(sizeof(*first)); +- if (!first) +- goto error_out; +- current = first; +- } +- current->first = first; +- current->next = NULL; +- +- memcpy(one_value, linebuf + pos, i - pos); +- one_value[i - pos] = '\0'; +- if (sscanf(one_value, "%lu %llu", +- ¤t->frequency, +- ¤t->time_in_state) != 2) +- goto error_out; +- +- *total_time = *total_time + current->time_in_state; +- pos = i + 1; +- } +- } +- +- return first; +- +- error_out: +- while (first) { +- current = first->next; +- free(first); +- first = current; +- } +- return NULL; +-} +- +-unsigned long sysfs_get_freq_transitions(unsigned int cpu) +-{ +- return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); +-} +- +-static int verify_gov(char *new_gov, char *passed_gov) +-{ +- unsigned int i, j = 0; +- +- if (!passed_gov || (strlen(passed_gov) > 19)) +- return -EINVAL; +- +- strncpy(new_gov, passed_gov, 20); +- for (i = 0; i < 20; i++) { +- if (j) { +- new_gov[i] = '\0'; +- continue; +- } +- if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) +- continue; +- +- if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) +- continue; +- +- if (new_gov[i] == '-') +- continue; +- +- if (new_gov[i] == '_') +- continue; +- +- if (new_gov[i] == '\0') { +- j = 1; +- continue; +- } +- return -EINVAL; +- } +- new_gov[19] = '\0'; +- return 0; +-} +- +-int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) +-{ +- char new_gov[SYSFS_PATH_MAX]; +- +- if (!governor) +- return -EINVAL; +- +- if (verify_gov(new_gov, governor)) +- return -EINVAL; +- +- return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, +- new_gov, strlen(new_gov)); +-}; +- +-int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) +-{ +- char value[SYSFS_PATH_MAX]; +- +- snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); +- +- return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +- value, strlen(value)); +-}; +- +- +-int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) +-{ +- char value[SYSFS_PATH_MAX]; +- +- snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); +- +- return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, +- value, strlen(value)); +-}; +- +- +-int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) +-{ +- char min[SYSFS_PATH_MAX]; +- char max[SYSFS_PATH_MAX]; +- char gov[SYSFS_PATH_MAX]; +- int ret; +- unsigned long old_min; +- int write_max_first; +- +- if (!policy || !(policy->governor)) +- return -EINVAL; +- +- if (policy->max < policy->min) +- return -EINVAL; +- +- if (verify_gov(gov, policy->governor)) +- return -EINVAL; +- +- snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); +- snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); +- +- old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); +- write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); +- +- if (write_max_first) { +- ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +- max, strlen(max)); +- if (ret) +- return ret; +- } +- +- ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, +- strlen(min)); +- if (ret) +- return ret; +- +- if (!write_max_first) { +- ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +- max, strlen(max)); +- if (ret) +- return ret; +- } +- +- return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, +- gov, strlen(gov)); +-} +- +-int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) +-{ +- struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); +- char userspace_gov[] = "userspace"; +- char freq[SYSFS_PATH_MAX]; +- int ret; +- +- if (!pol) +- return -ENODEV; +- +- if (strncmp(pol->governor, userspace_gov, 9) != 0) { +- ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); +- if (ret) { +- cpufreq_put_policy(pol); +- return ret; +- } +- } +- +- cpufreq_put_policy(pol); +- +- snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); +- +- return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, +- freq, strlen(freq)); +-} +- +-/* CPUFREQ sysfs access **************************************************/ +- +-/* General sysfs access **************************************************/ +-int sysfs_cpu_exists(unsigned int cpu) +-{ +- char file[SYSFS_PATH_MAX]; +- struct stat statbuf; +- +- snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); +- +- if (stat(file, &statbuf) != 0) +- return -ENOSYS; +- +- return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; +-} +- +-/* General sysfs access **************************************************/ +diff --git a/lib/sysfs.h b/lib/sysfs.h +deleted file mode 100644 +index c76a5e0..0000000 +--- a/lib/sysfs.h ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* General */ +-extern unsigned int sysfs_cpu_exists(unsigned int cpu); +- +-/* CPUfreq */ +-extern unsigned long sysfs_get_freq_kernel(unsigned int cpu); +-extern unsigned long sysfs_get_freq_hardware(unsigned int cpu); +-extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu); +-extern int sysfs_get_freq_hardware_limits(unsigned int cpu, +- unsigned long *min, unsigned long *max); +-extern char *sysfs_get_freq_driver(unsigned int cpu); +-extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu); +-extern struct cpufreq_available_governors *sysfs_get_freq_available_governors( +- unsigned int cpu); +-extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies( +- unsigned int cpu); +-extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus( +- unsigned int cpu); +-extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus( +- unsigned int cpu); +-extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, +- unsigned long long *total_time); +-extern unsigned long sysfs_get_freq_transitions(unsigned int cpu); +-extern int sysfs_set_freq_policy(unsigned int cpu, +- struct cpufreq_policy *policy); +-extern int sysfs_modify_freq_policy_min(unsigned int cpu, +- unsigned long min_freq); +-extern int sysfs_modify_freq_policy_max(unsigned int cpu, +- unsigned long max_freq); +-extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor); +-extern int sysfs_set_frequency(unsigned int cpu, +- unsigned long target_frequency); +diff --git a/utils/cpufreq-info.c b/utils/cpufreq-info.c +index 0e67643..e9679f4 100644 +--- a/utils/cpufreq-info.c ++++ b/utils/cpufreq-info.c +@@ -256,7 +256,7 @@ static void debug_output_one(unsigned int cpu) + struct cpufreq_available_governors *governors; + struct cpufreq_stats *stats; + +- if (cpufreq_cpu_exists(cpu)) ++ if (cpupower_is_cpu_online(cpu)) + return; + + freq_kernel = cpufreq_get_freq_kernel(cpu); +@@ -647,7 +647,7 @@ int cmd_freq_info(int argc, char **argv) + + if (!bitmask_isbitset(cpus_chosen, cpu)) + continue; +- if (cpufreq_cpu_exists(cpu)) { ++ if (cpupower_is_cpu_online(cpu)) { + printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); + continue; + } +diff --git a/utils/cpufreq-set.c b/utils/cpufreq-set.c +index 0fbd1a2..b4bf769 100644 +--- a/utils/cpufreq-set.c ++++ b/utils/cpufreq-set.c +@@ -16,8 +16,8 @@ + #include + + #include "cpufreq.h" ++#include "cpuidle.h" + #include "helpers/helpers.h" +-#include "helpers/sysfs.h" + + #define NORM_FREQ_LEN 32 + +@@ -296,7 +296,7 @@ int cmd_freq_set(int argc, char **argv) + struct cpufreq_affected_cpus *cpus; + + if (!bitmask_isbitset(cpus_chosen, cpu) || +- cpufreq_cpu_exists(cpu)) ++ cpupower_is_cpu_online(cpu)) + continue; + + cpus = cpufreq_get_related_cpus(cpu); +@@ -316,10 +316,10 @@ int cmd_freq_set(int argc, char **argv) + cpu <= bitmask_last(cpus_chosen); cpu++) { + + if (!bitmask_isbitset(cpus_chosen, cpu) || +- cpufreq_cpu_exists(cpu)) ++ cpupower_is_cpu_online(cpu)) + continue; + +- if (sysfs_is_cpu_online(cpu) != 1) ++ if (cpupower_is_cpu_online(cpu) != 1) + continue; + + printf(_("Setting cpu: %d\n"), cpu); +diff --git a/utils/cpuidle-info.c b/utils/cpuidle-info.c +index 750c1d8..8473ec4 100644 +--- a/utils/cpuidle-info.c ++++ b/utils/cpuidle-info.c +@@ -13,9 +13,9 @@ + #include + #include + #include ++#include + + #include "helpers/helpers.h" +-#include "helpers/sysfs.h" + #include "helpers/bitmask.h" + + #define LINE_LEN 10 +@@ -27,7 +27,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) + + printf(_ ("Analyzing CPU %d:\n"), cpu); + +- idlestates = sysfs_get_idlestate_count(cpu); ++ idlestates = cpuidle_state_count(cpu); + if (idlestates == 0) { + printf(_("CPU %u: No idle states\n"), cpu); + return; +@@ -36,7 +36,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) + printf(_("Number of idle states: %d\n"), idlestates); + printf(_("Available idle states:")); + for (idlestate = 0; idlestate < idlestates; idlestate++) { +- tmp = sysfs_get_idlestate_name(cpu, idlestate); ++ tmp = cpuidle_state_name(cpu, idlestate); + if (!tmp) + continue; + printf(" %s", tmp); +@@ -48,28 +48,28 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) + return; + + for (idlestate = 0; idlestate < idlestates; idlestate++) { +- int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); ++ int disabled = cpuidle_is_state_disabled(cpu, idlestate); + /* Disabled interface not supported on older kernels */ + if (disabled < 0) + disabled = 0; +- tmp = sysfs_get_idlestate_name(cpu, idlestate); ++ tmp = cpuidle_state_name(cpu, idlestate); + if (!tmp) + continue; + printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); + free(tmp); + +- tmp = sysfs_get_idlestate_desc(cpu, idlestate); ++ tmp = cpuidle_state_desc(cpu, idlestate); + if (!tmp) + continue; + printf(_("Flags/Description: %s\n"), tmp); + free(tmp); + + printf(_("Latency: %lu\n"), +- sysfs_get_idlestate_latency(cpu, idlestate)); ++ cpuidle_state_latency(cpu, idlestate)); + printf(_("Usage: %lu\n"), +- sysfs_get_idlestate_usage(cpu, idlestate)); ++ cpuidle_state_usage(cpu, idlestate)); + printf(_("Duration: %llu\n"), +- sysfs_get_idlestate_time(cpu, idlestate)); ++ cpuidle_state_time(cpu, idlestate)); + } + printf("\n"); + } +@@ -78,7 +78,7 @@ static void cpuidle_general_output(void) + { + char *tmp; + +- tmp = sysfs_get_cpuidle_driver(); ++ tmp = cpuidle_get_driver(); + if (!tmp) { + printf(_("Could not determine cpuidle driver\n")); + return; +@@ -87,7 +87,7 @@ static void cpuidle_general_output(void) + printf(_("CPUidle driver: %s\n"), tmp); + free(tmp); + +- tmp = sysfs_get_cpuidle_governor(); ++ tmp = cpuidle_get_governor(); + if (!tmp) { + printf(_("Could not determine cpuidle governor\n")); + return; +@@ -102,7 +102,7 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) + long max_allowed_cstate = 2000000000; + unsigned int cstate, cstates; + +- cstates = sysfs_get_idlestate_count(cpu); ++ cstates = cpuidle_state_count(cpu); + if (cstates == 0) { + printf(_("CPU %u: No C-states info\n"), cpu); + return; +@@ -117,11 +117,11 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) + "type[C%d] "), cstate, cstate); + printf(_("promotion[--] demotion[--] ")); + printf(_("latency[%03lu] "), +- sysfs_get_idlestate_latency(cpu, cstate)); ++ cpuidle_state_latency(cpu, cstate)); + printf(_("usage[%08lu] "), +- sysfs_get_idlestate_usage(cpu, cstate)); ++ cpuidle_state_usage(cpu, cstate)); + printf(_("duration[%020Lu] \n"), +- sysfs_get_idlestate_time(cpu, cstate)); ++ cpuidle_state_time(cpu, cstate)); + } + } + +@@ -190,7 +190,7 @@ int cmd_idle_info(int argc, char **argv) + cpu <= bitmask_last(cpus_chosen); cpu++) { + + if (!bitmask_isbitset(cpus_chosen, cpu) || +- cpufreq_cpu_exists(cpu)) ++ cpupower_is_cpu_online(cpu)) + continue; + + switch (output_param) { +diff --git a/utils/cpuidle-set.c b/utils/cpuidle-set.c +index d6b6ae4..691c24d 100644 +--- a/utils/cpuidle-set.c ++++ b/utils/cpuidle-set.c +@@ -5,12 +5,12 @@ + #include + #include + #include +- + #include + +-#include "cpufreq.h" ++#include ++#include ++ + #include "helpers/helpers.h" +-#include "helpers/sysfs.h" + + static struct option info_opts[] = { + {"disable", required_argument, NULL, 'd'}, +@@ -104,16 +104,16 @@ int cmd_idle_set(int argc, char **argv) + if (!bitmask_isbitset(cpus_chosen, cpu)) + continue; + +- if (sysfs_is_cpu_online(cpu) != 1) ++ if (cpupower_is_cpu_online(cpu) != 1) + continue; + +- idlestates = sysfs_get_idlestate_count(cpu); ++ idlestates = cpuidle_state_count(cpu); + if (idlestates <= 0) + continue; + + switch (param) { + case 'd': +- ret = sysfs_idlestate_disable(cpu, idlestate, 1); ++ ret = cpuidle_state_disable(cpu, idlestate, 1); + if (ret == 0) + printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); + else if (ret == -1) +@@ -126,7 +126,7 @@ int cmd_idle_set(int argc, char **argv) + idlestate, cpu); + break; + case 'e': +- ret = sysfs_idlestate_disable(cpu, idlestate, 0); ++ ret = cpuidle_state_disable(cpu, idlestate, 0); + if (ret == 0) + printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); + else if (ret == -1) +@@ -140,13 +140,13 @@ int cmd_idle_set(int argc, char **argv) + break; + case 'D': + for (idlestate = 0; idlestate < idlestates; idlestate++) { +- disabled = sysfs_is_idlestate_disabled ++ disabled = cpuidle_is_state_disabled + (cpu, idlestate); +- state_latency = sysfs_get_idlestate_latency ++ state_latency = cpuidle_state_latency + (cpu, idlestate); + if (disabled == 1) { + if (latency > state_latency){ +- ret = sysfs_idlestate_disable ++ ret = cpuidle_state_disable + (cpu, idlestate, 0); + if (ret == 0) + printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); +@@ -154,7 +154,7 @@ int cmd_idle_set(int argc, char **argv) + continue; + } + if (latency <= state_latency){ +- ret = sysfs_idlestate_disable ++ ret = cpuidle_state_disable + (cpu, idlestate, 1); + if (ret == 0) + printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); +@@ -163,10 +163,10 @@ int cmd_idle_set(int argc, char **argv) + break; + case 'E': + for (idlestate = 0; idlestate < idlestates; idlestate++) { +- disabled = sysfs_is_idlestate_disabled ++ disabled = cpuidle_is_state_disabled + (cpu, idlestate); + if (disabled == 1) { +- ret = sysfs_idlestate_disable ++ ret = cpuidle_state_disable + (cpu, idlestate, 0); + if (ret == 0) + printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); +diff --git a/utils/cpupower-info.c b/utils/cpupower-info.c +index 10299f2..0a02485 100644 +--- a/utils/cpupower-info.c ++++ b/utils/cpupower-info.c +@@ -13,8 +13,9 @@ + #include + + #include ++#include ++ + #include "helpers/helpers.h" +-#include "helpers/sysfs.h" + + static struct option set_opts[] = { + {"perf-bias", optional_argument, NULL, 'b'}, +@@ -84,7 +85,7 @@ int cmd_info(int argc, char **argv) + cpu <= bitmask_last(cpus_chosen); cpu++) { + + if (!bitmask_isbitset(cpus_chosen, cpu) || +- cpufreq_cpu_exists(cpu)) ++ cpupower_is_cpu_online(cpu)) + continue; + + printf(_("analyzing CPU %d:\n"), cpu); +diff --git a/utils/cpupower-set.c b/utils/cpupower-set.c +index 3e6f374..cf24c09 100644 +--- a/utils/cpupower-set.c ++++ b/utils/cpupower-set.c +@@ -12,9 +12,9 @@ + #include + #include + +-#include ++#include ++ + #include "helpers/helpers.h" +-#include "helpers/sysfs.h" + #include "helpers/bitmask.h" + + static struct option set_opts[] = { +@@ -79,7 +79,7 @@ int cmd_set(int argc, char **argv) + cpu <= bitmask_last(cpus_chosen); cpu++) { + + if (!bitmask_isbitset(cpus_chosen, cpu) || +- cpufreq_cpu_exists(cpu)) ++ cpupower_is_cpu_online(cpu)) + continue; + + if (params.perf_bias) { +diff --git a/utils/helpers/helpers.h b/utils/helpers/helpers.h +index aa9e954..afb66f8 100644 +--- a/utils/helpers/helpers.h ++++ b/utils/helpers/helpers.h +@@ -14,6 +14,7 @@ + #include + + #include "helpers/bitmask.h" ++#include + + /* Internationalization ****************************/ + #ifdef NLS +@@ -92,31 +93,6 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); + extern struct cpupower_cpu_info cpupower_cpu_info; + /* cpuid and cpuinfo helpers **************************/ + +-struct cpuid_core_info { +- int pkg; +- int core; +- int cpu; +- +- /* flags */ +- unsigned int is_online:1; +-}; +- +-/* CPU topology/hierarchy parsing ******************/ +-struct cpupower_topology { +- /* Amount of CPU cores, packages and threads per core in the system */ +- unsigned int cores; +- unsigned int pkgs; +- unsigned int threads; /* per core */ +- +- /* Array gets mallocated with cores entries, holding per core info */ +- struct cpuid_core_info *core_info; +-}; +- +-extern int get_cpu_topology(struct cpupower_topology *cpu_top); +-extern void cpu_topology_release(struct cpupower_topology cpu_top); +- +-/* CPU topology/hierarchy parsing ******************/ +- + /* X86 ONLY ****************************************/ + #if defined(__i386__) || defined(__x86_64__) + +diff --git a/utils/helpers/topology.c b/utils/helpers/topology.c +index 5f9c908..a1a6c60 100644 +--- a/utils/helpers/topology.c ++++ b/utils/helpers/topology.c +@@ -16,110 +16,7 @@ + #include + #include + +-#include +-#include ++#include + +-/* returns -1 on failure, 0 on success */ +-static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) +-{ +- char linebuf[MAX_LINE_LEN]; +- char *endp; +- char path[SYSFS_PATH_MAX]; ++/* CPU topology/hierarchy parsing ******************/ + +- snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", +- cpu, fname); +- if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) +- return -1; +- *result = strtol(linebuf, &endp, 0); +- if (endp == linebuf || errno == ERANGE) +- return -1; +- return 0; +-} +- +-static int __compare(const void *t1, const void *t2) +-{ +- struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; +- struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; +- if (top1->pkg < top2->pkg) +- return -1; +- else if (top1->pkg > top2->pkg) +- return 1; +- else if (top1->core < top2->core) +- return -1; +- else if (top1->core > top2->core) +- return 1; +- else if (top1->cpu < top2->cpu) +- return -1; +- else if (top1->cpu > top2->cpu) +- return 1; +- else +- return 0; +-} +- +-/* +- * Returns amount of cpus, negative on error, cpu_top must be +- * passed to cpu_topology_release to free resources +- * +- * Array is sorted after ->pkg, ->core, then ->cpu +- */ +-int get_cpu_topology(struct cpupower_topology *cpu_top) +-{ +- int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); +- +- cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); +- if (cpu_top->core_info == NULL) +- return -ENOMEM; +- cpu_top->pkgs = cpu_top->cores = 0; +- for (cpu = 0; cpu < cpus; cpu++) { +- cpu_top->core_info[cpu].cpu = cpu; +- cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); +- if(sysfs_topology_read_file( +- cpu, +- "physical_package_id", +- &(cpu_top->core_info[cpu].pkg)) < 0) { +- cpu_top->core_info[cpu].pkg = -1; +- cpu_top->core_info[cpu].core = -1; +- continue; +- } +- if(sysfs_topology_read_file( +- cpu, +- "core_id", +- &(cpu_top->core_info[cpu].core)) < 0) { +- cpu_top->core_info[cpu].pkg = -1; +- cpu_top->core_info[cpu].core = -1; +- continue; +- } +- } +- +- qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), +- __compare); +- +- /* Count the number of distinct pkgs values. This works +- because the primary sort of the core_info struct was just +- done by pkg value. */ +- last_pkg = cpu_top->core_info[0].pkg; +- for(cpu = 1; cpu < cpus; cpu++) { +- if (cpu_top->core_info[cpu].pkg != last_pkg && +- cpu_top->core_info[cpu].pkg != -1) { +- +- last_pkg = cpu_top->core_info[cpu].pkg; +- cpu_top->pkgs++; +- } +- } +- if (!(cpu_top->core_info[0].pkg == -1)) +- cpu_top->pkgs++; +- +- /* Intel's cores count is not consecutively numbered, there may +- * be a core_id of 3, but none of 2. Assume there always is 0 +- * Get amount of cores by counting duplicates in a package +- for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { +- if (cpu_top->core_info[cpu].core == 0) +- cpu_top->cores++; +- */ +- return cpus; +-} +- +-void cpu_topology_release(struct cpupower_topology cpu_top) +-{ +- free(cpu_top.core_info); +-} +diff --git a/utils/idle_monitor/cpuidle_sysfs.c b/utils/idle_monitor/cpuidle_sysfs.c +index bcd22a1..1b5da00 100644 +--- a/utils/idle_monitor/cpuidle_sysfs.c ++++ b/utils/idle_monitor/cpuidle_sysfs.c +@@ -10,8 +10,8 @@ + #include + #include + #include ++#include + +-#include "helpers/sysfs.h" + #include "helpers/helpers.h" + #include "idle_monitor/cpupower-monitor.h" + +@@ -51,7 +51,7 @@ static int cpuidle_start(void) + for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; + state++) { + previous_count[cpu][state] = +- sysfs_get_idlestate_time(cpu, state); ++ cpuidle_state_time(cpu, state); + dprint("CPU %d - State: %d - Val: %llu\n", + cpu, state, previous_count[cpu][state]); + } +@@ -70,7 +70,7 @@ static int cpuidle_stop(void) + for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; + state++) { + current_count[cpu][state] = +- sysfs_get_idlestate_time(cpu, state); ++ cpuidle_state_time(cpu, state); + dprint("CPU %d - State: %d - Val: %llu\n", + cpu, state, previous_count[cpu][state]); + } +@@ -132,13 +132,13 @@ static struct cpuidle_monitor *cpuidle_register(void) + char *tmp; + + /* Assume idle state count is the same for all CPUs */ +- cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); ++ cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0); + + if (cpuidle_sysfs_monitor.hw_states_num <= 0) + return NULL; + + for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { +- tmp = sysfs_get_idlestate_name(0, num); ++ tmp = cpuidle_state_name(0, num); + if (tmp == NULL) + continue; + +@@ -146,7 +146,7 @@ static struct cpuidle_monitor *cpuidle_register(void) + strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); + free(tmp); + +- tmp = sysfs_get_idlestate_desc(0, num); ++ tmp = cpuidle_state_desc(0, num); + if (tmp == NULL) + continue; + strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); diff --git a/msr-index.h b/msr-index.h index 2a1211e..afa6a00 100644 --- a/msr-index.h +++ b/msr-index.h @@ -35,7 +35,7 @@ #define MSR_IA32_PERFCTR0 0x000000c1 #define MSR_IA32_PERFCTR1 0x000000c2 #define MSR_FSB_FREQ 0x000000cd -#define MSR_NHM_PLATFORM_INFO 0x000000ce +#define MSR_PLATFORM_INFO 0x000000ce #define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2 #define NHM_C3_AUTO_DEMOTE (1UL << 25) @@ -44,7 +44,6 @@ #define SNB_C1_AUTO_UNDEMOTE (1UL << 27) #define SNB_C3_AUTO_UNDEMOTE (1UL << 28) -#define MSR_PLATFORM_INFO 0x000000ce #define MSR_MTRRcap 0x000000fe #define MSR_IA32_BBL_CR_CTL 0x00000119 #define MSR_IA32_BBL_CR_CTL3 0x0000011e @@ -56,11 +55,15 @@ #define MSR_IA32_MCG_CAP 0x00000179 #define MSR_IA32_MCG_STATUS 0x0000017a #define MSR_IA32_MCG_CTL 0x0000017b +#define MSR_IA32_MCG_EXT_CTL 0x000004d0 #define MSR_OFFCORE_RSP_0 0x000001a6 #define MSR_OFFCORE_RSP_1 0x000001a7 #define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad #define MSR_IVT_TURBO_RATIO_LIMIT 0x000001ae +#define MSR_TURBO_RATIO_LIMIT 0x000001ad +#define MSR_TURBO_RATIO_LIMIT1 0x000001ae +#define MSR_TURBO_RATIO_LIMIT2 0x000001af #define MSR_LBR_SELECT 0x000001c8 #define MSR_LBR_TOS 0x000001c9 @@ -69,11 +72,43 @@ #define MSR_LBR_CORE_FROM 0x00000040 #define MSR_LBR_CORE_TO 0x00000060 +#define MSR_LBR_INFO_0 0x00000dc0 /* ... 0xddf for _31 */ +#define LBR_INFO_MISPRED BIT_ULL(63) +#define LBR_INFO_IN_TX BIT_ULL(62) +#define LBR_INFO_ABORT BIT_ULL(61) +#define LBR_INFO_CYCLES 0xffff + #define MSR_IA32_PEBS_ENABLE 0x000003f1 #define MSR_IA32_DS_AREA 0x00000600 #define MSR_IA32_PERF_CAPABILITIES 0x00000345 #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 +#define MSR_IA32_RTIT_CTL 0x00000570 +#define RTIT_CTL_TRACEEN BIT(0) +#define RTIT_CTL_CYCLEACC BIT(1) +#define RTIT_CTL_OS BIT(2) +#define RTIT_CTL_USR BIT(3) +#define RTIT_CTL_CR3EN BIT(7) +#define RTIT_CTL_TOPA BIT(8) +#define RTIT_CTL_MTC_EN BIT(9) +#define RTIT_CTL_TSC_EN BIT(10) +#define RTIT_CTL_DISRETC BIT(11) +#define RTIT_CTL_BRANCH_EN BIT(13) +#define RTIT_CTL_MTC_RANGE_OFFSET 14 +#define RTIT_CTL_MTC_RANGE (0x0full << RTIT_CTL_MTC_RANGE_OFFSET) +#define RTIT_CTL_CYC_THRESH_OFFSET 19 +#define RTIT_CTL_CYC_THRESH (0x0full << RTIT_CTL_CYC_THRESH_OFFSET) +#define RTIT_CTL_PSB_FREQ_OFFSET 24 +#define RTIT_CTL_PSB_FREQ (0x0full << RTIT_CTL_PSB_FREQ_OFFSET) +#define MSR_IA32_RTIT_STATUS 0x00000571 +#define RTIT_STATUS_CONTEXTEN BIT(1) +#define RTIT_STATUS_TRIGGEREN BIT(2) +#define RTIT_STATUS_ERROR BIT(4) +#define RTIT_STATUS_STOPPED BIT(5) +#define MSR_IA32_RTIT_CR3_MATCH 0x00000572 +#define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560 +#define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561 + #define MSR_MTRRfix64K_00000 0x00000250 #define MSR_MTRRfix16K_80000 0x00000258 #define MSR_MTRRfix16K_A0000 0x00000259 @@ -105,6 +140,8 @@ #define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) #define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) +#define MSR_PEBS_FRONTEND 0x000003f7 + #define MSR_IA32_POWER_CTL 0x000001fc #define MSR_IA32_MC0_CTL 0x00000400 @@ -119,6 +156,7 @@ #define MSR_CORE_C3_RESIDENCY 0x000003fc #define MSR_CORE_C6_RESIDENCY 0x000003fd #define MSR_CORE_C7_RESIDENCY 0x000003fe +#define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff #define MSR_PKG_C2_RESIDENCY 0x0000060d #define MSR_PKG_C8_RESIDENCY 0x00000630 #define MSR_PKG_C9_RESIDENCY 0x00000631 @@ -147,11 +185,33 @@ #define MSR_PP1_ENERGY_STATUS 0x00000641 #define MSR_PP1_POLICY 0x00000642 +#define MSR_CONFIG_TDP_NOMINAL 0x00000648 +#define MSR_CONFIG_TDP_LEVEL_1 0x00000649 +#define MSR_CONFIG_TDP_LEVEL_2 0x0000064A +#define MSR_CONFIG_TDP_CONTROL 0x0000064B +#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C + +#define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 +#define MSR_PKG_ANY_CORE_C0_RES 0x00000659 +#define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A +#define MSR_PKG_BOTH_CORE_GFXE_C0_RES 0x0000065B + #define MSR_CORE_C1_RES 0x00000660 #define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 #define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 +#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690 +#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0 +#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1 + +/* Config TDP MSRs */ +#define MSR_CONFIG_TDP_NOMINAL 0x00000648 +#define MSR_CONFIG_TDP_LEVEL1 0x00000649 +#define MSR_CONFIG_TDP_LEVEL2 0x0000064A +#define MSR_CONFIG_TDP_CONTROL 0x0000064B +#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C + /* Hardware P state interface */ #define MSR_PPERF 0x0000064e #define MSR_PERF_LIMIT_REASONS 0x0000064f @@ -251,6 +311,10 @@ /* Fam 16h MSRs */ #define MSR_F16H_L2I_PERF_CTL 0xc0010230 #define MSR_F16H_L2I_PERF_CTR 0xc0010231 +#define MSR_F16H_DR1_ADDR_MASK 0xc0011019 +#define MSR_F16H_DR2_ADDR_MASK 0xc001101a +#define MSR_F16H_DR3_ADDR_MASK 0xc001101b +#define MSR_F16H_DR0_ADDR_MASK 0xc0011027 /* Fam 15h MSRs */ #define MSR_F15H_PERF_CTL 0xc0010200 @@ -275,6 +339,7 @@ /* C1E active bits in int pending message */ #define K8_INTP_C1E_ACTIVE_MASK 0x18000000 #define MSR_K8_TSEG_ADDR 0xc0010112 +#define MSR_K8_TSEG_MASK 0xc0010113 #define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */ #define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */ #define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */ @@ -345,6 +410,7 @@ #define FEATURE_CONTROL_LOCKED (1<<0) #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX (1<<1) #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX (1<<2) +#define FEATURE_CONTROL_LMCE (1<<20) #define MSR_IA32_APICBASE 0x0000001b #define MSR_IA32_APICBASE_BSP (1<<8) @@ -356,8 +422,12 @@ #define MSR_IA32_UCODE_WRITE 0x00000079 #define MSR_IA32_UCODE_REV 0x0000008b +#define MSR_IA32_SMM_MONITOR_CTL 0x0000009b +#define MSR_IA32_SMBASE 0x0000009e + #define MSR_IA32_PERF_STATUS 0x00000198 #define MSR_IA32_PERF_CTL 0x00000199 +#define INTEL_PERF_CTL_MASK 0xffff #define MSR_AMD_PSTATE_DEF_BASE 0xc0010064 #define MSR_AMD_PERF_STATUS 0xc0010063 #define MSR_AMD_PERF_CTL 0xc0010062