]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/unix/sysv/linux/getsysstats.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / getsysstats.c
CommitLineData
dfd2257a 1/* Determine various system internal values, Linux version.
04277e02 2 Copyright (C) 1996-2019 Free Software Foundation, Inc.
84384f5b
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
84384f5b
UD
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
84384f5b 15
41bdb6e2 16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
84384f5b
UD
19
20#include <alloca.h>
77432371 21#include <assert.h>
27692f89 22#include <ctype.h>
58d43ba8 23#include <dirent.h>
845dcb57 24#include <errno.h>
58d43ba8 25#include <fcntl.h>
845dcb57 26#include <mntent.h>
46ec036d 27#include <paths.h>
845dcb57 28#include <stdio.h>
2706ee38 29#include <stdio_ext.h>
77432371 30#include <stdlib.h>
845dcb57
UD
31#include <string.h>
32#include <unistd.h>
33#include <sys/sysinfo.h>
34
4009bf40 35#include <atomic.h>
58d43ba8 36#include <not-cancel.h>
852eb34d 37
77432371 38
845dcb57
UD
39/* How we can determine the number of available processors depends on
40 the configuration. There is currently (as of version 2.0.21) no
41 system call to determine the number. It is planned for the 2.1.x
42 series to add this, though.
43
44 One possibility to implement it for systems using Linux 2.0 is to
b0b67c47 45 examine the pseudo file /proc/cpuinfo. Here we have one entry for
845dcb57
UD
46 each processor.
47
48 But not all systems have support for the /proc filesystem. If it
49 is not available we simply return 1 since there is no way. */
bdb04ee8 50
f43b4be6 51
bdb04ee8
UD
52/* Other architectures use different formats for /proc/cpuinfo. This
53 provides a hook for alternative parsers. */
54#ifndef GET_NPROCS_PARSER
f43b4be6 55# define GET_NPROCS_PARSER(FD, BUFFER, CP, RE, BUFFER_END, RESULT) \
bdb04ee8
UD
56 do \
57 { \
58 (RESULT) = 0; \
59 /* Read all lines and count the lines starting with the string \
60 "processor". We don't have to fear extremely long lines since \
61 the kernel will not generate them. 8192 bytes are really \
62 enough. */ \
f43b4be6
UD
63 char *l; \
64 while ((l = next_line (FD, BUFFER, &CP, &RE, BUFFER_END)) != NULL) \
65 if (strncmp (l, "processor", 9) == 0) \
bdb04ee8
UD
66 ++(RESULT); \
67 } \
68 while (0)
69#endif
70
9506149a 71
f43b4be6
UD
72static char *
73next_line (int fd, char *const buffer, char **cp, char **re,
74 char *const buffer_end)
75{
76 char *res = *cp;
77 char *nl = memchr (*cp, '\n', *re - *cp);
78 if (nl == NULL)
79 {
80 if (*cp != buffer)
81 {
82 if (*re == buffer_end)
83 {
84 memmove (buffer, *cp, *re - *cp);
85 *re = buffer + (*re - *cp);
86 *cp = buffer;
87
a748eb31 88 ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
f43b4be6
UD
89 if (n < 0)
90 return NULL;
91
92 *re += n;
6a3d03ff
UD
93
94 nl = memchr (*cp, '\n', *re - *cp);
95 while (nl == NULL && *re == buffer_end)
96 {
97 /* Truncate too long lines. */
98 *re = buffer + 3 * (buffer_end - buffer) / 4;
a748eb31 99 n = __read_nocancel (fd, *re, buffer_end - *re);
6a3d03ff
UD
100 if (n < 0)
101 return NULL;
102
103 nl = memchr (*re, '\n', n);
104 **re = '\n';
105 *re += n;
106 }
f43b4be6 107 }
6a3d03ff
UD
108 else
109 nl = memchr (*cp, '\n', *re - *cp);
f43b4be6
UD
110
111 res = *cp;
f43b4be6
UD
112 }
113
114 if (nl == NULL)
115 nl = *re - 1;
116 }
117
118 *cp = nl + 1;
119 assert (*cp <= *re);
120
121 return res == *re ? NULL : res;
122}
123
124
0abf17de 125int
60d2f8f3 126__get_nprocs (void)
845dcb57 127{
995a46bb 128 static int cached_result = -1;
852eb34d
UD
129 static time_t timestamp;
130
d53a73ac 131 time_t now = time (NULL);
852eb34d
UD
132 time_t prev = timestamp;
133 atomic_read_barrier ();
995a46bb 134 if (now == prev && cached_result > -1)
852eb34d
UD
135 return cached_result;
136
0abf17de
UD
137 /* XXX Here will come a test for the new system call. */
138
6a3d03ff
UD
139 const size_t buffer_size = __libc_use_alloca (8192) ? 8192 : 512;
140 char *buffer = alloca (buffer_size);
141 char *buffer_end = buffer + buffer_size;
f43b4be6
UD
142 char *cp = buffer_end;
143 char *re = buffer_end;
845dcb57 144
f43b4be6 145 const int flags = O_RDONLY | O_CLOEXEC;
c2284574 146 int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags);
84e2a551
UD
147 char *l;
148 int result = 0;
149 if (fd != -1)
150 {
151 l = next_line (fd, buffer, &cp, &re, buffer_end);
152 if (l != NULL)
153 do
154 {
155 char *endp;
156 unsigned long int n = strtoul (l, &endp, 10);
157 if (l == endp)
158 {
159 result = 0;
160 break;
161 }
162
163 unsigned long int m = n;
164 if (*endp == '-')
165 {
166 l = endp + 1;
167 m = strtoul (l, &endp, 10);
168 if (l == endp)
169 {
170 result = 0;
171 break;
172 }
173 }
174
175 result += m - n + 1;
176
177 l = endp;
178 while (l < re && isspace (*l))
179 ++l;
180 }
181 while (l < re);
182
c181840c 183 __close_nocancel_nostatus (fd);
84e2a551
UD
184
185 if (result > 0)
186 goto out;
187 }
188
189 cp = buffer_end;
190 re = buffer_end;
1ff6c67a
FW
191
192 /* Default to an SMP system in case we cannot obtain an accurate
193 number. */
194 result = 2;
84e2a551 195
9506149a 196 /* The /proc/stat format is more uniform, use it by default. */
c2284574 197 fd = __open_nocancel ("/proc/stat", flags);
f43b4be6 198 if (fd != -1)
9506149a 199 {
9506149a 200 result = 0;
f43b4be6 201
f43b4be6 202 while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
6a3d03ff
UD
203 /* The current format of /proc/stat has all the cpu* entries
204 at the front. We assume here that stays this way. */
205 if (strncmp (l, "cpu", 3) != 0)
206 break;
207 else if (isdigit (l[3]))
9506149a
UD
208 ++result;
209
c181840c 210 __close_nocancel_nostatus (fd);
9506149a
UD
211 }
212 else
213 {
c2284574 214 fd = __open_nocancel ("/proc/cpuinfo", flags);
f43b4be6 215 if (fd != -1)
9506149a 216 {
f43b4be6 217 GET_NPROCS_PARSER (fd, buffer, cp, re, buffer_end, result);
c181840c 218 __close_nocancel_nostatus (fd);
9506149a
UD
219 }
220 }
221
84e2a551 222 out:
852eb34d
UD
223 cached_result = result;
224 atomic_write_barrier ();
d53a73ac 225 timestamp = now;
852eb34d 226
9506149a
UD
227 return result;
228}
b5648377 229libc_hidden_def (__get_nprocs)
845dcb57
UD
230weak_alias (__get_nprocs, get_nprocs)
231
bdb04ee8 232
bdb04ee8
UD
233/* On some architectures it is possible to distinguish between configured
234 and active cpus. */
235int
60d2f8f3 236__get_nprocs_conf (void)
bdb04ee8 237{
bdb04ee8
UD
238 /* XXX Here will come a test for the new system call. */
239
9506149a
UD
240 /* Try to use the sysfs filesystem. It has actual information about
241 online processors. */
242 DIR *dir = __opendir ("/sys/devices/system/cpu");
243 if (dir != NULL)
244 {
245 int count = 0;
246 struct dirent64 *d;
247
248 while ((d = __readdir64 (dir)) != NULL)
249 /* NB: the sysfs has d_type support. */
250 if (d->d_type == DT_DIR && strncmp (d->d_name, "cpu", 3) == 0)
251 {
252 char *endp;
253 unsigned long int nr = strtoul (d->d_name + 3, &endp, 10);
254 if (nr != ULONG_MAX && endp != d->d_name + 3 && *endp == '\0')
255 ++count;
256 }
257
258 __closedir (dir);
259
260 return count;
261 }
262
263 int result = 1;
264
265#ifdef GET_NPROCS_CONF_PARSER
bdb04ee8 266 /* If we haven't found an appropriate entry return 1. */
f43b4be6 267 FILE *fp = fopen ("/proc/cpuinfo", "rce");
5c980df9 268 if (fp != NULL)
bdb04ee8 269 {
9506149a
UD
270 char buffer[8192];
271
5c980df9
UD
272 /* No threads use this stream. */
273 __fsetlocking (fp, FSETLOCKING_BYCALLER);
274 GET_NPROCS_CONF_PARSER (fp, buffer, result);
275 fclose (fp);
bdb04ee8 276 }
9506149a 277#else
0abf17de 278 result = __get_nprocs ();
9506149a 279#endif
bdb04ee8
UD
280
281 return result;
282}
b5648377 283libc_hidden_def (__get_nprocs_conf)
bdb04ee8 284weak_alias (__get_nprocs_conf, get_nprocs_conf)
845dcb57 285
0ce657c5
RV
286
287/* Compute (num*mem_unit)/pagesize, but avoid overflowing long int.
288 In practice, mem_unit is never bigger than the page size, so after
289 the first loop it is 1. [In the kernel, it is initialized to
290 PAGE_SIZE in mm/page_alloc.c:si_meminfo(), and then in
291 kernel.sys.c:do_sysinfo() it is set to 1 if unsigned long can
292 represent all the sizes measured in bytes]. */
e4cf5229 293static long int
0ce657c5 294sysinfo_mempages (unsigned long int num, unsigned int mem_unit)
845dcb57 295{
0ce657c5 296 unsigned long int ps = __getpagesize ();
845dcb57 297
0ce657c5 298 while (mem_unit > 1 && ps > 1)
845dcb57 299 {
0ce657c5
RV
300 mem_unit >>= 1;
301 ps >>= 1;
845dcb57 302 }
0ce657c5
RV
303 num *= mem_unit;
304 while (ps > 1)
305 {
306 ps >>= 1;
307 num >>= 1;
308 }
309 return num;
845dcb57
UD
310}
311
0ce657c5
RV
312/* Return the number of pages of total/available physical memory in
313 the system. This used to be done by parsing /proc/meminfo, but
314 that's unnecessarily expensive (and /proc is not always available).
315 The sysinfo syscall provides the same information, and has been
316 available at least since kernel 2.3.48. */
e4cf5229 317long int
60d2f8f3 318__get_phys_pages (void)
845dcb57 319{
0ce657c5 320 struct sysinfo info;
845dcb57 321
0ce657c5
RV
322 __sysinfo (&info);
323 return sysinfo_mempages (info.totalram, info.mem_unit);
845dcb57 324}
b5648377 325libc_hidden_def (__get_phys_pages)
845dcb57
UD
326weak_alias (__get_phys_pages, get_phys_pages)
327
e4cf5229 328long int
60d2f8f3 329__get_avphys_pages (void)
845dcb57 330{
0ce657c5 331 struct sysinfo info;
845dcb57 332
0ce657c5
RV
333 __sysinfo (&info);
334 return sysinfo_mempages (info.freeram, info.mem_unit);
845dcb57 335}
b5648377 336libc_hidden_def (__get_avphys_pages)
845dcb57 337weak_alias (__get_avphys_pages, get_avphys_pages)