1
2
3
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
17unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen)
18{
19 ssize_t numread;
20 int fd;
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
38unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen)
39{
40 ssize_t numwritten;
41 int fd;
42
43 fd = open(path, O_WRONLY);
44 if (fd == -1)
45 return 0;
46
47 numwritten = write(fd, buf, buflen - 1);
48 if (numwritten < 1) {
49 perror(path);
50 close(fd);
51 return -1;
52 }
53
54 close(fd);
55
56 return (unsigned int) numwritten;
57}
58
59
60
61
62
63
64
65
66
67int cpupower_is_cpu_online(unsigned int cpu)
68{
69 char path[SYSFS_PATH_MAX];
70 int fd;
71 ssize_t numread;
72 unsigned long long value;
73 char linebuf[MAX_LINE_LEN];
74 char *endp;
75 struct stat statbuf;
76
77 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
78
79 if (stat(path, &statbuf) != 0)
80 return 0;
81
82
83
84
85
86 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
87 if (stat(path, &statbuf) != 0)
88 return 1;
89
90 fd = open(path, O_RDONLY);
91 if (fd == -1)
92 return -errno;
93
94 numread = read(fd, linebuf, MAX_LINE_LEN - 1);
95 if (numread < 1) {
96 close(fd);
97 return -EIO;
98 }
99 linebuf[numread] = '\0';
100 close(fd);
101
102 value = strtoull(linebuf, &endp, 0);
103 if (value > 1)
104 return -EINVAL;
105
106 return value;
107}
108
109
110static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
111{
112 char linebuf[MAX_LINE_LEN];
113 char *endp;
114 char path[SYSFS_PATH_MAX];
115
116 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
117 cpu, fname);
118 if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0)
119 return -1;
120 *result = strtol(linebuf, &endp, 0);
121 if (endp == linebuf || errno == ERANGE)
122 return -1;
123 return 0;
124}
125
126static int __compare(const void *t1, const void *t2)
127{
128 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
129 struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
130 if (top1->pkg < top2->pkg)
131 return -1;
132 else if (top1->pkg > top2->pkg)
133 return 1;
134 else if (top1->core < top2->core)
135 return -1;
136 else if (top1->core > top2->core)
137 return 1;
138 else if (top1->cpu < top2->cpu)
139 return -1;
140 else if (top1->cpu > top2->cpu)
141 return 1;
142 else
143 return 0;
144}
145
146
147
148
149
150
151
152int get_cpu_topology(struct cpupower_topology *cpu_top)
153{
154 int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
155
156 cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
157 if (cpu_top->core_info == NULL)
158 return -ENOMEM;
159 cpu_top->pkgs = cpu_top->cores = 0;
160 for (cpu = 0; cpu < cpus; cpu++) {
161 cpu_top->core_info[cpu].cpu = cpu;
162 cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu);
163 if(sysfs_topology_read_file(
164 cpu,
165 "physical_package_id",
166 &(cpu_top->core_info[cpu].pkg)) < 0) {
167 cpu_top->core_info[cpu].pkg = -1;
168 cpu_top->core_info[cpu].core = -1;
169 continue;
170 }
171 if(sysfs_topology_read_file(
172 cpu,
173 "core_id",
174 &(cpu_top->core_info[cpu].core)) < 0) {
175 cpu_top->core_info[cpu].pkg = -1;
176 cpu_top->core_info[cpu].core = -1;
177 continue;
178 }
179 }
180
181 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
182 __compare);
183
184
185
186
187 last_pkg = cpu_top->core_info[0].pkg;
188 for(cpu = 1; cpu < cpus; cpu++) {
189 if (cpu_top->core_info[cpu].pkg != last_pkg &&
190 cpu_top->core_info[cpu].pkg != -1) {
191
192 last_pkg = cpu_top->core_info[cpu].pkg;
193 cpu_top->pkgs++;
194 }
195 }
196 if (!(cpu_top->core_info[0].pkg == -1))
197 cpu_top->pkgs++;
198
199
200
201
202
203
204
205
206 return cpus;
207}
208
209void cpu_topology_release(struct cpupower_topology cpu_top)
210{
211 free(cpu_top.core_info);
212}
213