linux/tools/power/cpupower/lib/cpupower.c
<<
>>
Prefs
   1/*
   2 *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
   3 *
   4 *  Licensed under the terms of the GNU GPL License version 2.
   5 */
   6
   7#include <sys/types.h>
   8#include <sys/stat.h>
   9#include <fcntl.h>
  10#include <unistd.h>
  11#include <stdio.h>
  12#include <errno.h>
  13#include <stdlib.h>
  14
  15#include "cpupower.h"
  16#include "cpupower_intern.h"
  17
  18unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
  19{
  20        int fd;
  21        ssize_t numread;
  22
  23        fd = open(path, O_RDONLY);
  24        if (fd == -1)
  25                return 0;
  26
  27        numread = read(fd, buf, buflen - 1);
  28        if (numread < 1) {
  29                close(fd);
  30                return 0;
  31        }
  32
  33        buf[numread] = '\0';
  34        close(fd);
  35
  36        return (unsigned int) numread;
  37}
  38
  39/*
  40 * Detect whether a CPU is online
  41 *
  42 * Returns:
  43 *     1 -> if CPU is online
  44 *     0 -> if CPU is offline
  45 *     negative errno values in error case
  46 */
  47int cpupower_is_cpu_online(unsigned int cpu)
  48{
  49        char path[SYSFS_PATH_MAX];
  50        int fd;
  51        ssize_t numread;
  52        unsigned long long value;
  53        char linebuf[MAX_LINE_LEN];
  54        char *endp;
  55        struct stat statbuf;
  56
  57        snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
  58
  59        if (stat(path, &statbuf) != 0)
  60                return 0;
  61
  62        /*
  63         * kernel without CONFIG_HOTPLUG_CPU
  64         * -> cpuX directory exists, but not cpuX/online file
  65         */
  66        snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
  67        if (stat(path, &statbuf) != 0)
  68                return 1;
  69
  70        fd = open(path, O_RDONLY);
  71        if (fd == -1)
  72                return -errno;
  73
  74        numread = read(fd, linebuf, MAX_LINE_LEN - 1);
  75        if (numread < 1) {
  76                close(fd);
  77                return -EIO;
  78        }
  79        linebuf[numread] = '\0';
  80        close(fd);
  81
  82        value = strtoull(linebuf, &endp, 0);
  83        if (value > 1)
  84                return -EINVAL;
  85
  86        return value;
  87}
  88
  89/* returns -1 on failure, 0 on success */
  90static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
  91{
  92        char linebuf[MAX_LINE_LEN];
  93        char *endp;
  94        char path[SYSFS_PATH_MAX];
  95
  96        snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
  97                         cpu, fname);
  98        if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
  99                return -1;
 100        *result = strtol(linebuf, &endp, 0);
 101        if (endp == linebuf || errno == ERANGE)
 102                return -1;
 103        return 0;
 104}
 105
 106static int __compare(const void *t1, const void *t2)
 107{
 108        struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
 109        struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
 110        if (top1->pkg < top2->pkg)
 111                return -1;
 112        else if (top1->pkg > top2->pkg)
 113                return 1;
 114        else if (top1->core < top2->core)
 115                return -1;
 116        else if (top1->core > top2->core)
 117                return 1;
 118        else if (top1->cpu < top2->cpu)
 119                return -1;
 120        else if (top1->cpu > top2->cpu)
 121                return 1;
 122        else
 123                return 0;
 124}
 125
 126/*
 127 * Returns amount of cpus, negative on error, cpu_top must be
 128 * passed to cpu_topology_release to free resources
 129 *
 130 * Array is sorted after ->pkg, ->core, then ->cpu
 131 */
 132int get_cpu_topology(struct cpupower_topology *cpu_top)
 133{
 134        int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
 135
 136        cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
 137        if (cpu_top->core_info == NULL)
 138                return -ENOMEM;
 139        cpu_top->pkgs = cpu_top->cores = 0;
 140        for (cpu = 0; cpu < cpus; cpu++) {
 141                cpu_top->core_info[cpu].cpu = cpu;
 142                cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu);
 143                if(sysfs_topology_read_file(
 144                        cpu,
 145                        "physical_package_id",
 146                        &(cpu_top->core_info[cpu].pkg)) < 0) {
 147                        cpu_top->core_info[cpu].pkg = -1;
 148                        cpu_top->core_info[cpu].core = -1;
 149                        continue;
 150                }
 151                if(sysfs_topology_read_file(
 152                        cpu,
 153                        "core_id",
 154                        &(cpu_top->core_info[cpu].core)) < 0) {
 155                        cpu_top->core_info[cpu].pkg = -1;
 156                        cpu_top->core_info[cpu].core = -1;
 157                        continue;
 158                }
 159        }
 160
 161        qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
 162              __compare);
 163
 164        /* Count the number of distinct pkgs values. This works
 165           because the primary sort of the core_info struct was just
 166           done by pkg value. */
 167        last_pkg = cpu_top->core_info[0].pkg;
 168        for(cpu = 1; cpu < cpus; cpu++) {
 169                if (cpu_top->core_info[cpu].pkg != last_pkg &&
 170                                cpu_top->core_info[cpu].pkg != -1) {
 171
 172                        last_pkg = cpu_top->core_info[cpu].pkg;
 173                        cpu_top->pkgs++;
 174                }
 175        }
 176        if (!(cpu_top->core_info[0].pkg == -1))
 177                cpu_top->pkgs++;
 178
 179        /* Intel's cores count is not consecutively numbered, there may
 180         * be a core_id of 3, but none of 2. Assume there always is 0
 181         * Get amount of cores by counting duplicates in a package
 182        for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
 183                if (cpu_top->core_info[cpu].core == 0)
 184        cpu_top->cores++;
 185        */
 186        return cpus;
 187}
 188
 189void cpu_topology_release(struct cpupower_topology cpu_top)
 190{
 191        free(cpu_top.core_info);
 192}
 193