root/tools/power/cpupower/lib/cpupower.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cpupower_read_sysfs
  2. cpupower_is_cpu_online
  3. sysfs_topology_read_file
  4. __compare
  5. get_cpu_topology
  6. cpu_topology_release

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

/* [<][>][^][v][top][bottom][index][help] */