Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/power/cpupower/lib/cpupower.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* (C) 2004-2009 Dominik Brodowski <[email protected]>
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
#include <string.h>
14
15
#include "cpupower.h"
16
#include "cpupower_intern.h"
17
18
int is_valid_path(const char *path)
19
{
20
if (access(path, F_OK) == -1)
21
return 0;
22
return 1;
23
}
24
25
unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen)
26
{
27
ssize_t numread;
28
int fd;
29
30
fd = open(path, O_RDONLY);
31
if (fd == -1)
32
return 0;
33
34
numread = read(fd, buf, buflen - 1);
35
if (numread < 1) {
36
close(fd);
37
return 0;
38
}
39
40
buf[numread] = '\0';
41
close(fd);
42
43
return (unsigned int) numread;
44
}
45
46
unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen)
47
{
48
ssize_t numwritten;
49
int fd;
50
51
fd = open(path, O_WRONLY);
52
if (fd == -1)
53
return 0;
54
55
numwritten = write(fd, buf, buflen - 1);
56
if (numwritten < 1) {
57
perror(path);
58
close(fd);
59
return -1;
60
}
61
62
close(fd);
63
64
return (unsigned int) numwritten;
65
}
66
67
/*
68
* Detect whether a CPU is online
69
*
70
* Returns:
71
* 1 -> if CPU is online
72
* 0 -> if CPU is offline
73
* negative errno values in error case
74
*/
75
int cpupower_is_cpu_online(unsigned int cpu)
76
{
77
char path[SYSFS_PATH_MAX];
78
int fd;
79
ssize_t numread;
80
unsigned long long value;
81
char linebuf[MAX_LINE_LEN];
82
char *endp;
83
struct stat statbuf;
84
85
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
86
87
if (stat(path, &statbuf) != 0)
88
return 0;
89
90
/*
91
* kernel without CONFIG_HOTPLUG_CPU
92
* -> cpuX directory exists, but not cpuX/online file
93
*/
94
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
95
if (stat(path, &statbuf) != 0)
96
return 1;
97
98
fd = open(path, O_RDONLY);
99
if (fd == -1)
100
return -errno;
101
102
numread = read(fd, linebuf, MAX_LINE_LEN - 1);
103
if (numread < 1) {
104
close(fd);
105
return -EIO;
106
}
107
linebuf[numread] = '\0';
108
close(fd);
109
110
value = strtoull(linebuf, &endp, 0);
111
if (value > 1)
112
return -EINVAL;
113
114
return value;
115
}
116
117
/* returns -1 on failure, 0 on success */
118
static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
119
{
120
char linebuf[MAX_LINE_LEN];
121
char *endp;
122
char path[SYSFS_PATH_MAX];
123
124
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
125
cpu, fname);
126
if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0)
127
return -1;
128
*result = strtol(linebuf, &endp, 0);
129
if (endp == linebuf || errno == ERANGE)
130
return -1;
131
return 0;
132
}
133
134
static int __compare(const void *t1, const void *t2)
135
{
136
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
137
struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
138
if (top1->pkg < top2->pkg)
139
return -1;
140
else if (top1->pkg > top2->pkg)
141
return 1;
142
else if (top1->core < top2->core)
143
return -1;
144
else if (top1->core > top2->core)
145
return 1;
146
else if (top1->cpu < top2->cpu)
147
return -1;
148
else if (top1->cpu > top2->cpu)
149
return 1;
150
else
151
return 0;
152
}
153
154
static int __compare_core_cpu_list(const void *t1, const void *t2)
155
{
156
struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
157
struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
158
159
return strcmp(top1->core_cpu_list, top2->core_cpu_list);
160
}
161
162
/*
163
* Returns amount of cpus, negative on error, cpu_top must be
164
* passed to cpu_topology_release to free resources
165
*
166
* Array is sorted after ->cpu_smt_list ->pkg, ->core
167
*/
168
int get_cpu_topology(struct cpupower_topology *cpu_top)
169
{
170
int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
171
char path[SYSFS_PATH_MAX];
172
char *last_cpu_list;
173
174
cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
175
if (cpu_top->core_info == NULL)
176
return -ENOMEM;
177
cpu_top->pkgs = cpu_top->cores = 0;
178
for (cpu = 0; cpu < cpus; cpu++) {
179
cpu_top->core_info[cpu].cpu = cpu;
180
cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu);
181
if(sysfs_topology_read_file(
182
cpu,
183
"physical_package_id",
184
&(cpu_top->core_info[cpu].pkg)) < 0) {
185
cpu_top->core_info[cpu].pkg = -1;
186
cpu_top->core_info[cpu].core = -1;
187
continue;
188
}
189
if(sysfs_topology_read_file(
190
cpu,
191
"core_id",
192
&(cpu_top->core_info[cpu].core)) < 0) {
193
cpu_top->core_info[cpu].pkg = -1;
194
cpu_top->core_info[cpu].core = -1;
195
continue;
196
}
197
if (cpu_top->core_info[cpu].core == -1) {
198
strncpy(cpu_top->core_info[cpu].core_cpu_list, "-1", CPULIST_BUFFER);
199
continue;
200
}
201
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
202
cpu, "core_cpus_list");
203
if (cpupower_read_sysfs(
204
path,
205
cpu_top->core_info[cpu].core_cpu_list,
206
CPULIST_BUFFER) < 1) {
207
printf("Warning CPU%u has a 0 size core_cpus_list string", cpu);
208
}
209
}
210
211
/* Count the number of distinct cpu lists to get the physical core
212
* count.
213
*/
214
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
215
__compare_core_cpu_list);
216
217
last_cpu_list = cpu_top->core_info[0].core_cpu_list;
218
cpu_top->cores = 1;
219
for (cpu = 1; cpu < cpus; cpu++) {
220
if (strcmp(cpu_top->core_info[cpu].core_cpu_list, last_cpu_list) != 0 &&
221
cpu_top->core_info[cpu].pkg != -1) {
222
last_cpu_list = cpu_top->core_info[cpu].core_cpu_list;
223
cpu_top->cores++;
224
}
225
}
226
227
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
228
__compare);
229
230
/* Count the number of distinct pkgs values. This works
231
because the primary sort of the core_info struct was just
232
done by pkg value. */
233
last_pkg = cpu_top->core_info[0].pkg;
234
for(cpu = 1; cpu < cpus; cpu++) {
235
if (cpu_top->core_info[cpu].pkg != last_pkg &&
236
cpu_top->core_info[cpu].pkg != -1) {
237
238
last_pkg = cpu_top->core_info[cpu].pkg;
239
cpu_top->pkgs++;
240
}
241
}
242
if (!(cpu_top->core_info[0].pkg == -1))
243
cpu_top->pkgs++;
244
245
return cpus;
246
}
247
248
void cpu_topology_release(struct cpupower_topology cpu_top)
249
{
250
free(cpu_top.core_info);
251
}
252
253