]> 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.
dff8da6b 2 Copyright (C) 1996-2024 Free Software Foundation, Inc.
84384f5b 3 This file is part of the GNU C Library.
84384f5b
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
84384f5b
UD
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
84384f5b 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6 16 License along with the GNU C Library; if not, see
5a82c748 17 <https://www.gnu.org/licenses/>. */
84384f5b 18
eb68d7d2 19#include <array_length.h>
34229827
AZ
20#include <assert.h>
21#include <ctype.h>
eb68d7d2
FW
22#include <errno.h>
23#include <ldsodefs.h>
24#include <limits.h>
903bc7dc 25#include <not-cancel.h>
845dcb57 26#include <stdio.h>
2706ee38 27#include <stdio_ext.h>
eb68d7d2 28#include <sys/mman.h>
845dcb57 29#include <sys/sysinfo.h>
903bc7dc 30#include <sysdep.h>
f43b4be6 31
472894d2 32static int
34229827 33__get_nprocs_sched (void)
eb68d7d2 34{
33099d72
AZ
35 enum
36 {
37 max_num_cpus = 32768,
38 cpu_bits_size = CPU_ALLOC_SIZE (32768)
39 };
40
41 /* This cannot use malloc because it is used on malloc initialization. */
42 __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)];
43 int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size,
44 cpu_bits);
eb68d7d2 45 if (r > 0)
97ba273b 46 return CPU_COUNT_S (r, (cpu_set_t*) cpu_bits);
eb68d7d2 47 else if (r == -EINVAL)
33099d72
AZ
48 /* The input buffer is still not enough to store the number of cpus. This
49 is an arbitrary values assuming such systems should be rare and there
50 is no offline cpus. */
51 return max_num_cpus;
e1d32b83
DL
52 /* Some other error. */
53 return 0;
9506149a 54}
34229827
AZ
55
56static char *
57next_line (int fd, char *const buffer, char **cp, char **re,
58 char *const buffer_end)
59{
60 char *res = *cp;
61 char *nl = memchr (*cp, '\n', *re - *cp);
62 if (nl == NULL)
63 {
64 if (*cp != buffer)
65 {
66 if (*re == buffer_end)
67 {
68 memmove (buffer, *cp, *re - *cp);
69 *re = buffer + (*re - *cp);
70 *cp = buffer;
71
72 ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
73 if (n < 0)
74 return NULL;
75
76 *re += n;
77
78 nl = memchr (*cp, '\n', *re - *cp);
79 while (nl == NULL && *re == buffer_end)
80 {
81 /* Truncate too long lines. */
82 *re = buffer + 3 * (buffer_end - buffer) / 4;
83 n = __read_nocancel (fd, *re, buffer_end - *re);
84 if (n < 0)
85 return NULL;
86
87 nl = memchr (*re, '\n', n);
88 **re = '\n';
89 *re += n;
90 }
91 }
92 else
93 nl = memchr (*cp, '\n', *re - *cp);
94
95 res = *cp;
96 }
97
98 if (nl == NULL)
99 nl = *re - 1;
100 }
101
102 *cp = nl + 1;
103 assert (*cp <= *re);
104
105 return res == *re ? NULL : res;
106}
107
137ed5ac 108static int
e1d32b83 109get_nproc_stat (void)
137ed5ac 110{
e1d32b83
DL
111 enum { buffer_size = 1024 };
112 char buffer[buffer_size];
137ed5ac
AZ
113 char *buffer_end = buffer + buffer_size;
114 char *cp = buffer_end;
115 char *re = buffer_end;
e1d32b83 116 int result = 0;
137ed5ac
AZ
117
118 const int flags = O_RDONLY | O_CLOEXEC;
119 int fd = __open_nocancel ("/proc/stat", flags);
120 if (fd != -1)
121 {
137ed5ac
AZ
122 char *l;
123 while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
124 /* The current format of /proc/stat has all the cpu* entries
125 at the front. We assume here that stays this way. */
126 if (strncmp (l, "cpu", 3) != 0)
127 break;
128 else if (isdigit (l[3]))
129 ++result;
130
131 __close_nocancel_nostatus (fd);
132 }
133
134 return result;
135}
845dcb57 136
e1d32b83 137static int
97a912f7 138read_sysfs_file (const char *fname)
11a02b03 139{
34229827
AZ
140 enum { buffer_size = 1024 };
141 char buffer[buffer_size];
142 char *buffer_end = buffer + buffer_size;
143 char *cp = buffer_end;
144 char *re = buffer_end;
145
146 const int flags = O_RDONLY | O_CLOEXEC;
147 /* This file contains comma-separated ranges. */
97a912f7 148 int fd = __open_nocancel (fname, flags);
34229827
AZ
149 char *l;
150 int result = 0;
151 if (fd != -1)
152 {
153 l = next_line (fd, buffer, &cp, &re, buffer_end);
154 if (l != NULL)
155 do
156 {
157 char *endp;
158 unsigned long int n = strtoul (l, &endp, 10);
159 if (l == endp)
160 {
161 result = 0;
162 break;
163 }
164
165 unsigned long int m = n;
166 if (*endp == '-')
167 {
168 l = endp + 1;
169 m = strtoul (l, &endp, 10);
170 if (l == endp)
171 {
172 result = 0;
173 break;
174 }
175 }
176
e1d32b83
DL
177 if (m >= n)
178 result += m - n + 1;
34229827
AZ
179
180 l = endp;
181 if (l < re && *l == ',')
182 ++l;
183 }
184 while (l < re && *l != '\n');
185
186 __close_nocancel_nostatus (fd);
34229827
AZ
187 }
188
e1d32b83 189 return result;
11a02b03 190}
bdb04ee8 191
e1d32b83
DL
192static int
193get_nprocs_fallback (void)
194{
195 int result;
196
197 /* Try /proc/stat first. */
198 result = get_nproc_stat ();
199 if (result != 0)
200 return result;
201
202 /* Try sched_getaffinity. */
203 result = __get_nprocs_sched ();
204 if (result != 0)
205 return result;
206
207 /* We failed to obtain an accurate number. Be conservative: return
208 the smallest number meaning that this is not a uniprocessor system,
209 so atomics are needed. */
210 return 2;
211}
212
213int
214__get_nprocs (void)
215{
97a912f7 216 int result = read_sysfs_file ("/sys/devices/system/cpu/online");
e1d32b83
DL
217 if (result != 0)
218 return result;
219
220 /* Fall back to /proc/stat and sched_getaffinity. */
221 return get_nprocs_fallback ();
222}
223libc_hidden_def (__get_nprocs)
224weak_alias (__get_nprocs, get_nprocs)
225
226/* On some architectures it is possible to distinguish between configured
227 and active cpus. */
228int
229__get_nprocs_conf (void)
230{
97a912f7 231 int result = read_sysfs_file ("/sys/devices/system/cpu/possible");
e1d32b83
DL
232 if (result != 0)
233 return result;
234
235 /* Fall back to /proc/stat and sched_getaffinity. */
236 return get_nprocs_fallback ();
bdb04ee8 237}
b5648377 238libc_hidden_def (__get_nprocs_conf)
bdb04ee8 239weak_alias (__get_nprocs_conf, get_nprocs_conf)
845dcb57 240
0ce657c5
RV
241
242/* Compute (num*mem_unit)/pagesize, but avoid overflowing long int.
243 In practice, mem_unit is never bigger than the page size, so after
244 the first loop it is 1. [In the kernel, it is initialized to
245 PAGE_SIZE in mm/page_alloc.c:si_meminfo(), and then in
246 kernel.sys.c:do_sysinfo() it is set to 1 if unsigned long can
247 represent all the sizes measured in bytes]. */
e4cf5229 248static long int
0ce657c5 249sysinfo_mempages (unsigned long int num, unsigned int mem_unit)
845dcb57 250{
0ce657c5 251 unsigned long int ps = __getpagesize ();
845dcb57 252
0ce657c5 253 while (mem_unit > 1 && ps > 1)
845dcb57 254 {
0ce657c5
RV
255 mem_unit >>= 1;
256 ps >>= 1;
845dcb57 257 }
0ce657c5
RV
258 num *= mem_unit;
259 while (ps > 1)
260 {
261 ps >>= 1;
262 num >>= 1;
263 }
264 return num;
845dcb57
UD
265}
266
0ce657c5
RV
267/* Return the number of pages of total/available physical memory in
268 the system. This used to be done by parsing /proc/meminfo, but
269 that's unnecessarily expensive (and /proc is not always available).
270 The sysinfo syscall provides the same information, and has been
271 available at least since kernel 2.3.48. */
e4cf5229 272long int
60d2f8f3 273__get_phys_pages (void)
845dcb57 274{
0ce657c5 275 struct sysinfo info;
845dcb57 276
0ce657c5
RV
277 __sysinfo (&info);
278 return sysinfo_mempages (info.totalram, info.mem_unit);
845dcb57 279}
b5648377 280libc_hidden_def (__get_phys_pages)
845dcb57
UD
281weak_alias (__get_phys_pages, get_phys_pages)
282
e4cf5229 283long int
60d2f8f3 284__get_avphys_pages (void)
845dcb57 285{
0ce657c5 286 struct sysinfo info;
845dcb57 287
0ce657c5
RV
288 __sysinfo (&info);
289 return sysinfo_mempages (info.freeram, info.mem_unit);
845dcb57 290}
b5648377 291libc_hidden_def (__get_avphys_pages)
845dcb57 292weak_alias (__get_avphys_pages, get_avphys_pages)